Compare commits

..

1 commit

Author SHA1 Message Date
Przemek Grondek
0304cc2590 Try to make UI not stuck - DO NOT MERGE
It doesn't work SHIT
2014-07-31 15:23:52 +02:00
69 changed files with 927 additions and 1976 deletions

View file

@ -56,25 +56,7 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
</content>
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />

View file

@ -2,11 +2,11 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 19
buildToolsVersion '19.1.0'
buildToolsVersion '20.0.0'
defaultConfig {
applicationId "info.nerull7.mysqlbrowser"
minSdkVersion 14
minSdkVersion 15
targetSdkVersion 19
versionCode 1
versionName "1.0"

View file

@ -3,14 +3,13 @@
package="info.nerull7.mysqlbrowser" >
<application
android:allowBackup="false"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/LoginTheme" >
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -18,30 +17,25 @@
</intent-filter>
</activity>
<activity
android:name=".ListActivity"
android:label="@string/title_activity_list" >
android:name=".DatabaseActivity"
android:label="@string/title_activity_database" >
</activity>
<activity
android:name=".TableActivity"
android:label="@string/title_activity_table" >
</activity>
<activity
android:name=".EntriesActivity"
android:label="@string/title_activity_entries" >
android:label="@string/title_activity_entries"
android:theme="@style/EntriesTheme" >
</activity>
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_setting"
android:theme="@style/SettingsTheme" >
</activity>
<activity
android:name=".ElementActivity"
android:label="@string/title_activity_element"
android:windowSoftInputMode="adjustPan">
</activity>
<activity
android:name=".SQLActivity"
android:label="@string/title_activity_sql"
android:windowSoftInputMode="adjustResize">
android:icon="@drawable/ic_action_settings">
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View file

@ -2,17 +2,21 @@ package info.nerull7.mysqlbrowser;
import android.content.Context;
import android.util.Base64;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@ -20,11 +24,10 @@ import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.PBEKeySpec;
/**
* Created by nerull7 on 28.07.14.
*
* Class delegated to encrypt data
*/
public class Crypto {
private static final String KEY_FILE = "null_file"; // to trick h4x0r5
@ -46,19 +49,23 @@ public class Crypto {
}
}
private void generateKey() throws NoSuchAlgorithmException {
private SecretKey generateKey() throws NoSuchAlgorithmException {
SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
keyGenerator.init(OUTPUT_KEY_LENGTH, secureRandom);
secretKey = keyGenerator.generateKey();
SecretKey secretKey = keyGenerator.generateKey();
return secretKey;
}
private void getSecretKey() throws NoSuchAlgorithmException, IOException, ClassNotFoundException {
String key;
// First try to open file
File keyFile = new File(context.getFilesDir(), KEY_FILE);
if(!keyFile.exists()) { // new key
generateKey();
secretKey = generateKey();
FileOutputStream fileOutputStream = new FileOutputStream(keyFile);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(secretKey);
@ -93,6 +100,7 @@ public class Crypto {
public String decryptBase64(String encodedString) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
byte [] encryptedString = Base64.decode(encodedString, Base64.DEFAULT);
return decrypt(encryptedString);
String decrypted = decrypt(encryptedString);
return decrypted;
}
}

View file

@ -2,7 +2,6 @@ package info.nerull7.mysqlbrowser;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;
/**
@ -10,18 +9,10 @@ import android.widget.ScrollView;
*/
public class CustomScrollView extends ScrollView {
private OnTouchEventListener onTouchEventListener;
private OnScrollChangedListener listener;
@Override
public boolean onTouchEvent(MotionEvent ev) {
if(onTouchEventListener != null){
onTouchEventListener.onTouchEvent(ev);
}
return super.onTouchEvent(ev);
}
public void setOnTouchEventListener(OnTouchEventListener onTouchEventListener){
this.onTouchEventListener = onTouchEventListener;
public void setOnScrollChangedListener(OnScrollChangedListener listener){
this.listener = listener;
}
public CustomScrollView(Context context) {
@ -32,7 +23,13 @@ public class CustomScrollView extends ScrollView {
super(context,attributeSet);
}
public interface OnTouchEventListener {
public boolean onTouchEvent(MotionEvent ev);
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
if(listener!=null)
listener.onScrollChanged(l,t,oldl,oldt);
}
public interface OnScrollChangedListener{
public void onScrollChanged(int l, int t, int oldl, int oldt);
}
}

View file

@ -1,31 +1,19 @@
package info.nerull7.mysqlbrowser;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class ListActivity extends Activity {
public class DatabaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
Bundle extras = getIntent().getExtras();
String fragmentName = extras.getString(Static.FRAGMENT_TO_START);
Fragment fragment = null;
if(fragmentName.compareTo(Static.FRAGMENT_DATABASE)==0){
fragment = new DatabaseFragment();
setTitle(R.string.title_fragment_database);
} else if (fragmentName.compareTo(Static.FRAGMENT_TABLE)==0) {
fragment = new TableFragment();
setTitle(extras.getString(Static.DATABASE_NAME_ARG));
}
fragment.setArguments(getIntent().getExtras());
setContentView(R.layout.activity_database);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, fragment)
.add(R.id.container, new DatabaseFragment())
.commit();
}
}
@ -33,7 +21,7 @@ public class ListActivity extends Activity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.logged, menu);
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@ -47,8 +35,6 @@ public class ListActivity extends Activity {
if (id == R.id.action_settings) {
Static.startSettings(this);
return true;
} else if (id == R.id.action_sql){
Static.startSQL(this, getIntent().getExtras().getString(Static.DATABASE_NAME_ARG));
}
return super.onOptionsItemSelected(item);
}

View file

@ -17,25 +17,20 @@ import android.widget.TextView;
import java.util.List;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
import info.nerull7.mysqlbrowser.db.AsyncDatabaseConnector;
/**
* Created by nerull7 on 14.07.14.
*
* Fragment for showing list of Available Databases for user
*/
public class DatabaseFragment extends Fragment implements AdapterView.OnItemClickListener, DatabaseConnector.ListReturnListener, DatabaseConnector.OnPostExecuteListener {
public class DatabaseFragment extends Fragment implements AdapterView.OnItemClickListener, AsyncDatabaseConnector.ListReturnListener {
private ListView databasesListView;
private ListAdapter listAdapter;
private RelativeLayout rootView;
private ProgressBar progressBar;
private List<String> databases;
@Override
public void onResume() {
super.onResume();
Static.databaseConnector.setDatabaseInUse(null);
}
private String chosenDatabase;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
@ -45,46 +40,48 @@ public class DatabaseFragment extends Fragment implements AdapterView.OnItemClic
this.rootView = (RelativeLayout) rootView;
progressBar = (ProgressBar) rootView.findViewById(R.id.loginProgressBar);
Static.databaseConnector.setListReturnListener(this);
Static.databaseConnector.setOnPostExecuteListener(this);
Static.databaseConnector.getDatabases();
// Static.asyncDatabaseConnector.setListReturnListener(this);
// Static.asyncDatabaseConnector.getDatabases();
listAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Static.databases);
databasesListView.setAdapter(listAdapter);
databasesListView.setOnItemClickListener(this);
progressBar.setVisibility(View.INVISIBLE);
return rootView;
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
if(Static.isNetworkConnected(getActivity())) {
String chosenDatabase = (String) listAdapter.getItem(position);
listAdapter.getItem(position);
Intent intent = new Intent(getActivity(), ListActivity.class);
intent.putExtra(Static.FRAGMENT_TO_START, Static.FRAGMENT_TABLE);
intent.putExtra(Static.DATABASE_NAME_ARG, chosenDatabase);
Static.databaseConnector.setDatabaseInUse(chosenDatabase);
startActivity(intent);
} else {
Static.showErrorAlert(getResources().getString(R.string.no_connection), getActivity());
}
chosenDatabase = (String) listAdapter.getItem(position);
listAdapter.getItem(position);
progressBar.setVisibility(View.VISIBLE);
Static.asyncDatabaseConnector.setDatabaseInUse(chosenDatabase);
Static.asyncDatabaseConnector.setListReturnListener(this);
Static.asyncDatabaseConnector.getTables();
}
@Override
public void onListReturn(List<String> databases) {
this.databases = databases;
}
@Override
public void onPostExecute() {
if(databases!= null) {
listAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, databases);
databasesListView.setAdapter(listAdapter);
databasesListView.setOnItemClickListener(this);
} else {
TextView errorMessage = new TextView(getActivity());
errorMessage.setText(R.string.error_no_databases);
errorMessage.setTypeface(null, Typeface.ITALIC);
errorMessage.setClickable(false);
rootView.addView(errorMessage);
rootView.removeView(databasesListView);
public void onListReturn(List<String> tables) {
// if(databases!= null) {
// listAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, databases);
// databasesListView.setAdapter(listAdapter);
// databasesListView.setOnItemClickListener(this);
// } else {
// TextView errorMessage = new TextView(getActivity());
// errorMessage.setText(R.string.error_no_databases);
// errorMessage.setTypeface(null, Typeface.ITALIC);
// errorMessage.setClickable(false);
// rootView.addView(errorMessage);
// rootView.removeView(databasesListView);
// }
// progressBar.setVisibility(View.INVISIBLE);
if(tables!=null) {
Static.tables = tables;
}
progressBar.setVisibility(View.INVISIBLE);
Intent intent = new Intent(getActivity(), TableActivity.class);
intent.putExtra(Static.DATABASE_NAME_ARG, chosenDatabase);
startActivity(intent);
}
}

View file

@ -1,49 +0,0 @@
package info.nerull7.mysqlbrowser;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
public class ElementActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_element);
Bundle bundle = getIntent().getExtras();
String titleName = bundle.getString(Static.TABLE_NAME_ARG);
setTitle(titleName);
ElementFragment elementFragment = new ElementFragment();
elementFragment.setArguments(bundle);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, elementFragment)
.commit();
}
}
@Override
public void onBackPressed() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.error_no_save));
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.setTitle(R.string.warning);
builder.setIcon(R.drawable.ic_action_warning);
builder.create();
builder.show();
}
}

View file

@ -1,79 +0,0 @@
package info.nerull7.mysqlbrowser;
import android.content.Context;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by nerull7 on 2014-08-06.
*/
public class ElementArrayAdapter extends ArrayAdapter<String> {
private Context context;
private List<String> fields;
private List<String> values;
private int layout;
public ElementArrayAdapter(Context context, int resource, List<String> fields) {
super(context, resource, fields);
init(context, resource, fields);
values = new ArrayList<String>();
for(String field: fields){
values.add("");
}
}
public ElementArrayAdapter(Context context, int resource, List<String> fields, List<String> values) {
super(context, resource, fields);
init(context, resource, fields);
this.values = new ArrayList<String>();
if(values!=null) {
this.values.addAll(values); // Copy
} else {
for(int i=0;i<fields.size();i++){
this.values.add(new String());
}
}
}
private void init(Context context, int resource, List<String> fields){
this.context = context;
this.fields = fields;
layout = resource;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rowView = layoutInflater.inflate(layout, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.textFieldName);
textView.setText(fields.get(position));
TextView textFieldName = (TextView) rowView.findViewById(R.id.editFieldValue);
textFieldName.setText(values.get(position));
textFieldName.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
String tmp = String.valueOf(((TextView) v).getText());
values.set(position, tmp);
}
}
});
return rowView;
}
public List<String> getFieldArray(){
return fields;
}
public List<String> getValues() {
return values;
}
}

View file

@ -1,202 +0,0 @@
package info.nerull7.mysqlbrowser;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ProgressBar;
import java.util.List;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
/**
* Created by nerull7 on 2014-08-06.
*
* Fragment for editing/adding elements
*/
public class ElementFragment extends Fragment implements DatabaseConnector.ListReturnListener, DatabaseConnector.StringReturnListener, DatabaseConnector.OnPostExecuteListener {
public static final String EDIT_ELEMENT = "edit_element";
public static final String EDIT_LIST = "edit_element_list";
private static final int POST_EXECUTE_NONE = 0;
private static final int POST_EXECUTE_GET_FIELDS = 1;
private static final int POST_EXECUTE_UPDATE_ELEMENT = 2;
private static final int POST_EXECUTE_ADD_ELEMENT = 3;
private String tableName;
private ElementArrayAdapter listAdapter;
private ProgressBar progressBar;
private ListView listView;
private List<String> values;
private String message;
private int postExecute;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_element, container, false);
progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar);
listView = (ListView) rootView.findViewById(R.id.listView);
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState==SCROLL_STATE_TOUCH_SCROLL) {
listView.requestFocus();
InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(listView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
listView.setItemsCanFocus(true);
initArguments();
postExecute = POST_EXECUTE_NONE;
Static.databaseConnector.setListReturnListener(this);
Static.databaseConnector.setOnPostExecuteListener(this);
Static.databaseConnector.getFields(tableName);
return rootView;
}
private void actionSave(){
List<String> fields = listAdapter.getFieldArray();
Static.databaseConnector.setStringReturnListener(this);
if(getArguments().getBoolean(EDIT_ELEMENT))
Static.databaseConnector.updateElement(tableName, fields, values, listAdapter.getValues());
else
Static.databaseConnector.addNewElement(tableName, fields, listAdapter.getValues());
}
private void actionRemove(){
final List<String> fields = listAdapter.getFieldArray();
Static.databaseConnector.setStringReturnListener(this);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.error_remove);
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Static.databaseConnector.removeElement(tableName, fields, values);
// getActivity().finish();
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Nothing to do just get back
}
});
builder.setTitle(R.string.warning);
builder.setIcon(R.drawable.ic_action_warning);
builder.setCancelable(false); // There is no exit
builder.create();
builder.show();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
listView.requestFocus();
switch (item.getItemId()){
case R.id.action_save:
actionSave();
break;
case R.id.action_remove:
actionRemove();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
private void initArguments() {
tableName = getArguments().getString(Static.TABLE_NAME_ARG);
if(getArguments().getBoolean(EDIT_ELEMENT))
values = getArguments().getStringArrayList(EDIT_LIST);
else
values = null;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.element, menu);
if(!getArguments().getBoolean(EDIT_ELEMENT)) {
menu.findItem(R.id.action_remove).setVisible(false);
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public void onListReturn(List<String> fields) {
listAdapter = new ElementArrayAdapter(getActivity(), R.layout.list_item_element_simple, fields, values);
postExecute = POST_EXECUTE_GET_FIELDS;
}
@Override
public void onStringReturn(String data) {
message = data;
postExecute = POST_EXECUTE_ADD_ELEMENT;
}
@Override
public void onPostExecute() {
switch (postExecute){
case POST_EXECUTE_GET_FIELDS:
listView.setAdapter(listAdapter);
progressBar.setVisibility(View.INVISIBLE);
setHasOptionsMenu(true);
break;
case POST_EXECUTE_ADD_ELEMENT:
case POST_EXECUTE_UPDATE_ELEMENT:
showInfo(message);
break;
}
// Clean after execute
postExecute = POST_EXECUTE_NONE;
}
private void showInfo(String info){
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(info);
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
getActivity().finish();
}
});
/*builder.setNegativeButton(R.string.back, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Nothing to do just get back
}
});*/
builder.setTitle(R.string.status);
builder.setIcon(R.drawable.ic_action_warning);
builder.setCancelable(false); // There is no exit
builder.create();
builder.show();
}
}

View file

@ -2,6 +2,11 @@ package info.nerull7.mysqlbrowser;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import java.util.zip.Inflater;
public class EntriesActivity extends Activity {

View file

@ -1,7 +1,6 @@
package info.nerull7.mysqlbrowser;
import android.app.Fragment;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.PreferenceManager;
@ -9,11 +8,9 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
@ -21,17 +18,14 @@ import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
import info.nerull7.mysqlbrowser.db.AsyncDatabaseConnector;
/**
* Created by nerull7 on 15.07.14.
*
* Fragment for showing elements
*/
public class EntriesFragment extends Fragment implements DatabaseConnector.MatrixReturnListener, DatabaseConnector.ListReturnListener, DatabaseConnector.IntegerReturnListener, View.OnClickListener, DatabaseConnector.OnPostExecuteListener {
public class EntriesFragment extends Fragment implements AsyncDatabaseConnector.MatrixReturnListener, AsyncDatabaseConnector.ListReturnListener, AsyncDatabaseConnector.IntegerReturnListener {
private static final int HEADER_PADDING_TOP = 15;
private static final int HEADER_PADDING_BOTTOM = 15;
private static final int HEADER_PADDING_LEFT = 15;
@ -42,28 +36,23 @@ public class EntriesFragment extends Fragment implements DatabaseConnector.Matri
private static final int ENTRIES_PADDING_RIGHT = 15;
private TableLayout entriesTable;
private ScrollView entriesScrollView;
private CustomScrollView entriesScrollView;
private FrameLayout headerFrame;
private HorizontalScrollView horizontalScrollView;
private RelativeLayout rootView;
private TableRow.LayoutParams layoutParams;
private TableRow headerRow;
private String databaseName;
private String tableName;
private int entriesLimit;
private int page;
private int pageCount;
private int rowCount;
private ProgressBar progressBar;
private CustomScrollView fakeScrollView;
private ScrollView fakeScrollView;
private View dummyView;
private int onPostExecuteListenerExecuted;
private MenuInflater menuInflater;
private Menu menu;
private TableRow headerRow;
private int[] maxWidth;
private boolean isFirstCreate;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@ -72,11 +61,63 @@ public class EntriesFragment extends Fragment implements DatabaseConnector.Matri
initArguments();
initViewItems(rootView);
initListeners();
onPostExecuteListenerExecuted = 0;
Static.databaseConnector.getFields(tableName);
Static.databaseConnector.getEntriesCount(tableName);
// Static.asyncDatabaseConnector.setIntegerReturnListener(this);
// Static.asyncDatabaseConnector.setListReturnListener(this);
// Static.asyncDatabaseConnector.setMatrixReturnListener(this);
// Static.asyncDatabaseConnector.getFields(tableName);
// Static.asyncDatabaseConnector.getEntriesCount(tableName);
pageCount = Static.pageCount/entriesLimit;
if( Static.pageCount%entriesLimit > 0)
pageCount++;
if(pageCount>1)
setHasOptionsMenu(true);
// First we need header
headerRow = new TableRow(getActivity());
headerRow.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
for(int i =0;i<Static.header.size();i++){
TextView textView = new TextView(getActivity());
textView.setText(Static.header.get(i));
textView.setTypeface(null, Typeface.BOLD);
textView.setLayoutParams(layoutParams);
textView.setBackgroundResource(R.drawable.background_header);
textView.setPadding(HEADER_PADDING_LEFT, HEADER_PADDING_TOP, HEADER_PADDING_RIGHT, HEADER_PADDING_BOTTOM);
headerRow.addView(textView);
}
headerFrame.addView(headerRow);
// now data
if(Static.entries!=null) {
for (int i = 0; i < Static.entries.size(); i++) {
List<String> elements = Static.entries.get(i);
TableRow newRow = new TableRow(getActivity());
for (int j = 0; j < elements.size(); j++) { // elements.size can be the same as in header so maybe some one number or not
TextView textView = new TextView(getActivity());
textView.setText(elements.get(j));
textView.setLayoutParams(layoutParams);
textView.setPadding(ENTRIES_PADDING_LEFT, ENTRIES_PADDING_TOP, ENTRIES_PADDING_RIGHT, ENTRIES_PADDING_BOTTOM);
textView.setBackgroundResource(R.drawable.background_element);
newRow.addView(textView);
}
entriesTable.addView(newRow);
syncWidths();
fakeScroll();
}
} else {
TextView errorMessage = new TextView(getActivity());
errorMessage.setText(R.string.error_no_entries);
errorMessage.setTypeface(null, Typeface.ITALIC);
errorMessage.setClickable(false);
entriesScrollView.removeView(entriesTable);
headerFrame.setVisibility(View.VISIBLE);
entriesScrollView.addView(errorMessage);
}
setLoading(false);
return rootView;
}
@ -85,48 +126,39 @@ public class EntriesFragment extends Fragment implements DatabaseConnector.Matri
databaseName = getArguments().getString(Static.DATABASE_NAME_ARG);
tableName = getArguments().getString(Static.TABLE_NAME_ARG);
page = 1;
isFirstCreate = true;
entriesLimit = PreferenceManager.getDefaultSharedPreferences(getActivity()).getInt(SettingsFragment.ENTRIES_PAGE_LIMIT, SettingsFragment.ENTRIES_PAGE_LIMIT_DEF);
}
private void initViewItems(View rootView){
headerFrame = (FrameLayout) rootView.findViewById(R.id.headerFrame);
entriesScrollView = (ScrollView) rootView.findViewById(R.id.entriesScrollView);
fakeScrollView = (CustomScrollView) rootView.findViewById(R.id.fakeScroll);
entriesTable = (TableLayout) rootView.findViewById(R.id.entriesTable);
entriesScrollView = (CustomScrollView) rootView.findViewById(R.id.entriesScrollView);
fakeScrollView = (ScrollView) rootView.findViewById(R.id.fakeScroll);
progressBar = (ProgressBar) rootView.findViewById(R.id.loginProgressBar);
dummyView = rootView.findViewById(R.id.dummyView);
horizontalScrollView = (HorizontalScrollView) rootView.findViewById(R.id.horizontalScrollView);
entriesTable = new TableLayout(getActivity());
fakeScrollView.setOnTouchEventListener(new CustomScrollView.OnTouchEventListener() {
this.rootView = (RelativeLayout) rootView;
entriesScrollView.setOnScrollChangedListener(new CustomScrollView.OnScrollChangedListener() {
@Override
public boolean onTouchEvent(MotionEvent ev) {
ev.offsetLocation(0, headerFrame.getHeight());
horizontalScrollView.dispatchTouchEvent(ev);
return true;
public void onScrollChanged(int l, int t, int oldl, int oldt) {
fakeScrollView.scrollTo(0,t);
}
});
layoutParams = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.MATCH_PARENT);
}
private void initListeners(){
Static.databaseConnector.setIntegerReturnListener(this);
Static.databaseConnector.setListReturnListener(this);
Static.databaseConnector.setMatrixReturnListener(this);
Static.databaseConnector.setOnPostExecuteListener(this);
layoutParams = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
headerFrame.setVisibility(View.INVISIBLE);
entriesTable.setVisibility(View.INVISIBLE);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.entries_activity_actions, menu);
menuInflater = inflater; // I think we need it later
menu.findItem(R.id.action_previous).setVisible(false); // hide previous
if(pageCount<=1)
menu.findItem(R.id.action_next).setVisible(false); // hide next if we don't have any more pages
this.menu = menu;
super.onCreateOptionsMenu(menu, inflater);
// super.onCreateOptionsMenu(menu, inflater);
}
private void changeMenus(int page){
@ -150,97 +182,76 @@ public class EntriesFragment extends Fragment implements DatabaseConnector.Matri
progressBar.setVisibility(isLoading ? View.VISIBLE : View.INVISIBLE);
}
private void loadAnotherPage(){
changeMenus(page);
entriesScrollView.removeAllViews(); // clean table
entriesTable = new TableLayout(getActivity());
onPostExecuteListenerExecuted--;
setLoading(true);
Static.databaseConnector.getRows(tableName, entriesLimit, page); // get new entries
}
private void addNewElement(){
Intent intent = new Intent(getActivity(), ElementActivity.class);
intent.putExtra(Static.DATABASE_NAME_ARG,databaseName);
intent.putExtra(Static.TABLE_NAME_ARG,tableName);
startActivity(intent);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (Static.isNetworkConnected(getActivity())) {
switch (item.getItemId()) {
case R.id.action_previous:
page--;
loadAnotherPage();
break;
case R.id.action_next:
page++;
loadAnotherPage();
break;
case R.id.action_add:
addNewElement();
break;
}
} else {
Static.showErrorAlert(getResources().getString(R.string.no_connection), getActivity());
switch (item.getItemId()){
case R.id.action_previous:
page--;
break;
case R.id.action_next:
page++;
break;
}
changeMenus(page);
entriesTable.removeAllViews(); // clean table
setLoading(true);
Static.asyncDatabaseConnector.getRows(tableName, entriesLimit, page); // get new entries
return super.onOptionsItemSelected(item);
}
@Override
public void onMatrixReturn(List<List<String>> rows) {
// Now we get Rows
if(rows!=null) {
int background;
for (int i = 0; i < rows.size(); i++) {
List<String> elements = rows.get(i);
TableRow newRow = new TableRow(getActivity());
if( i%2 == 0 ){ // Two backgrounds for lines for better visibility
background=R.drawable.entries_element_1;
} else {
background=R.drawable.entries_element_2;
}
for (int j = 0; j < elements.size(); j++) { // elements.size can be the same as in header so maybe some one number or not
TextView textView = new TextView(getActivity());
textView.setText(elements.get(j));
textView.setLayoutParams(layoutParams);
textView.setPadding(ENTRIES_PADDING_LEFT, ENTRIES_PADDING_TOP, ENTRIES_PADDING_RIGHT, ENTRIES_PADDING_BOTTOM);
textView.setBackgroundResource(background);
textView.setId(j);
newRow.addView(textView);
}
newRow.setClickable(true);
newRow.setOnClickListener(this);
entriesTable.addView(newRow);
syncWidthsFirstStage();
}
} else {
entriesTable = null;
}
// // Now we get Rows
// if(rows!=null) {
// for (int i = 0; i < rows.size(); i++) {
// List<String> elements = rows.get(i);
// TableRow newRow = new TableRow(getActivity());
// for (int j = 0; j < elements.size(); j++) { // elements.size can be the same as in header so maybe some one number or not
// TextView textView = new TextView(getActivity());
// textView.setText(elements.get(j));
// textView.setLayoutParams(layoutParams);
// textView.setPadding(ENTRIES_PADDING_LEFT, ENTRIES_PADDING_TOP, ENTRIES_PADDING_RIGHT, ENTRIES_PADDING_BOTTOM);
// textView.setBackgroundResource(R.drawable.background_element);
// newRow.addView(textView);
// }
// entriesTable.addView(newRow);
//
// syncWidths();
// fakeScroll();
// }
// } else {
// TextView errorMessage = new TextView(getActivity());
// errorMessage.setText(R.string.error_no_entries);
// errorMessage.setTypeface(null, Typeface.ITALIC);
// errorMessage.setClickable(false);
// entriesScrollView.removeView(entriesTable);
// headerFrame.setVisibility(View.VISIBLE);
// entriesScrollView.addView(errorMessage);
// }
//
// setLoading(false);
}
@Override
public void onListReturn(List<String> fieldList) {
// First we need header
headerRow = new TableRow(getActivity());
headerRow.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
rowCount = fieldList.size();
for (String aFieldList : fieldList) {
TextView textView = new TextView(getActivity());
textView.setText(aFieldList);
textView.setTypeface(null, Typeface.BOLD);
textView.setLayoutParams(layoutParams);
textView.setBackgroundResource(R.drawable.background_header);
textView.setPadding(HEADER_PADDING_LEFT, HEADER_PADDING_TOP, HEADER_PADDING_RIGHT, HEADER_PADDING_BOTTOM);
headerRow.addView(textView);
}
Static.databaseConnector.getRows(tableName, entriesLimit, page);
// // First we need header
// headerRow = new TableRow(getActivity());
// headerRow.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
// for(int i =0;i<fieldList.size();i++){
// TextView textView = new TextView(getActivity());
// textView.setText(fieldList.get(i));
// textView.setTypeface(null, Typeface.BOLD);
// textView.setLayoutParams(layoutParams);
// textView.setBackgroundResource(R.drawable.background_header);
// textView.setPadding(HEADER_PADDING_LEFT, HEADER_PADDING_TOP, HEADER_PADDING_RIGHT, HEADER_PADDING_BOTTOM);
// headerRow.addView(textView);
// }
// headerFrame.addView(headerRow);
//
// Static.asyncDatabaseConnector.getRows(tableName, entriesLimit, page);
}
@Override
@ -248,35 +259,31 @@ public class EntriesFragment extends Fragment implements DatabaseConnector.Matri
pageCount = result/entriesLimit;
if( result%entriesLimit > 0)
pageCount++;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
setHasOptionsMenu(true);
}
});
if(pageCount>1)
setHasOptionsMenu(true);
}
private void syncWidthsFirstStage() { // TODO: Merge with adding columns maybe? Loops -= 3 should be quicker
maxWidth = new int[headerRow.getChildCount()];
for (int i = 0; i < headerRow.getChildCount(); i++) {
private void syncWidths(){ // TODO: Merge with adding columns maybe? Loops -= 3 should be quicker
TableRow headerRow = (TableRow) headerFrame.getChildAt(0);
int maxWidth[]= new int[headerRow.getChildCount()];
for(int i=0;i<headerRow.getChildCount();i++){
TextView textView = (TextView) headerRow.getChildAt(i);
textView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
maxWidth[i] = textView.getMeasuredWidth();
}
for (int i = 0; i < entriesTable.getChildCount(); i++) {
for(int i=0;i<entriesTable.getChildCount();i++){
TableRow tableRow = (TableRow) entriesTable.getChildAt(i);
for (int j = 0; j < tableRow.getChildCount(); j++) {
for(int j=0;j<tableRow.getChildCount();j++){
TextView textView = (TextView) tableRow.getChildAt(j);
textView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = textView.getMeasuredWidth();
if (width > maxWidth[j])
maxWidth[j] = width;
if(width>maxWidth[j])
maxWidth[j]=width;
}
}
}
private void syncWidthsSecondStage() {
for(int i=0;i<headerRow.getChildCount();i++){
TableRow entriesRow = (TableRow) entriesTable.getChildAt(0);
@ -286,65 +293,16 @@ public class EntriesFragment extends Fragment implements DatabaseConnector.Matri
tmpEntries.setWidth(maxWidth[i]);
tmpHeader.setWidth(maxWidth[i]);
}
headerFrame.setVisibility(View.VISIBLE);
entriesTable.setVisibility(View.VISIBLE);
}
private void fakeScroll(){
entriesScrollView.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
int height = entriesScrollView.getMeasuredHeight();
dummyView.setMinimumHeight(height);
RelativeLayout.LayoutParams fakeScrollLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
headerFrame.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
fakeScrollLayout.setMargins(0,headerFrame.getMeasuredHeight(),0,0);
fakeScrollView.setLayoutParams(fakeScrollLayout);
}
@Override
public void onClick(View view) {
ArrayList<String> values = new ArrayList<String>();
for(int i=0;i<rowCount;i++){
TextView element = (TextView)view.findViewById(i);
values.add(element.getText().toString());
// element.setBackgroundResource(android.R.color.holo_blue_bright);
}
Intent intent = new Intent(getActivity(), ElementActivity.class);
intent.putExtra(Static.DATABASE_NAME_ARG,databaseName);
intent.putExtra(Static.TABLE_NAME_ARG,tableName);
intent.putExtra(ElementFragment.EDIT_ELEMENT, true);
intent.putStringArrayListExtra(ElementFragment.EDIT_LIST, values);
startActivity(intent);
}
@Override
public void onResume() {
super.onResume();
if(!isFirstCreate) {
initListeners(); // Could be overwritten
loadAnotherPage(); // This reloads entries
} else {
isFirstCreate = false;
}
}
@Override
public void onPostExecute() {
if(++onPostExecuteListenerExecuted==3){
if(headerFrame.getChildCount()==0) // You can have only one child
headerFrame.addView(headerRow);
if(entriesTable!=null) {
syncWidthsSecondStage();
entriesScrollView.addView(entriesTable);
fakeScroll();
} else {
TextView errorMessage = new TextView(getActivity());
errorMessage.setText(R.string.error_no_entries);
errorMessage.setTypeface(null, Typeface.ITALIC);
errorMessage.setClickable(false);
entriesScrollView.addView(errorMessage);
}
setLoading(false);
}
}
}

View file

@ -1,34 +1,46 @@
package info.nerull7.mysqlbrowser;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import info.nerull7.mysqlbrowser.db.AsyncDatabaseConnector;
/**
* Created by nerull7 on 07.07.14.
*
* Fragment for login
*/
public class LoginFragment extends Fragment implements View.OnClickListener, DatabaseConnector.BooleanReturnListener, DatabaseConnector.OnPostExecuteListener {
public class LoginFragment extends Fragment implements View.OnClickListener, AsyncDatabaseConnector.BooleanReturnListener, AsyncDatabaseConnector.ListReturnListener {
private EditText urlTextbox;
private EditText loginTextbox;
private EditText passwordTextbox;
private ProgressBar progressBar;
private Button loginButton;
DatabaseConnector databaseConnector;
private boolean result;
AsyncDatabaseConnector asyncDatabaseConnector;
public LoginFragment(){}
@ -49,13 +61,6 @@ public class LoginFragment extends Fragment implements View.OnClickListener, Dat
return rootView;
}
@Override
public void onResume() {
super.onResume();
processCredentials();
}
private void processCredentials() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
@ -84,38 +89,55 @@ public class LoginFragment extends Fragment implements View.OnClickListener, Dat
login = loginTextbox.getText().toString();
password = passwordTextbox.getText().toString();
url = urlTextbox.getText().toString();
if(Static.isNetworkConnected(getActivity())) {
databaseConnector = new DatabaseConnector(login, password, url, getActivity().getResources());
databaseConnector.setBooleanReturnListener(this);
databaseConnector.setOnPostExecuteListener(this);
databaseConnector.checkLogin();
} else {
Static.showErrorAlert(getResources().getString(R.string.no_connection), getActivity());
loginButton.setEnabled(true); // Now we can click button again
progressBar.setVisibility(View.INVISIBLE);
}
asyncDatabaseConnector = new AsyncDatabaseConnector(login, password, url);
asyncDatabaseConnector.setBooleanReturnListener(this);
asyncDatabaseConnector.checkLogin();
}
@Override
public void onBooleanReturn(boolean result) {
this.result = result;
}
@Override
public void onPostExecute() {
if(result) {
Static.databaseConnector = databaseConnector;
Intent intent = new Intent(getActivity(), ListActivity.class);
intent.putExtra(Static.FRAGMENT_TO_START, Static.FRAGMENT_DATABASE);
startActivity(intent);
Static.asyncDatabaseConnector = asyncDatabaseConnector;
Static.asyncDatabaseConnector.setListReturnListener(this);
Static.asyncDatabaseConnector.getDatabases();
}
else {
Static.showErrorAlert(DatabaseConnector.errorMsg, getActivity());
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(Static.asyncDatabaseConnector.errorMsg);
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Nothing to do here
// Cleaning inputs is stupid
}
});
builder.setTitle(R.string.error);
builder.setIcon(R.drawable.ic_action_warning);
builder.create();
builder.show();
}
loginButton.setEnabled(true); // Now we can click button again
progressBar.setVisibility(View.INVISIBLE);
}
@Override
public void onListReturn(List<String> databases) {
if(databases!= null) {
Static.databases = databases;
Intent intent = new Intent(getActivity(), DatabaseActivity.class);
startActivity(intent);
}
// listAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, databases);
// databasesListView.setAdapter(listAdapter);
// databasesListView.setOnItemClickListener(this);
// } else {
// TextView errorMessage = new TextView(getActivity());
// errorMessage.setText(R.string.error_no_databases);
// errorMessage.setTypeface(null, Typeface.ITALIC);
// errorMessage.setClickable(false);
// rootView.addView(errorMessage);
// rootView.removeView(databasesListView);
// }
}
}

View file

@ -1,6 +1,7 @@
package info.nerull7.mysqlbrowser;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

View file

@ -0,0 +1,108 @@
package info.nerull7.mysqlbrowser;
/**
* Created by nerull7 on 18.07.14.
*/
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.NumberPicker;
/**
* A dialog that prompts the user for the message deletion limits.
*/
public class NumberPickerDialog extends AlertDialog implements DialogInterface.OnClickListener {
private static final String NUMBER = "number";
/**
* The callback interface used to indicate the user is done filling in
* the time (they clicked on the 'Set' button).
*/
public interface OnNumberSetListener {
/**
* @param number The number that was set.
*/
void onNumberSet(int number);
}
private final NumberPicker mNumberPicker;
private final OnNumberSetListener mCallback;
/**
* @param context Parent.
* @param callBack How parent is notified.
* @param number The initial number.
*/
public NumberPickerDialog(Context context,
OnNumberSetListener callBack,
int number,
int rangeMin,
int rangeMax,
int title) {
this(context, AlertDialog.THEME_HOLO_LIGHT, callBack, number, rangeMin, rangeMax, title);
}
/**
* @param context Parent.
* @param theme the theme to apply to this dialog
* @param callBack How parent is notified.
* @param number The initial number.
*/
public NumberPickerDialog(Context context,
int theme,
OnNumberSetListener callBack,
int number,
int rangeMin,
int rangeMax,
int title) {
super(context, theme);
mCallback = callBack;
setTitle(title);
setButton(DialogInterface.BUTTON_POSITIVE, context.getText(R.string.set), this);
setButton(DialogInterface.BUTTON_NEGATIVE, context.getText(R.string.cancel),
(OnClickListener) null);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.number_picker_dialog, null);
setView(view);
mNumberPicker = (NumberPicker) view.findViewById(R.id.number_picker);
// initialize state
mNumberPicker.setMinValue(rangeMin);
mNumberPicker.setMaxValue(rangeMax);
mNumberPicker.setValue(number);
mNumberPicker.setOnLongPressUpdateInterval(100); // make the repeat rate three times as fast
// as normal since the range is so large.
mNumberPicker.setWrapSelectorWheel(false); // don't wrap from min->max
}
public void onClick(DialogInterface dialog, int which) {
if (mCallback != null) {
mNumberPicker.clearFocus();
mCallback.onNumberSet(mNumberPicker.getValue());
dialog.dismiss();
}
}
@Override
public Bundle onSaveInstanceState() {
Bundle state = super.onSaveInstanceState();
state.putInt(NUMBER, mNumberPicker.getValue());
return state;
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
int number = savedInstanceState.getInt(NUMBER);
mNumberPicker.setValue(number);
}
}

View file

@ -1,22 +0,0 @@
package info.nerull7.mysqlbrowser;
import android.app.Activity;
import android.os.Bundle;
/**
* Created by nerull7 on 30.09.14.
*/
public class SQLActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sql);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new SQLFragment())
.commit();
}
}
}

View file

@ -1,240 +0,0 @@
package info.nerull7.mysqlbrowser;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import java.util.List;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
/**
* Created by nerull7 on 15.07.14.
*
* Fragment for showing elements
*/
public class SQLEntriesFragment extends Fragment implements DatabaseConnector.MatrixReturnListener, DatabaseConnector.ListReturnListener, DatabaseConnector.OnPostExecuteListener, DatabaseConnector.StringReturnListener {
private static final int HEADER_PADDING_TOP = 15;
private static final int HEADER_PADDING_BOTTOM = 15;
private static final int HEADER_PADDING_LEFT = 15;
private static final int HEADER_PADDING_RIGHT = 15;
private static final int ENTRIES_PADDING_TOP = 30;
private static final int ENTRIES_PADDING_BOTTOM = 30;
private static final int ENTRIES_PADDING_LEFT = 15;
private static final int ENTRIES_PADDING_RIGHT = 15;
private TableLayout entriesTable;
private ScrollView entriesScrollView;
private FrameLayout headerFrame;
private HorizontalScrollView horizontalScrollView;
private TableRow.LayoutParams layoutParams;
private ProgressBar progressBar;
private CustomScrollView fakeScrollView;
private View dummyView;
private boolean showError;
private Menu menu;
private TableRow headerRow;
private int[] maxWidth;
private boolean isFirstCreate;
private String errorMessage;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_entries, container, false);
initViewItems(rootView);
showError = false;
return rootView;
}
private void initViewItems(View rootView){
headerFrame = (FrameLayout) rootView.findViewById(R.id.headerFrame);
entriesScrollView = (ScrollView) rootView.findViewById(R.id.entriesScrollView);
fakeScrollView = (CustomScrollView) rootView.findViewById(R.id.fakeScroll);
progressBar = (ProgressBar) rootView.findViewById(R.id.loginProgressBar);
dummyView = rootView.findViewById(R.id.dummyView);
horizontalScrollView = (HorizontalScrollView) rootView.findViewById(R.id.horizontalScrollView);
entriesTable = new TableLayout(getActivity());
fakeScrollView.setOnTouchEventListener(new CustomScrollView.OnTouchEventListener() {
@Override
public boolean onTouchEvent(MotionEvent ev) {
ev.offsetLocation(0, headerFrame.getHeight());
horizontalScrollView.dispatchTouchEvent(ev);
return true;
}
});
layoutParams = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.MATCH_PARENT);
}
private void setLoading(boolean isLoading){
if(menu != null) {
menu.findItem(R.id.action_next).setEnabled(!isLoading);
menu.findItem(R.id.action_previous).setEnabled(!isLoading);
}
progressBar.setVisibility(isLoading ? View.VISIBLE : View.INVISIBLE);
}
@Override
public void onMatrixReturn(List<List<String>> rows) {
// Now we get Rows
if(rows!=null) {
int background;
for (int i = 0; i < rows.size(); i++) {
List<String> elements = rows.get(i);
TableRow newRow = new TableRow(getActivity());
if( i%2 == 0 ){ // Two backgrounds for lines for better visibility
background=R.drawable.entries_element_1;
} else {
background=R.drawable.entries_element_2;
}
for (int j = 0; j < elements.size(); j++) { // elements.size can be the same as in header so maybe some one number or not
TextView textView = new TextView(getActivity());
textView.setText(elements.get(j));
textView.setLayoutParams(layoutParams);
textView.setPadding(ENTRIES_PADDING_LEFT, ENTRIES_PADDING_TOP, ENTRIES_PADDING_RIGHT, ENTRIES_PADDING_BOTTOM);
textView.setBackgroundResource(background);
textView.setId(j);
newRow.addView(textView);
}
newRow.setClickable(false);
entriesTable.addView(newRow);
syncWidthsFirstStage();
}
} else {
entriesTable = null;
}
}
@Override
public void onListReturn(List<String> fieldList) {
// First we need header
headerRow = new TableRow(getActivity());
headerRow.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
for (String aFieldList : fieldList) {
TextView textView = new TextView(getActivity());
textView.setText(aFieldList);
textView.setTypeface(null, Typeface.BOLD);
textView.setLayoutParams(layoutParams);
textView.setBackgroundResource(R.drawable.background_header);
textView.setPadding(HEADER_PADDING_LEFT, HEADER_PADDING_TOP, HEADER_PADDING_RIGHT, HEADER_PADDING_BOTTOM);
headerRow.addView(textView);
}
}
private void syncWidthsFirstStage() { // TODO: Merge with adding columns maybe? Loops -= 3 should be quicker
maxWidth = new int[headerRow.getChildCount()];
for (int i = 0; i < headerRow.getChildCount(); i++) {
TextView textView = (TextView) headerRow.getChildAt(i);
textView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
maxWidth[i] = textView.getMeasuredWidth();
}
for (int i = 0; i < entriesTable.getChildCount(); i++) {
TableRow tableRow = (TableRow) entriesTable.getChildAt(i);
for (int j = 0; j < tableRow.getChildCount(); j++) {
TextView textView = (TextView) tableRow.getChildAt(j);
textView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = textView.getMeasuredWidth();
if (width > maxWidth[j])
maxWidth[j] = width;
}
}
}
private void syncWidthsSecondStage() {
for(int i=0;i<headerRow.getChildCount();i++){
TableRow entriesRow = (TableRow) entriesTable.getChildAt(0);
TextView tmpEntries = (TextView) entriesRow.getChildAt(i);
TextView tmpHeader = (TextView) headerRow.getChildAt(i);
tmpEntries.setWidth(maxWidth[i]);
tmpHeader.setWidth(maxWidth[i]);
}
}
private void fakeScroll(){
entriesScrollView.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
int height = entriesScrollView.getMeasuredHeight();
dummyView.setMinimumHeight(height);
RelativeLayout.LayoutParams fakeScrollLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
headerFrame.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
fakeScrollLayout.setMargins(0,headerFrame.getMeasuredHeight(),0,0);
fakeScrollView.setLayoutParams(fakeScrollLayout);
}
// @Override
// public void onResume() {
// super.onResume();
// if(!isFirstCreate) {
// getActivity().finish();
// } else {
// isFirstCreate = false;
// }
// }
@Override
public void onPostExecute() {
if(!showError) {
if (headerFrame.getChildCount() == 0) // You can have only one child
headerFrame.addView(headerRow);
if (entriesTable != null) {
syncWidthsSecondStage();
entriesScrollView.addView(entriesTable);
fakeScroll();
} else {
TextView errorMessage = new TextView(getActivity());
errorMessage.setText(R.string.error_no_entries);
errorMessage.setTypeface(null, Typeface.ITALIC);
errorMessage.setClickable(false);
entriesScrollView.addView(errorMessage);
}
setLoading(false);
} else {
setLoading(false);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(errorMessage);
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
getActivity().finish();
}
});
builder.setTitle(R.string.info);
builder.setIcon(R.drawable.ic_action_info);
builder.create();
builder.show();
}
}
@Override
public void onStringReturn(String data) {
errorMessage = data;
showError = true;
}
}

View file

@ -1,89 +0,0 @@
package info.nerull7.mysqlbrowser;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
/**
* Created by nerull7 on 30.09.14.
*/
public class SQLFragment extends Fragment implements DatabaseConnector.OnPostExecuteListener {
private EditText sqlEditText;
private InputMethodManager inputMethodManager;
private SQLEntriesFragment sqlEntriesFragment;
private FragmentTransaction fragmentTransaction;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sql, container, false);
sqlEditText = (EditText) rootView.findViewById(R.id.sqlQueryText);
setHasOptionsMenu(true);
return rootView;
}
@Override
public void onStart() {
super.onStart();
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(sqlEditText, InputMethodManager.SHOW_FORCED);
sqlEditText.requestFocus();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.action_execute:
actionExecute();
break;
case R.id.action_cancel:
actionCancel();
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.sql, menu);
super.onCreateOptionsMenu(menu, inflater);
}
private void actionCancel(){
inputMethodManager.hideSoftInputFromWindow(sqlEditText.getWindowToken(), 0);
getActivity().finish();
}
private void actionExecute(){
String sqlQuery = String.valueOf(sqlEditText.getText());
Log.d("SQLQUERY", sqlQuery);
fragmentTransaction = getFragmentManager().beginTransaction();
sqlEntriesFragment = new SQLEntriesFragment();
fragmentTransaction.replace(R.id.container, sqlEntriesFragment);
fragmentTransaction.commit();
Static.databaseConnector.setStringReturnListener(sqlEntriesFragment);
Static.databaseConnector.setListReturnListener(sqlEntriesFragment);
Static.databaseConnector.setMatrixReturnListener(sqlEntriesFragment);
Static.databaseConnector.setOnPostExecuteListener(this);
Static.databaseConnector.executeSQL(getActivity().getIntent().getExtras().getString(Static.DATABASE_NAME_ARG), sqlQuery);
}
@Override
public void onPostExecute() {
sqlEntriesFragment.onPostExecute();
}
}

View file

@ -1,5 +1,7 @@
package info.nerull7.mysqlbrowser;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.preference.PreferenceActivity;

View file

@ -6,26 +6,32 @@ import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.Base64;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
/**
* Created by nerull7 on 18.07.14.
*
* Fragment for Preferences/Settings
*/
public class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public class SettingsFragment extends PreferenceFragment implements NumberPickerDialog.OnNumberSetListener, Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public static final String ENTRIES_PAGE_LIMIT = "entries_limit";
public static final String ENTRIES_PAGE_LIMIT_STRING = "entries_limit_string";
public static final String SAVE_SERVER_CREDENTIALS = "save_credentials_enabled";
public static final String URL_CREDENTIALS = "url";
public static final String LOGIN_CREDENTIALS = "login";
public static final String PASSWORD_CREDENTIALS = "password";
public static final int ENTRIES_PAGE_LIMIT_DEF = 20;
public static final int ENTRIES_MIN_PAGE = 20;
public static final int ENTRIES_MAX_PAGE = 100;
private SharedPreferences preferences;
private EditTextPreference mEntriesLimit;
private Preference mEntriesLimit;
private CheckBoxPreference saveCredentials;
private EditTextPreference connectorUrlCredentials;
private EditTextPreference loginCredentials;
@ -36,8 +42,7 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
getPreferenceManager();
preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
preferences = getPreferenceManager().getDefaultSharedPreferences(getActivity());
crypto = new Crypto(getActivity());
loadPrefs();
@ -47,18 +52,17 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
addPreferencesFromResource(R.xml.settings);
// Getting fields
mEntriesLimit = (EditTextPreference) findPreference(ENTRIES_PAGE_LIMIT_STRING);
mEntriesLimit = findPreference(ENTRIES_PAGE_LIMIT);
saveCredentials = (CheckBoxPreference) findPreference(SAVE_SERVER_CREDENTIALS);
connectorUrlCredentials = (EditTextPreference) findPreference(URL_CREDENTIALS);
loginCredentials = (EditTextPreference) findPreference(LOGIN_CREDENTIALS);
passwordCredentials = (EditTextPreference) findPreference(PASSWORD_CREDENTIALS); // TODO: Some encryption
// Settings fields
setEntriesPageLimit();
setEntriesPageLimitSummary();
setPasswordCredentials();
// Settings Listener
mEntriesLimit.setOnPreferenceChangeListener(this);
saveCredentials.setOnPreferenceClickListener(this);
passwordCredentials.setOnPreferenceChangeListener(this);
}
@ -73,6 +77,7 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
}
editor.putBoolean(SAVE_SERVER_CREDENTIALS, isEnabled);
editor.apply();
editor.commit();
if(!isEnabled)
reloadLoginPrefsView();
@ -82,7 +87,7 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
saveCredentials.setChecked(preferences.getBoolean(SAVE_SERVER_CREDENTIALS, false));
connectorUrlCredentials.setText(preferences.getString(URL_CREDENTIALS, null));
loginCredentials.setText(preferences.getString(LOGIN_CREDENTIALS, null));
passwordCredentials.setText(preferences.getString(PASSWORD_CREDENTIALS, null));
passwordCredentials.setText(preferences.getString(PASSWORD_CREDENTIALS, null));;
}
private int getEntriesPageLimit(){
@ -93,11 +98,6 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
mEntriesLimit.setSummary(getString(R.string.entries_summary, getEntriesPageLimit()));
}
private void setEntriesPageLimit(){
mEntriesLimit.setText(String.valueOf(getEntriesPageLimit()));
setEntriesPageLimitSummary();
}
private void setPasswordCredentials(){
String password;
password = preferences.getString(PASSWORD_CREDENTIALS, null);
@ -118,6 +118,23 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
} catch (Exception e) { e.printStackTrace(); } // TODO: Something useful
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if(preference == mEntriesLimit){
new NumberPickerDialog(getActivity(), this, getEntriesPageLimit(), ENTRIES_MIN_PAGE, ENTRIES_MAX_PAGE, R.string.entries_limit).show();
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
@Override
public void onNumberSet(int number) {
SharedPreferences.Editor editor = preferences.edit();
editor.putInt(ENTRIES_PAGE_LIMIT, number);
editor.apply();
setEntriesPageLimitSummary();
}
@Override
public boolean onPreferenceClick(Preference preference) {
if(preference==saveCredentials){
@ -133,16 +150,7 @@ public class SettingsFragment extends PreferenceFragment implements Preference.O
public boolean onPreferenceChange(Preference preference, Object newValue) {
if(preference == passwordCredentials){
savePassword((String) newValue);
} else if (preference == mEntriesLimit) {
saveEntriesLimit((String) newValue);
}
return false;
}
private void saveEntriesLimit(String newValue) {
SharedPreferences.Editor editor = preferences.edit();
editor.putInt(ENTRIES_PAGE_LIMIT, Integer.parseInt(newValue));
editor.apply();
setEntriesPageLimit();
}
}

View file

@ -1,13 +1,11 @@
package info.nerull7.mysqlbrowser;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
import java.util.List;
import info.nerull7.mysqlbrowser.db.AsyncDatabaseConnector;
/**
* Created by nerull7 on 14.07.14.
@ -16,45 +14,15 @@ public class Static {
public static final String DATABASE_NAME_ARG = "DatabaseName";
public static final String TABLE_NAME_ARG = "TableName";
public static final String FRAGMENT_TO_START = "FragmentStarter";
public static final String FRAGMENT_DATABASE = "DatabaseFragment";
public static final String FRAGMENT_TABLE = "TableFragment";
public static DatabaseConnector databaseConnector = null;
public static AsyncDatabaseConnector asyncDatabaseConnector = null;
static List<String> tables;
static List<String> databases;
static List<String> header;
static List<List<String>> entries;
static int pageCount;
public static void startSettings(Context context){
Intent intent = new Intent(context, SettingsActivity.class);
context.startActivity(intent);
}
public static boolean isNetworkConnected(Context context){
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo!=null && networkInfo.isConnected()){
return true;
} else
return false;
}
public static void showErrorAlert(String errorMessage, Context context){
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(errorMessage);
builder.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Nothing to do here
// Cleaning inputs is stupid
}
});
builder.setTitle(R.string.error);
builder.setIcon(R.drawable.ic_action_warning);
builder.create();
builder.show();
}
public static void startSQL(Context context, String database) {
Intent intent = new Intent(context, SQLActivity.class);
intent.putExtra(Static.DATABASE_NAME_ARG, database);
context.startActivity(intent);
}
}

View file

@ -0,0 +1,46 @@
package info.nerull7.mysqlbrowser;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class TableActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_table);
setTitle(getIntent().getStringExtra(Static.DATABASE_NAME_ARG));
TableFragment tableFragment = new TableFragment();
tableFragment.setArguments(getIntent().getExtras());
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, tableFragment)
.commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
Static.startSettings(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -4,9 +4,11 @@ import android.app.Fragment;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
@ -17,18 +19,20 @@ import android.widget.TextView;
import java.util.List;
import info.nerull7.mysqlbrowser.db.DatabaseConnector;
import info.nerull7.mysqlbrowser.db.AsyncDatabaseConnector;
/**
* Created by nerull7 on 14.07.14.
*/
public class TableFragment extends Fragment implements AdapterView.OnItemClickListener, DatabaseConnector.ListReturnListener, DatabaseConnector.OnPostExecuteListener {
public class TableFragment extends Fragment implements AdapterView.OnItemClickListener, AsyncDatabaseConnector.ListReturnListener, AsyncDatabaseConnector.IntegerReturnListener, AsyncDatabaseConnector.MatrixReturnListener {
private String databaseName;
private ListView tablesList;
private ListAdapter listAdapter;
private RelativeLayout rootView;
private ProgressBar progressBar;
private List<String> tables;
private int listenerCalled;
private String chosenTable;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@ -38,36 +42,12 @@ public class TableFragment extends Fragment implements AdapterView.OnItemClickLi
tablesList = (ListView) rootView.findViewById(R.id.tableList);
this.rootView = (RelativeLayout) rootView;
progressBar = (ProgressBar) rootView.findViewById(R.id.loginProgressBar);
Static.databaseConnector.setListReturnListener(this);
Static.databaseConnector.setOnPostExecuteListener(this);
Static.databaseConnector.getTables();
return rootView;
}
listenerCalled = 0;
// Static.asyncDatabaseConnector.setListReturnListener(this);
// Static.asyncDatabaseConnector.getTables();
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
if(Static.isNetworkConnected(getActivity())) {
String chosenTable = (String) listAdapter.getItem(position);
listAdapter.getItem(position);
Intent intent = new Intent(getActivity(), EntriesActivity.class);
intent.putExtra(Static.DATABASE_NAME_ARG,databaseName);
intent.putExtra(Static.TABLE_NAME_ARG,chosenTable);
startActivity(intent);
} else {
Static.showErrorAlert(getResources().getString(R.string.no_connection), getActivity());
}
}
@Override
public void onListReturn(List<String> tables) {
this.tables = tables;
}
@Override
public void onPostExecute() {
if(tables != null) {
listAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1, tables);
if(Static.tables != null) {
listAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1, Static.tables);
tablesList.setAdapter(listAdapter);
tablesList.setOnItemClickListener(this);
} else {
@ -75,9 +55,73 @@ public class TableFragment extends Fragment implements AdapterView.OnItemClickLi
errorMessage.setText(R.string.error_no_tables);
errorMessage.setTypeface(null, Typeface.ITALIC);
errorMessage.setClickable(false);
rootView.addView(errorMessage);
rootView.removeView(tablesList);
this.rootView.addView(errorMessage);
this.rootView.removeView(tablesList);
}
progressBar.setVisibility(View.INVISIBLE);
return rootView;
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
chosenTable = (String) listAdapter.getItem(position);
listAdapter.getItem(position);
progressBar.setVisibility(View.VISIBLE);
Static.asyncDatabaseConnector.setIntegerReturnListener(this);
Static.asyncDatabaseConnector.setListReturnListener(this);
Static.asyncDatabaseConnector.setMatrixReturnListener(this);
int entriesLimit = PreferenceManager.getDefaultSharedPreferences(getActivity()).getInt(SettingsFragment.ENTRIES_PAGE_LIMIT, SettingsFragment.ENTRIES_PAGE_LIMIT_DEF);
Static.asyncDatabaseConnector.getRows(chosenTable, entriesLimit, 1);
Static.asyncDatabaseConnector.getFields(chosenTable);
Static.asyncDatabaseConnector.getEntriesCount(chosenTable);
}
@Override
public void onListReturn(List<String> header) {
// if(tables != null) {
// listAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1, tables);
// tablesList.setAdapter(listAdapter);
// tablesList.setOnItemClickListener(this);
// } else {
// TextView errorMessage = new TextView(getActivity());
// errorMessage.setText(R.string.error_no_tables);
// errorMessage.setTypeface(null, Typeface.ITALIC);
// errorMessage.setClickable(false);
// rootView.addView(errorMessage);
// rootView.removeView(tablesList);
// }
// progressBar.setVisibility(View.INVISIBLE);
Static.header = header;
listenerCalled++;
if(listenerCalled==3)
startEntriesActivity();
}
@Override
public void onIntegerReturn(int result) {
Static.pageCount = result;
listenerCalled++;
if(listenerCalled==3)
startEntriesActivity();
}
@Override
public void onMatrixReturn(List<List<String>> data) {
Static.entries = data;
listenerCalled++;
if(listenerCalled==3)
startEntriesActivity();
}
private void startEntriesActivity() {
Intent intent = new Intent(getActivity(), EntriesActivity.class);
intent.putExtra(Static.DATABASE_NAME_ARG,databaseName);
intent.putExtra(Static.TABLE_NAME_ARG,chosenTable);
startActivity(intent);
}
}

View file

@ -0,0 +1,289 @@
package info.nerull7.mysqlbrowser.db;
import android.os.AsyncTask;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Created by nerull7 on 07.07.14.
*/
public class AsyncDatabaseConnector {
public static final String ACTION_LOGIN = "login";
public static final String ACTION_DATABASE_LIST = "dblist";
public static final String ACTION_TABLE_LIST = "tablelist";
public static final String ACTION_FIELD_LIST = "fieldlist";
public static final String ACTION_ENTRIES_COUNT = "numrows";
public static final String ACTION_DATA_MATRIX = "getrows";
private String login;
private String password;
private String url;
private String database;
private BooleanReturnListener booleanReturnListener;
private IntegerReturnListener integerReturnListener;
private StringReturnListener stringReturnListener;
private ListReturnListener listReturnListener;
private MatrixReturnListener matrixReturnListener;
public static String errorMsg;
public AsyncDatabaseConnector(String login, String password, String url){
this.login = login;
this.password = password;
this.url = url;
booleanReturnListener=null;
stringReturnListener=null;
listReturnListener=null;
matrixReturnListener=null;
}
private String actionUrlBuilder(String action){ // TODO Better UrlBuilder this is shit only for use
String urlBuilder = url;
urlBuilder += "?u="+login;
urlBuilder += "&p="+password;
urlBuilder += "&a="+action;
// Log.d("URLBuilder", urlBuilder);
return urlBuilder;
}
public void setDatabaseInUse(String database){
this.database = database;
}
private void getList(String urlQuery){
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
List<String>list = null;
try {
list = parseListFromJSON(data);
} catch (JSONException e) { e.printStackTrace(); }
if(listReturnListener!=null)
listReturnListener.onListReturn(list);
}
});
downloader.execute(urlQuery);
}
private void getMatrix(String urlQuery){
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
List<List<String>> list = null;
try {
list = parseMatrixFromJSON(data);
} catch (JSONException e) { e.printStackTrace(); }
if(matrixReturnListener!=null)
matrixReturnListener.onMatrixReturn(list);
}
});
downloader.execute(urlQuery);
}
private List<String> parseListFromJSON(String jsonListString) throws JSONException {
JSONArray jsonArray = new JSONArray(jsonListString);
List<String> databaseStringList = new ArrayList<String>();
for(int i=0;i<jsonArray.length();i++){
databaseStringList.add(jsonArray.getString(i));
}
return databaseStringList;
}
private List<List<String>> parseMatrixFromJSON(String jsonMatrixString) throws JSONException {
JSONArray jsonMatrix = new JSONArray(jsonMatrixString);
List<List<String>> matrix = new ArrayList<List<String>>();
for(int i=0;i<jsonMatrix.length();i++){
JSONArray jsonArray = jsonMatrix.getJSONArray(i);
List<String> list = new ArrayList<String>();
for(int j=0;j<jsonArray.length();j++){
list.add(jsonArray.getString(j));
}
matrix.add(list);
}
return matrix;
}
public boolean checkLogin(){
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
List<String>list = null;
boolean listenerData;
if(data==null) {
listenerData = false;
errorMsg = error;
}
else if(booleanReturnListener!=null)
listenerData = (data.compareTo("OK")==0);
else {
errorMsg = data;
listenerData = false;
}
booleanReturnListener.onBooleanReturn(listenerData);
}
});
downloader.execute(actionUrlBuilder(ACTION_LOGIN));
return false;
}
public void getDatabases(){
getList(actionUrlBuilder(ACTION_DATABASE_LIST));
}
public void getTables(){
getList(actionUrlBuilder(ACTION_TABLE_LIST)+"&d="+database);
}
public void getFields(String table){
getList(actionUrlBuilder(ACTION_FIELD_LIST)+"&d="+database+"&t="+table);
}
public void getRows(String table, int count, int page){
int limitStart = (page-1) * count;
getMatrix(actionUrlBuilder(ACTION_DATA_MATRIX)+"&d="+database+"&t="+table+"&s="+limitStart+"&l="+count);
}
public void getEntriesCount(String table){
String urlQuery = actionUrlBuilder(ACTION_ENTRIES_COUNT)+"&d="+database+"&t="+table;
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
if(integerReturnListener!=null)
integerReturnListener.onIntegerReturn(Integer.parseInt(data));
}
});
downloader.execute(urlQuery);
}
public void setBooleanReturnListener(BooleanReturnListener booleanReturnListener){
this.booleanReturnListener = booleanReturnListener;
}
public void setStringReturnListener(StringReturnListener stringReturnListener) {
this.stringReturnListener = stringReturnListener;
}
public void setIntegerReturnListener(IntegerReturnListener integerReturnListener){
this.integerReturnListener = integerReturnListener;
}
public void setListReturnListener(ListReturnListener listReturnListener) {
this.listReturnListener = listReturnListener;
}
public void setMatrixReturnListener(MatrixReturnListener matrixReturnListener) {
this.matrixReturnListener = matrixReturnListener;
}
public static interface BooleanReturnListener{
public void onBooleanReturn(boolean result);
}
public static interface IntegerReturnListener{
public void onIntegerReturn(int result);
}
public static interface StringReturnListener{
public void onStringReturn(String data);
}
public static interface ListReturnListener {
public void onListReturn(List<String> data);
}
public static interface MatrixReturnListener{
public void onMatrixReturn(List<List<String>> data);
}
private static class Downloader extends AsyncTask<String, Void, String> {
private OnFinishedListener onFinishedListener;
private String errorString;
public static final String CONNECTION_REQUEST_METHOD = "GET";
public static final int CONNECTION_TIMEOUT = 15000;
public static final int READ_TIMEOUT = 10000;
Downloader(OnFinishedListener onFinishedListener){
this.onFinishedListener = onFinishedListener;
errorString = null;
}
private String httpRequest(String urlRequest) throws IOException {
URL url = new URL(urlRequest);
InputStream inputStream = null;
String response;
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // TODO Handling no connection
urlConnection.setReadTimeout(READ_TIMEOUT);
urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);
urlConnection.setRequestMethod(CONNECTION_REQUEST_METHOD);
urlConnection.connect();
if(urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
try {
inputStream = urlConnection.getInputStream();
response = readStream(inputStream);
} finally {
if(inputStream!=null)
inputStream.close();
urlConnection.disconnect();
}
return response;
}
else {
errorString = "ERROR "+urlConnection.getResponseCode()+": "+urlConnection.getResponseMessage();
return null;
}
}
private String readStream(InputStream in) throws IOException {
String streamOutput = "";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
streamOutput += line;
}
} finally {
if (reader != null) {
reader.close();
}
}
return streamOutput;
}
@Override
protected String doInBackground(String... strings) {
try {
return httpRequest(strings[0]);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String data) {
onFinishedListener.onFinished(data, errorString); // Can't be null cos we demand listener in constructor
}
private static interface OnFinishedListener {
void onFinished(String data, String error);
}
}
}

View file

@ -1,565 +0,0 @@
package info.nerull7.mysqlbrowser.db;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import info.nerull7.mysqlbrowser.R;
/**
* Created by nerull7 on 07.07.14.
* Database connector using Async calls
*/
public class DatabaseConnector {
public static final String ACTION_LOGIN = "login";
public static final String ACTION_DATABASE_LIST = "dblist";
public static final String ACTION_TABLE_LIST = "tablelist";
public static final String ACTION_FIELD_LIST = "fieldlist";
public static final String ACTION_ENTRIES_COUNT = "numrows";
public static final String ACTION_DATA_MATRIX = "getrows";
public static final String ACTION_ADD_ELEMENT = "addelement";
public static final String ACTION_UPDATE_ELEMENT = "updateelement";
public static final String ACTION_REMOVE_ELEMENT = "removeelement";
public static final String ACTION_SQL_QUERY = "query";
private String login;
private String password;
private String url;
private String database;
private final Resources resources;
private BooleanReturnListener booleanReturnListener;
private IntegerReturnListener integerReturnListener;
private StringReturnListener stringReturnListener;
private ListReturnListener listReturnListener;
private MatrixReturnListener matrixReturnListener;
public static String errorMsg;
private OnPostExecuteListener onPostExecuteListener;
public DatabaseConnector(String login, String password, String url, Resources resources){
this.login = login;
this.password = password;
this.url = url;
this.resources = resources;
booleanReturnListener=null;
stringReturnListener=null;
listReturnListener=null;
matrixReturnListener=null;
}
private Request requestBuilder(String action){
Request request = new Request(url);
String urlData = "u="+login
+ "&p="+password
+ "&a="+action;
request.data = urlData;
return request;
}
private Request actionUrlBuilder(String action, String argument, String value){
ArrayList<String> arguments = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
arguments.add(argument);
values.add(value);
return this.actionUrlBuilder(action, arguments, values);
}
private Request actionUrlBuilder(String action, List<String> arguments, List<String> values){ // TODO Better UrlBuilder this is shit only for use
Request urlBuilder = requestBuilder(action);
for (int i = 0; i < arguments.size(); i++) {
try {
urlBuilder.data += "&" + arguments.get(i) + "=" + URLEncoder.encode(values.get(i), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
// Log.d("URLBuilder", urlBuilder);
return urlBuilder;
}
public void setDatabaseInUse(String database){
this.database = database;
}
private void getList(Request urlQuery){
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
List<String>list = null;
try {
list = parseListFromJSON(data);
} catch (JSONException e) { e.printStackTrace(); }
if(listReturnListener!=null) {
listReturnListener.onListReturn(list);
}
errorMsg = error;
}
}, onPostExecuteListener, resources);
downloader.execute(urlQuery);
}
private void getMatrix(Request urlQuery){
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
List<List<String>> list = null;
try {
list = parseMatrixFromJSON(data);
} catch (JSONException e) { e.printStackTrace(); }
if(matrixReturnListener!=null)
matrixReturnListener.onMatrixReturn(list);
errorMsg = error;
}
}, onPostExecuteListener, resources);
downloader.execute(urlQuery);
}
private List<String> parseListFromJSON(String jsonListString) throws JSONException {
JSONArray jsonArray = new JSONArray(jsonListString);
List<String> databaseStringList = new ArrayList<String>();
for(int i=0;i<jsonArray.length();i++){
databaseStringList.add(jsonArray.getString(i));
}
return databaseStringList;
}
private List<List<String>> parseMatrixFromJSON(String jsonMatrixString) throws JSONException {
JSONArray jsonMatrix = new JSONArray(jsonMatrixString);
List<List<String>> matrix = new ArrayList<List<String>>();
for(int i=0;i<jsonMatrix.length();i++){
JSONArray jsonArray = jsonMatrix.getJSONArray(i);
List<String> list = new ArrayList<String>();
for(int j=0;j<jsonArray.length();j++){
list.add(jsonArray.getString(j));
}
matrix.add(list);
}
return matrix;
}
public boolean checkLogin(){
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
boolean listenerData;
if(data == null) {
listenerData = false;
errorMsg = error;
} else if( data.compareTo("OK") == 0){
listenerData = true;
} else {
errorMsg = data;
listenerData = false;
}
booleanReturnListener.onBooleanReturn(listenerData);
}
}, onPostExecuteListener, resources);
downloader.execute(requestBuilder(ACTION_LOGIN));
return false;
}
public void getDatabases(){
getList(requestBuilder(ACTION_DATABASE_LIST));
}
public void getTables(){
getList(actionUrlBuilder(ACTION_TABLE_LIST, "d", database));
}
public void getFields(String table){
ArrayList<String> args = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
args.add("d");
values.add(database);
args.add("t");
values.add(table);
getList(actionUrlBuilder(ACTION_FIELD_LIST, args, values));
}
public void getRows(String table, int count, int page){
int limitStart = (page-1) * count;
ArrayList<String> args = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
args.add("d");
values.add(database);
args.add("t");
values.add(table);
args.add("s");
values.add(String.valueOf(limitStart));
args.add("l");
values.add(String.valueOf(count));
getMatrix(actionUrlBuilder(ACTION_DATA_MATRIX, args, values));
}
public void getEntriesCount(String table){
ArrayList<String> args = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
args.add("d");
values.add(database);
args.add("t");
values.add(table);
Request urlQuery = actionUrlBuilder(ACTION_ENTRIES_COUNT, args, values);
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
if(integerReturnListener!=null)
integerReturnListener.onIntegerReturn(Integer.parseInt(data));
errorMsg = error;
}
}, onPostExecuteListener, resources);
downloader.execute(urlQuery);
}
public void addNewElement(String table, List<String> header, List<String> values) {
this.updateElement(table, header, null, values);
}
public void updateElement(String table, List<String> header, List<String> oldValues, List<String> newValues){
JSONArray headerJSON = new JSONArray();
JSONArray newValuesJSON = new JSONArray();
Request request;
ArrayList<String> args = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
args.add("d");
values.add(database);
args.add("t");
values.add(table);
for (String aHeader : header) {
headerJSON.put(aHeader);
}
for (String newValue : newValues) {
newValuesJSON.put(newValue);
}
args.add("h");
values.add(headerJSON.toString());
args.add("v");
values.add(newValuesJSON.toString());
if(oldValues!=null){
JSONArray oldValuesJSON = new JSONArray();
for(int i=0;i<newValues.size();i++){
oldValuesJSON.put(oldValues.get(i));
}
args.add("o");
values.add(oldValuesJSON.toString());
request = actionUrlBuilder(ACTION_UPDATE_ELEMENT, args, values);
} else
request = actionUrlBuilder(ACTION_ADD_ELEMENT, args, values);
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
if(stringReturnListener!=null){
stringReturnListener.onStringReturn(data);
}
errorMsg = error;
}
}, onPostExecuteListener, resources);
downloader.execute(request);
}
public void removeElement(String table, List<String> header, List<String> values) {
JSONArray headerJSON = new JSONArray();
JSONArray valuesJSON = new JSONArray();
Request request;
ArrayList<String> args = new ArrayList<String>();
ArrayList<String> argValues = new ArrayList<String>();
args.add("d");
argValues.add(database);
args.add("t");
argValues.add(table);
for (String aHeader : header) {
headerJSON.put(aHeader);
}
for (String value : values) {
valuesJSON.put(value);
}
args.add("h");
argValues.add(headerJSON.toString());
args.add("v");
argValues.add(valuesJSON.toString());
request = actionUrlBuilder(ACTION_REMOVE_ELEMENT, args, argValues);
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
if(stringReturnListener!=null){
stringReturnListener.onStringReturn(data);
}
errorMsg = error;
}
}, onPostExecuteListener, resources);
downloader.execute(request);
}
public void executeSQL(String database, String query){
ArrayList<String> args = new ArrayList();
ArrayList<String> values = new ArrayList();
final Request request;
if(database!=null){
args.add("d");
values.add(database);
}
args.add("q");
values.add(query);
request = actionUrlBuilder(ACTION_SQL_QUERY, args, values);
Downloader downloader = new Downloader(new Downloader.OnFinishedListener() {
@Override
public void onFinished(String data, String error) {
String []response = data.split("\n");
if(response[0].equals("OK")) {
List<String> headerList = null;
try {
headerList = parseListFromJSON(response[1]);
} catch (JSONException e) {
e.printStackTrace();
}
if (listReturnListener != null) {
listReturnListener.onListReturn(headerList);
}
List<List<String>> dataMatrix = null;
try {
dataMatrix = parseMatrixFromJSON(response[2]);
} catch (JSONException e) {
e.printStackTrace();
}
if (matrixReturnListener != null)
matrixReturnListener.onMatrixReturn(dataMatrix);
} else {
if(stringReturnListener!=null)
stringReturnListener.onStringReturn(data);
}
}
}, onPostExecuteListener, resources);
downloader.execute(request);
}
public void setBooleanReturnListener(BooleanReturnListener booleanReturnListener){
this.booleanReturnListener = booleanReturnListener;
}
public void setStringReturnListener(StringReturnListener stringReturnListener) {
this.stringReturnListener = stringReturnListener;
}
public void setIntegerReturnListener(IntegerReturnListener integerReturnListener){
this.integerReturnListener = integerReturnListener;
}
public void setListReturnListener(ListReturnListener listReturnListener) {
this.listReturnListener = listReturnListener;
}
public void setMatrixReturnListener(MatrixReturnListener matrixReturnListener) {
this.matrixReturnListener = matrixReturnListener;
}
public void setOnPostExecuteListener(OnPostExecuteListener onPostExecuteListener){
this.onPostExecuteListener = onPostExecuteListener;
}
public static interface BooleanReturnListener{
public void onBooleanReturn(boolean result);
}
public static interface IntegerReturnListener{
public void onIntegerReturn(int result);
}
public static interface StringReturnListener{
public void onStringReturn(String data);
}
public static interface ListReturnListener {
public void onListReturn(List<String> data);
}
public static interface MatrixReturnListener{
public void onMatrixReturn(List<List<String>> data);
}
public static interface OnPostExecuteListener {
void onPostExecute();
}
private static class Downloader extends AsyncTask<Request, Void, String> {
private OnFinishedListener onFinishedListener;
private OnPostExecuteListener onPostExecuteListener;
private String errorString;
private Resources resources;
public static final String CONNECTION_REQUEST_METHOD = "POST";
public static final int CONNECTION_TIMEOUT = 15000; // ms
public static final int READ_TIMEOUT = 10000; // ms
private Downloader(OnFinishedListener onFinishedListener, OnPostExecuteListener onPostExecuteListener, Resources resources){
this.onFinishedListener = onFinishedListener;
this.onPostExecuteListener = onPostExecuteListener;
this.resources = resources;
errorString = null;
}
private String httpRequest(Request urlRequest) throws IOException {
URL url = new URL(urlRequest.url);
InputStream inputStream = null;
String response;
// Log.d("URL REQUEST", urlRequest);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // TODO Handling no connection
urlConnection.setReadTimeout(READ_TIMEOUT);
urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);
urlConnection.setRequestMethod(CONNECTION_REQUEST_METHOD);
OutputStream outputStream = urlConnection.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write(urlRequest.data);
outputStreamWriter.flush();
outputStreamWriter.close();
outputStream.close();
try {
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
try {
inputStream = urlConnection.getInputStream();
response = readStream(inputStream);
} finally {
if (inputStream != null)
inputStream.close();
urlConnection.disconnect();
}
return response;
} else {
errorString = "ERROR " + urlConnection.getResponseCode() + ": " + urlConnection.getResponseMessage();
}
} catch (Exception e) {
parseException(e);
}
return null;
}
private void parseException(Exception e){
if(e instanceof SocketException){
if(e.getMessage().contains("ECONNREFUSED")) {
errorString = resources.getString(R.string.error_connection_refused);
} else if(e.getMessage().contains("EHOSTUNREACH")) {
errorString = resources.getString(R.string.error_connection_unreachable);
} else {
errorString = "Exception: " + e.getClass();
}
} else if (e instanceof SocketTimeoutException){
errorString = resources.getString(R.string.error_connection_timeout);
} else {
errorString = "Exception: " + e.getClass();
}
}
private String readStream(InputStream in) throws IOException {
String streamOutput = "";
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
streamOutput += line + '\n';
}
} finally {
if (reader != null) {
reader.close();
}
}
return streamOutput.substring(0, streamOutput.length()-1); // Remove last \n
}
@Override
protected String doInBackground(Request... requests) {
try {
String data = httpRequest(requests[0]);
onFinishedListener.onFinished(data, errorString); // Can't be null cos we demand listener in constructor
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String data) {
if (onPostExecuteListener!=null)
onPostExecuteListener.onPostExecute();
}
public void setOnPostExecuteListener(OnPostExecuteListener onPostExecuteListener) {
this.onPostExecuteListener = onPostExecuteListener;
}
private static interface OnFinishedListener {
void onFinished(String data, String error);
}
}
class Request{
String url;
String data;
Request(String url){
this.url = url;
}
}
}

Binary file not shown.

Before

(image error) Size: 711 B

Binary file not shown.

Before

(image error) Size: 764 B

Binary file not shown.

Before

(image error) Size: 380 B

Binary file not shown.

Before

(image error) Size: 696 B

Binary file not shown.

Before

(image error) Size: 575 B

Binary file not shown.

Before

(image error) Size: 1 KiB

Binary file not shown.

Before

(image error) Size: 497 B

Binary file not shown.

Before

(image error) Size: 507 B

Binary file not shown.

Before

(image error) Size: 271 B

Binary file not shown.

Before

(image error) Size: 469 B

Binary file not shown.

Before

(image error) Size: 387 B

Binary file not shown.

Before

(image error) Size: 666 B

Binary file not shown.

Before

(image error) Size: 885 B

Binary file not shown.

Before

(image error) Size: 990 B

Binary file not shown.

Before

(image error) Size: 466 B

Binary file not shown.

Before

(image error) Size: 891 B

Binary file not shown.

Before

(image error) Size: 807 B

Binary file not shown.

Before

(image error) Size: 1.4 KiB

Binary file not shown.

Before

(image error) Size: 1.6 KiB

Binary file not shown.

Before

(image error) Size: 1.7 KiB

Binary file not shown.

Before

(image error) Size: 832 B

Binary file not shown.

Before

(image error) Size: 1.5 KiB

Binary file not shown.

Before

(image error) Size: 1.2 KiB

Binary file not shown.

Before

(image error) Size: 2 KiB

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/entries_background_color_1"/>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--<solid android:color="#0fff"/>-->
<stroke android:width="1dp" android:color="@color/border"/>
</shape>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/entries_background_color_2"/>
<stroke android:width="1dp" android:color="@color/border"/>
</shape>

View file

@ -3,5 +3,5 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.nerull7.mysqlbrowser.ElementActivity"
tools:context="info.nerull7.mysqlbrowser.DatabaseActivity"
tools:ignore="MergeRootFrame" />

View file

@ -1,7 +0,0 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.nerull7.mysqlbrowser.ListActivity"
tools:ignore="MergeRootFrame" />

View file

@ -3,5 +3,5 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.nerull7.mysqlbrowser.ListActivity"
tools:context="info.nerull7.mysqlbrowser.TableActivity"
tools:ignore="MergeRootFrame" />

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="false"
android:layout_marginTop="-7dp" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_below="@+id/progressBar"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:descendantFocusability="afterDescendants"/>
</RelativeLayout>

View file

@ -4,9 +4,22 @@
android:layout_height="match_parent"
tools:context="info.nerull7.mysqlbrowser.EntriesFragment">
<HorizontalScrollView
android:layout_width="fill_parent"
<ScrollView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_below="@+id/loginProgressBar"
android:layout_alignParentRight="true"
android:foregroundGravity="right"
android:id="@+id/fakeScroll">
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/dummyView"/>
</ScrollView>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/horizontalScrollView" >
<RelativeLayout
@ -20,18 +33,18 @@
android:id="@+id/headerFrame"
></FrameLayout>
<ScrollView
<info.nerull7.mysqlbrowser.CustomScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/entriesScrollView"
android:layout_below="@+id/headerFrame"
android:scrollbars="none">
<!--<TableLayout-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:id="@+id/entriesTable">-->
<!--</TableLayout>-->
</ScrollView>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/entriesTable">
</TableLayout>
</info.nerull7.mysqlbrowser.CustomScrollView>
</RelativeLayout>
</HorizontalScrollView>
@ -45,17 +58,4 @@
android:layout_alignParentTop="false"
android:layout_marginTop="-7dp" />
<info.nerull7.mysqlbrowser.CustomScrollView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:foregroundGravity="right"
android:id="@+id/fakeScroll"
android:overScrollMode="never">
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/dummyView"/>
</info.nerull7.mysqlbrowser.CustomScrollView>
</RelativeLayout>

View file

@ -1,24 +0,0 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.nerull7.mysqlbrowser.DatabaseFragment">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/sqlQueryText"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:gravity="left|top"
android:hint="@string/hint_sql_query" >
<requestFocus/>
</EditText>
</RelativeLayout>

View file

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textFieldName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editFieldValue"
android:layout_below="@+id/textFieldName"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/action_save"
android:title="@string/action_save"
android:showAsAction="always"
android:icon="@drawable/ic_action_save"/>
<item android:id="@+id/action_remove"
android:title="@string/action_remove"
android:showAsAction="always"
android:icon="@drawable/ic_action_delete"/>
</menu>

View file

@ -1,12 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_add"
android:icon="@drawable/ic_action_add_circle"
android:title="@string/action_add"
android:showAsAction="ifRoom" />
<item
android:id="@+id/action_previous"
android:icon="@drawable/ic_action_arrow_back"

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
android:showAsAction="never" />
<item android:id="@+id/action_sql"
android:title="@string/sql_query"
android:orderInCategory="200"
android:showAsAction="never" />
</menu>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/action_execute"
android:title="@string/action_execute"
android:showAsAction="always"
android:icon="@drawable/ic_action_file_upload"/>
<item android:id="@+id/action_cancel"
android:title="@string/action_cancel"
android:showAsAction="always"
android:icon="@drawable/ic_action_delete"/>
</menu>

View file

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Przeglądarka Mysql</string>
<string name="action_settings">Ustawienia</string>
<string name="action_add">Dodaj nowy</string>
<string name="action_remove">Usuń</string>
<string name="action_previous">Poprzedni</string>
<string name="action_next">Następny</string>
<string name="title_fragment_database">Dostępne bazy</string>
<string name="login">Zaloguj</string>
<string name="password">Hasło</string>
<string name="username">Użytkownik</string>
<string name="yes">Tak</string>
<string name="no">Nie</string>
<string name="ok">OK</string>
<string name="cancel">Anuluj</string>
<string name="action_save">Zapisz</string>
<string name="set">Ustaw</string>
<string name="back">Cofnij</string>
<string name="status">Info</string>
<string name="warning">Ostrzeżenie</string>
<string name="error">Błąd</string>
<string name="login_error">Zły login/hasło</string>
<string name="general_category">Ogólne</string>
<string name="entries_limit">Limit wpisów na stronę</string>
<string name="entries_summary">%s na stronę</string> <!-- <xliff:g id="count"></xliff:g> -->
<string name="error_no_tables">Brak tabel w tej bazie</string>
<string name="error_no_entries">Brak wpisów w tej bazie</string>
<string name="error_no_databases">Brak dostępnych baz</string>
<string name="error_no_save">Twoje dane <b>NIE</b> zostaną zapisane! Czy chciałbyś kontynuować?</string>
<string name="error_remove">Ten wpis zostanie usunięty z bazy. Tej akcji <b>NIE MOŻNA</b> cofnąć! Czy chciałbyś kontynuować?</string>
<string name="error_connection_timeout">Przekroczono czas połączenia</string>
<string name="error_connection_reset">Połączenie zostało zrestartowane</string>
<string name="error_connection_unreachable">No route to host</string>
<string name="pref_entries_per_page">Ustaw limit wpisów na stronę</string>
<string name="login_settings">Poświadczenia logowania</string>
<string name="save_credentials">Zapamiętaj poświadczenia</string>
<string name="connector_url">URL Wtyczki php</string>
<string name="no_connection">Brak połączenia internetowego</string>
</resources>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="android:Theme.Holo.Light">
</style>
</resources>

View file

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="border">@android:color/tab_indicator_text</color>
<color name="header_background">#ffaa22</color>
<color name="header_login_background">@android:color/holo_blue_dark</color>
<color name="entries_background_color_1">@android:color/background_light</color>
<color name="entries_background_color_2">#ffcccccc</color>
<color name="header_background">@android:color/holo_orange_light</color>
</resources>

View file

@ -1,63 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Mysql Browser</string>
<string name="action_settings">Settings</string>
<string name="action_add">Add new</string>
<string name="action_remove">Remove</string>
<string name="action_previous">Previous</string>
<string name="action_next">Next</string>
<string name="title_activity_main">MainActivity</string>
<string name="title_activity_entries">EntriesActivity</string>
<string name="title_activity_setting">Settings</string>
<string name="title_activity_element">ElementActivity</string>
<string name="title_activity_list">ListActivity</string>
<string name="title_fragment_database">Available Databases</string>
<string name="login">Log in</string>
<string name="password">Password</string>
<string name="username">Username</string>
<string name="hint_url">URL ex: https://example.com/c.php</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="ok">OK</string>
<string name="cancel">Cancel</string>
<string name="action_save">Save</string>
<string name="set">Set</string>
<string name="back">Back</string>
<string name="status">Status</string>
<string name="warning">Warning</string>
<string name="error">Error</string>
<string name="title_activity_main">MainActivity</string>
<string name="title_activity_database">DatabaseActivity</string>
<string name="hello_world">Hello world!</string>
<string name="login_error">Wrong login/password</string>
<string name="ok">OK</string>
<string name="error">Error</string>
<string name="title_activity_table">TableActivity</string>
<string name="title_activity_entries">EntriesActivity</string>
<string name="general_category">General</string>
<string name="entries_limit">Entries per page limit</string>
<string name="entries_summary">%s entries per page</string> <!-- <xliff:g id="count"></xliff:g> -->
<string name="entries_summary">%s entries per page</string><!--<xliff:g id="count"></xliff:g>-->
<string name="title_activity_setting">Settings</string>
<string name="cancel">Cancel</string>
<string name="set">Set</string>
<string name="pref_entries_per_page">Set number of entries per page</string>
<string name="error_no_tables">No tables in this database</string>
<string name="error_no_entries">No entries in this table</string>
<string name="error_no_databases">No available databases</string>
<string name="error_no_save">Your data will <b>NOT</b> be saved! Would you like to continue?</string>
<string name="error_remove">This entry will be removed from database. This action <b>CAN NOT</b> be reversed! Would you like to continue?</string>
<string name="error_connection_timeout">Connection timeout</string>
<string name="error_connection_reset">Connection reset by peer</string>
<string name="error_connection_refused">Connection refused</string>
<string name="error_connection_unreachable">No route to host</string>
<string name="pref_entries_per_page">Set number of entries per page</string>
<string name="action_previous">Previous</string>
<string name="action_next">Next</string>
<string name="login_settings">Login credentials</string>
<string name="save_credentials">Save credentials</string>
<string name="connector_url">Connector URL</string>
<string name="no_connection">No Internet Connection</string>
<string name="sql_query">SQL Query</string>
<string name="title_activity_sql">SQL Query</string>
<string name="hint_sql_query">SQL Query</string>
<string name="action_cancel">Cancel</string>
<string name="action_execute">Execute</string>
<string name="info">Information</string>
</resources>

View file

@ -1,20 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--Action Bar styles-->
<style name="DefaultActionBar"
parent="android:Widget.Holo.Light.ActionBar.Solid" >
<item name="android:background">@color/header_background</item>
<item name="android:icon">@drawable/ic_revert</item>
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
<style name="LoginActionBar"
parent="DefaultActionBar" >
<item name="android:background">@color/header_login_background</item>
<item name="android:icon">@drawable/ic_launcher</item>
<style name="TableTheme">
<item name="android:layout_width">1dip</item>
<item name="android:layout_height">match_parent</item>
<item name="android:background">@android:color/white</item>
</style>
<style name="SettingsActionBar"
parent="DefaultActionBar">
<item name="android:icon">@drawable/ic_action_settings</item>
</style>
</resources>

View file

@ -1,19 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<style name="AppTheme"
<!--Activites Themes-->
<style name="EntriesTheme"
parent="android:Theme.Holo.Light">
<item name="android:actionBarStyle">@style/DefaultActionBar</item>
</style>
<item name="android:actionBarStyle">@style/EntriesActionBar</item>
</style>
<style name="LoginTheme"
parent="AppTheme">
<item name="android:actionBarStyle">@style/LoginActionBar</item>
</style>
<style name="SettingsTheme"
parent="AppTheme">
<item name="android:actionBarStyle">@style/SettingsActionBar</item>
<!--Action Bar styles-->
<style name="EntriesActionBar"
parent="android:Widget.Holo.Light.ActionBar.Solid" >
<item name="android:background">@color/header_background</item>
</style>
</resources>

View file

@ -3,9 +3,8 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/general_category">
<EditTextPreference
android:key="entries_limit_string"
android:numeric="integer"
<Preference
android:key="entries_limit"
android:title="@string/entries_limit"
android:summary="@string/entries_summary"
/>