Commit 9b4e67c3 authored by Javier Romero's avatar Javier Romero

Merge branch 'feature/query-redesign' into 'master'

Query Redesign

See merge request !15
parents 54f4af3b 8551adf8
Pipeline #32871144 passed with stages
in 66 minutes and 33 seconds
......@@ -32,18 +32,20 @@ android {
compileSdkVersion 28
buildToolsVersion '28.0.2'
androidExtensions {
experimental = true
}
defaultConfig {
applicationId "app.devlife.connect2sql"
/* format: [ M].[00m].[00p] */
versionCode 4000012
versionName "4.0.12"
minSdkVersion 23
targetSdkVersion 28
manifestPlaceholders = [fabricApiKey: fabricApiKey]
project.version = versionName
targetSdkVersion 28
/* format: [ M].[00m].[00p] */
versionCode 4000012
versionName "4.0.12"
}
testOptions {
......@@ -101,6 +103,7 @@ android {
}
detekt {
version = '1.0.0.RC8'
defaultProfile {
config = file("$projectDir/detekt.yml")
output = file("$buildDir/reports/")
......@@ -110,6 +113,7 @@ android {
}
ext {
version_arch = '1.1.1'
version_answers = '1.4.3'
version_constraint_layout = '1.1.3'
version_crashlytcs = '2.9.5'
......@@ -117,6 +121,7 @@ ext {
version_jsr250 = '1.0'
version_jsch = '0.1.54'
version_logback_android = '1.1.1-12'
version_expandable_rv = '1.3'
version_mariadb = '1.7.4'
version_dexmaker_mockito = '2.19.0'
version_patternlock = '2.1.2'
......@@ -124,11 +129,13 @@ ext {
version_saripaar = '1.0.3'
version_sqlcipher = '3.5.9'
version_slf4j = '1.7.25'
version_support = '28.0.0-rc01'
version_support = '28.0.0'
}
dependencies {
implementation fileTree(include: '*.jar', dir: 'libs')
implementation "android.arch.lifecycle:extensions:${version_arch}"
implementation "android.arch.lifecycle:viewmodel:${version_arch}"
implementation "com.android.support:support-v4:${version_support}"
implementation "com.android.support:support-annotations:${version_support}"
implementation "com.android.support:appcompat-v7:${version_support}"
......@@ -152,6 +159,7 @@ dependencies {
implementation "com.jcraft:jsch:${version_jsch}"
implementation "com.linkedin.dexmaker:dexmaker-mockito:${version_dexmaker_mockito}"
implementation "com.mobsandgeeks:android-saripaar:${version_saripaar}"
implementation "com.thoughtbot:expandablerecyclerview:${version_expandable_rv}"
implementation "javax.annotation:jsr250-api:${version_jsr250}"
implementation "io.reactivex:rxandroid:${version_rx}"
implementation "io.reactivex:rxjava:${version_rx}"
......
......@@ -48,16 +48,8 @@
android:label="@string/activity_host_keys" />
<activity
android:name="app.devlife.connect2sql.ui.query.QueryActivity"
android:configChanges="orientation|uiMode|screenSize|smallestScreenSize|keyboardHidden"
android:label="@string/activity_query"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="app.devlife.connect2sql.ui.savedqueries.SavedQueriesActivity"
android:label="@string/activity_saved_queries" />
<activity
android:name="app.devlife.connect2sql.ui.history.QueryHistoryActivity"
android:label="@string/activity_query_history" />
android:theme="@style/Theme.C2SQL.NoActionBar" />
<activity
android:name="app.devlife.connect2sql.ui.results.ResultsActivity"
android:configChanges="orientation|uiMode|screenSize|smallestScreenSize|keyboardHidden"
......
package app.devlife.connect2sql;
import android.app.Activity;
import android.app.Application;
import java.lang.ref.WeakReference;
import javax.inject.Inject;
import app.devlife.connect2sql.activity.LaunchActivity;
import app.devlife.connect2sql.data.LockManager;
import app.devlife.connect2sql.di.AnalyticsModule;
import app.devlife.connect2sql.di.ApplicationComponent;
import app.devlife.connect2sql.di.ApplicationModule;
import app.devlife.connect2sql.di.ConnectionModule;
import app.devlife.connect2sql.di.DaggerApplicationComponent;
import app.devlife.connect2sql.di.DatabaseModule;
import app.devlife.connect2sql.di.PreferencesModule;
import app.devlife.connect2sql.di.SecurityModule;
import app.devlife.connect2sql.log.EzLogger;
import io.fabric.sdk.android.Fabric;
/**
*
*/
public class Connect2SqlApplication extends Application {
private ApplicationComponent mApplicationComponent;
@Inject
ApplicationFocusManager mApplicationFocusManager;
@Inject
LockManager mLockManager;
@Inject
Fabric mFabric;
@Override
public void onCreate() {
super.onCreate();
mApplicationComponent = DaggerApplicationComponent.builder()
.analyticsModule(new AnalyticsModule(this))
.applicationModule(new ApplicationModule(this))
.connectionModule(new ConnectionModule(this))
.databaseModule(new DatabaseModule(this))
.preferencesModule(new PreferencesModule(this))
.securityModule(new SecurityModule(this))
.build();
mApplicationComponent.inject(this);
mApplicationFocusManager.addOnFocusChangeListener(mOnFocusChangeListener);
EzLogger.i("Fabric version: " + mFabric.getVersion());
}
public ApplicationComponent getApplicationComponent() {
return mApplicationComponent;
}
private ApplicationFocusManager.OnFocusChangeListener mOnFocusChangeListener = new ApplicationFocusManager.OnFocusChangeListener() {
@Override
public void onApplicationFocusChange(boolean focused) {
if (focused) {
WeakReference<Activity> lastFocusedActivity = mApplicationFocusManager.getLastFocusedActivity();
if (lastFocusedActivity != null) {
if (lastFocusedActivity.get() != null) {
Activity activity = lastFocusedActivity.get();
EzLogger.d("Last focused activity: " + activity);
if (!activity.getClass().equals(LaunchActivity.class)) {
if (!mLockManager.isSetLockActivity(activity) &&
!mLockManager.isUnlockActivity(activity) &&
!mLockManager.isForgotLockActivity(activity)) {
mLockManager.startUnlockActivity(activity, 0);
} else {
EzLogger.d("Activity is a lock specific activity.");
}
} else {
EzLogger.d("Last focused activity was the Launch activity.");
}
} else {
EzLogger.d("Last focused activity has gone away.");
}
} else {
EzLogger.d("No reference to last focused activity");
}
}
}
};
}
package app.devlife.connect2sql
import android.app.Activity
import android.app.Application
import app.devlife.connect2sql.activity.LaunchActivity
import app.devlife.connect2sql.data.LockManager
import app.devlife.connect2sql.di.AnalyticsModule
import app.devlife.connect2sql.di.ApplicationComponent
import app.devlife.connect2sql.di.ApplicationModule
import app.devlife.connect2sql.di.ConnectionModule
import app.devlife.connect2sql.di.DaggerApplicationComponent
import app.devlife.connect2sql.di.DatabaseModule
import app.devlife.connect2sql.di.PreferencesModule
import app.devlife.connect2sql.di.SecurityModule
import app.devlife.connect2sql.log.EzLogger
import io.fabric.sdk.android.Fabric
import javax.inject.Inject
/**
*
*/
class Connect2SqlApplication : Application() {
lateinit var applicationComponent: ApplicationComponent
@Inject
lateinit var applicationFocusManager: ApplicationFocusManager
@Inject
lateinit var lockManager: LockManager
@Inject
lateinit var fabric: Fabric
private val mOnFocusChangeListener = ApplicationFocusManager.OnFocusChangeListener { focused ->
if (focused) {
val lastFocusedActivity = applicationFocusManager.lastFocusedActivity
if (lastFocusedActivity != null) {
if (lastFocusedActivity.get() != null) {
val activity = lastFocusedActivity.get()
EzLogger.d("Last focused activity: $activity")
if (activity !is LaunchActivity) {
if (!lockManager.isSetLockActivity(activity) &&
!lockManager.isUnlockActivity(activity) &&
!lockManager.isForgotLockActivity(activity)) {
lockManager.startUnlockActivity(activity, 0)
} else {
EzLogger.d("Activity is a lock specific activity.")
}
} else {
EzLogger.d("Last focused activity was the Launch activity.")
}
} else {
EzLogger.d("Last focused activity has gone away.")
}
} else {
EzLogger.d("No reference to last focused activity")
}
}
}
override fun onCreate() {
super.onCreate()
applicationComponent = DaggerApplicationComponent.builder()
.analyticsModule(AnalyticsModule(this))
.applicationModule(ApplicationModule(this))
.connectionModule(ConnectionModule(this))
.databaseModule(DatabaseModule(this))
.preferencesModule(PreferencesModule(this))
.securityModule(SecurityModule(this))
.build()
.also { it.inject(this) }
applicationFocusManager.addOnFocusChangeListener(mOnFocusChangeListener)
EzLogger.i("Fabric version: " + fabric.version)
}
}
package app.devlife.connect2sql.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import com.gitlab.connect2sql.R;
public class QuickKeysAdapter extends BaseExpandableListAdapter {
public static final int SECTION_SNIPPETS = 0;
public static final int SECTION_OPERATORS = 1;
public static final int SECTION_DATABASES = 2;
public static final int SECTION_TABLES = 3;
public static final int SECTION_COLUMNS = 4;
private List<List<String>> mData = new ArrayList<List<String>>();
private Context mContext;
private int mListItemLayout = android.R.layout.simple_expandable_list_item_1;
public int getListItemLayout() {
return mListItemLayout;
}
public void setListItemLayout(int mListItemLayout) {
this.mListItemLayout = mListItemLayout;
}
public QuickKeysAdapter(Context context) {
mContext = context;
for (int i = 0; i < 5; i++) {
mData.add(new ArrayList<String>());
}
}
public void clearSection(int section) {
mData.get(section).clear();
}
public void addChild(String value, int section) {
mData.get(section).add(value);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return ((List<?>) getGroup(groupPosition)).get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
// if no view present build it
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mListItemLayout, null);
convertView.setBackgroundColor(Color.TRANSPARENT);
}
TextView textView = (TextView) convertView
.findViewById(android.R.id.text1);
//textView.setPadding(10, 30, 10, 30);
textView.setText(getChild(groupPosition, childPosition).toString());
return convertView;
}
@Override
public int getChildrenCount(int groupPosition) {
return ((List<?>) getGroup(groupPosition)).size();
}
@Override
public Object getGroup(int groupPosition) {
return mData.get(groupPosition);
}
@Override
public int getGroupCount() {
return mData.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView == null) {
// if no view present build it
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mListItemLayout, null);
}
TextView textView = (TextView) convertView
.findViewById(android.R.id.text1);
//textView.setPadding(10, 30, 10, 30);
switch (groupPosition) {
case SECTION_COLUMNS:
textView.setText(R.string.qk_section_column);
break;
case SECTION_DATABASES:
textView.setText(R.string.qk_section_databases);
break;
case SECTION_TABLES:
textView.setText(R.string.qk_section_tables);
break;
case SECTION_SNIPPETS:
textView.setText(R.string.qk_section_snippets);
break;
case SECTION_OPERATORS:
textView.setText(R.string.qk_section_operators);
break;
default:
textView.setText("");
break;
}
return convertView;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
package app.devlife.connect2sql.adapter
import app.devlife.connect2sql.db.model.query.BaseNamedQuery
import app.devlife.connect2sql.db.model.query.BuiltInQuery
import com.gitlab.connect2sql.R
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseExpandableListAdapter
import android.widget.TextView
import app.devlife.connect2sql.db.model.query.BaseNamedQuery
import app.devlife.connect2sql.db.model.query.BuiltInQuery
import app.devlife.connect2sql.db.model.query.SavedQuery
import com.gitlab.connect2sql.R
class SavedQueriesAdapter(private val context: Context) : BaseExpandableListAdapter() {
var titleOnly = false
......@@ -30,6 +30,10 @@ class SavedQueriesAdapter(private val context: Context) : BaseExpandableListAdap
queries[GROUP_SAVED].remove(query)
}
fun clearSavedQueries() {
queries[GROUP_SAVED].clear()
}
fun clear() {
queries[GROUP_BUILTIN].clear()
queries[GROUP_SAVED].clear()
......@@ -52,11 +56,7 @@ class SavedQueriesAdapter(private val context: Context) : BaseExpandableListAdap
): View {
val view: View = when (convertView) {
null -> {
val view = inflator.inflate(R.layout.item_query_list_child, null)
view.setPadding(80, 10, 2, 10)
view
}
null -> inflator.inflate(R.layout.item_query_list_child, null)
else -> convertView
}
......@@ -92,15 +92,11 @@ class SavedQueriesAdapter(private val context: Context) : BaseExpandableListAdap
parent: ViewGroup
): View {
val view: View = when (convertView) {
null -> {
val view = inflator.inflate(android.R.layout.simple_expandable_list_item_1, null)
view.setPadding(80, 15, 2, 15)
view
}
null -> inflator.inflate(R.layout.item_expandable_group, null)
else -> convertView
}
val textView = view.findViewById(android.R.id.text1) as TextView
val textView = view.findViewById(R.id.text1) as TextView
when (groupPosition) {
GROUP_BUILTIN -> textView.text = builtInText
else -> textView.text = savedText
......
......@@ -9,7 +9,7 @@ data class ConnectionInfo(
val host: String,
val port: Int,
val username: String,
val password: String?,
val password: String,
val database: String?,
val sshConfig: SshConfig?,
val options: Map<String, String>
......
......@@ -6,7 +6,7 @@ import app.devlife.connect2sql.db.model.SqlModel;
import android.net.Uri;
public class ContentUriHelper {
private static HashMap<String, HashMap<Class<? extends SqlModel>, Uri>> sCachedUris = new HashMap<String, HashMap<Class<? extends SqlModel>, Uri>>();
private static HashMap<String, HashMap<Class<? extends SqlModel>, Uri>> sCachedUris = new HashMap<>();
public static Uri getContentUri(Class<? extends SqlModel> clazz) throws BaseUriNotFoundException {
return getContentUri(AppContentProvider.AUTHORITY, clazz);
......
......@@ -5,14 +5,16 @@ import javax.inject.Singleton;
import app.devlife.connect2sql.Connect2SqlApplication;
import app.devlife.connect2sql.activity.DashboardActivity;
import app.devlife.connect2sql.activity.LaunchActivity;
import app.devlife.connect2sql.ui.browse.BrowseFragment;
import app.devlife.connect2sql.ui.connection.ConnectionInfoEditorActivity;
import app.devlife.connect2sql.ui.history.QueryHistoryActivity;
import app.devlife.connect2sql.ui.history.HistoryFragment;
import app.devlife.connect2sql.ui.hostkeys.HostKeysActivity;
import app.devlife.connect2sql.ui.lock.SetLockActivity;
import app.devlife.connect2sql.ui.lock.UnlockActivity;
import app.devlife.connect2sql.ui.query.QueryActivity;
import app.devlife.connect2sql.ui.quickkeys.QuickKeysFragment;
import app.devlife.connect2sql.ui.results.ResultsActivity;
import app.devlife.connect2sql.ui.savedqueries.SavedQueriesActivity;
import app.devlife.connect2sql.ui.savedqueries.SavedQueryFragment;
import dagger.Component;
@Singleton
......@@ -22,31 +24,36 @@ import dagger.Component;
ConnectionModule.class,
DatabaseModule.class,
PreferencesModule.class,
SecurityModule.class
SecurityModule.class,
ViewModelModule.class
})
public interface ApplicationComponent {
// application
void inject(Connect2SqlApplication application);
// activities
// activities / fragments
void inject(BrowseFragment fragment);
void inject(ConnectionInfoEditorActivity activity);
void inject(DashboardActivity activity);
void inject(HistoryFragment fragment);
void inject(HostKeysActivity activity);
void inject(LaunchActivity activity);
void inject(QueryActivity activity);
void inject(QueryHistoryActivity activity);
void inject(QuickKeysFragment fragment);
void inject(ResultsActivity activity);
void inject(SetLockActivity activity);
void inject(SavedQueryFragment fragment);
void inject(SavedQueriesActivity activity);
void inject(SetLockActivity activity);
void inject(UnlockActivity activity);
}
......@@ -4,9 +4,9 @@ import android.app.Application;
import javax.inject.Singleton;
import app.devlife.connect2sql.ApplicationFocusManager;
import dagger.Module;
import dagger.Provides;
import app.devlife.connect2sql.ApplicationFocusManager;
/**
*
......@@ -25,4 +25,11 @@ public class ApplicationModule {
public ApplicationFocusManager provideApplicationFocusManager() {
return new ApplicationFocusManager(mApplication);
}
@Provides
@Singleton
public Application provideApplication() {
return mApplication;
}
}
......@@ -2,8 +2,8 @@ package app.devlife.connect2sql.di;
import javax.inject.Singleton;
import dagger.Component;
import app.devlife.connect2sql.db.provider.AppContentProvider;
import dagger.Component;
/**
*
......@@ -11,6 +11,5 @@ import app.devlife.connect2sql.db.provider.AppContentProvider;
@Singleton
@Component(modules = {DatabaseModule.class, SecurityModule.class})
public interface ContentProviderComponent {
void inject(AppContentProvider appContentProvider);
}
package app.devlife.connect2sql.di
import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import app.devlife.connect2sql.viewmodel.ConnectionViewModel
import app.devlife.connect2sql.viewmodel.SavedQueriesViewModel
import app.devlife.connect2sql.viewmodel.ViewModelFactory
import dagger.Binds
import dagger.MapKey
import dagger.Module
import dagger.multibindings.IntoMap
import kotlin.reflect.KClass
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER)
@Retention
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(ConnectionViewModel::class)
abstract fun bindConnectionViewModel(modelView: ConnectionViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(SavedQueriesViewModel::class)
abstract fun bindSavedQueriesViewModel(modelView: SavedQueriesViewModel): ViewModel
}
\ No newline at end of file
package app.devlife.connect2sql.fragment;
import android.support.v4.app.Fragment;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class BaseFragment extends Fragment implements OnTouchListener {
@Override
public void onResume() {
super.onResume();
// prevent touches to interact with lower level fragment
if (getView() != null) {
getView().setOnTouchListener(this);
}
}
@Override
public boolean onTouch(View v, MotionEvent