From b5615d75917fbf055837db1b902f6d157402e661 Mon Sep 17 00:00:00 2001 From: Przemek Grondek <github@nerull7.info> Date: Wed, 1 Oct 2014 11:40:22 +0200 Subject: [PATCH] SQL queries Full support --- .../mysqlbrowser/DatabaseFragment.java | 6 + .../nerull7/mysqlbrowser/ListActivity.java | 2 +- .../mysqlbrowser/SQLEntriesFragment.java | 245 ++++++++++++++++++ .../nerull7/mysqlbrowser/SQLFragment.java | 24 +- .../info/nerull7/mysqlbrowser/Static.java | 3 +- .../db/AsyncDatabaseConnector.java | 35 ++- .../main/res/drawable-hdpi/ic_action_info.png | Bin 0 -> 696 bytes .../main/res/drawable-mdpi/ic_action_info.png | Bin 0 -> 469 bytes .../res/drawable-xhdpi/ic_action_info.png | Bin 0 -> 891 bytes .../res/drawable-xxhdpi/ic_action_info.png | Bin 0 -> 1577 bytes app/src/main/res/values/strings.xml | 1 + 11 files changed, 298 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/info/nerull7/mysqlbrowser/SQLEntriesFragment.java create mode 100644 app/src/main/res/drawable-hdpi/ic_action_info.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_info.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_info.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_info.png diff --git a/app/src/main/java/info/nerull7/mysqlbrowser/DatabaseFragment.java b/app/src/main/java/info/nerull7/mysqlbrowser/DatabaseFragment.java index c70f172..91a6ff4 100644 --- a/app/src/main/java/info/nerull7/mysqlbrowser/DatabaseFragment.java +++ b/app/src/main/java/info/nerull7/mysqlbrowser/DatabaseFragment.java @@ -31,6 +31,12 @@ public class DatabaseFragment extends Fragment implements AdapterView.OnItemClic private ProgressBar progressBar; private List<String> databases; + @Override + public void onResume() { + super.onResume(); + Static.asyncDatabaseConnector.setDatabaseInUse(null); + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ //Inflate the layout for this fragment diff --git a/app/src/main/java/info/nerull7/mysqlbrowser/ListActivity.java b/app/src/main/java/info/nerull7/mysqlbrowser/ListActivity.java index c88c75f..3eeb667 100644 --- a/app/src/main/java/info/nerull7/mysqlbrowser/ListActivity.java +++ b/app/src/main/java/info/nerull7/mysqlbrowser/ListActivity.java @@ -48,7 +48,7 @@ public class ListActivity extends Activity { Static.startSettings(this); return true; } else if (id == R.id.action_sql){ - Static.startSQL(this); + Static.startSQL(this, getIntent().getExtras().getString(Static.DATABASE_NAME_ARG)); } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/java/info/nerull7/mysqlbrowser/SQLEntriesFragment.java b/app/src/main/java/info/nerull7/mysqlbrowser/SQLEntriesFragment.java new file mode 100644 index 0000000..4c1af95 --- /dev/null +++ b/app/src/main/java/info/nerull7/mysqlbrowser/SQLEntriesFragment.java @@ -0,0 +1,245 @@ +package info.nerull7.mysqlbrowser; + +import android.app.AlertDialog; +import android.app.Fragment; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Typeface; +import android.os.Bundle; +import android.preference.PreferenceManager; +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; +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.AsyncDatabaseConnector; + +/** + * Created by nerull7 on 15.07.14. + * + * Fragment for showing elements + */ +public class SQLEntriesFragment extends Fragment implements AsyncDatabaseConnector.MatrixReturnListener, AsyncDatabaseConnector.ListReturnListener, AsyncDatabaseConnector.OnPostExecuteListener, AsyncDatabaseConnector.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; + } +} diff --git a/app/src/main/java/info/nerull7/mysqlbrowser/SQLFragment.java b/app/src/main/java/info/nerull7/mysqlbrowser/SQLFragment.java index 0ba7079..c67bc2e 100644 --- a/app/src/main/java/info/nerull7/mysqlbrowser/SQLFragment.java +++ b/app/src/main/java/info/nerull7/mysqlbrowser/SQLFragment.java @@ -2,6 +2,7 @@ package info.nerull7.mysqlbrowser; import android.app.Activity; import android.app.Fragment; +import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.util.Log; @@ -14,12 +15,16 @@ import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import info.nerull7.mysqlbrowser.db.AsyncDatabaseConnector; + /** * Created by nerull7 on 30.09.14. */ -public class SQLFragment extends Fragment{ +public class SQLFragment extends Fragment implements AsyncDatabaseConnector.OnPostExecuteListener { private EditText sqlEditText; private InputMethodManager inputMethodManager; + private SQLEntriesFragment sqlEntriesFragment; + private FragmentTransaction fragmentTransaction; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -66,7 +71,20 @@ public class SQLFragment extends Fragment{ String sqlQuery = String.valueOf(sqlEditText.getText()); Log.d("SQLQUERY", sqlQuery); - Static.asyncDatabaseConnector.setOnPostExecuteListener(null); - Static.asyncDatabaseConnector.executeSQL(null /*FIXME*/, sqlQuery); + fragmentTransaction = getFragmentManager().beginTransaction(); + sqlEntriesFragment = new SQLEntriesFragment(); + fragmentTransaction.replace(R.id.container, sqlEntriesFragment); + fragmentTransaction.commit(); + + Static.asyncDatabaseConnector.setStringReturnListener(sqlEntriesFragment); + Static.asyncDatabaseConnector.setListReturnListener(sqlEntriesFragment); + Static.asyncDatabaseConnector.setMatrixReturnListener(sqlEntriesFragment); + Static.asyncDatabaseConnector.setOnPostExecuteListener(this); + Static.asyncDatabaseConnector.executeSQL(getActivity().getIntent().getExtras().getString(Static.DATABASE_NAME_ARG), sqlQuery); + } + + @Override + public void onPostExecute() { + sqlEntriesFragment.onPostExecute(); } } diff --git a/app/src/main/java/info/nerull7/mysqlbrowser/Static.java b/app/src/main/java/info/nerull7/mysqlbrowser/Static.java index 01d7d35..ca0281e 100644 --- a/app/src/main/java/info/nerull7/mysqlbrowser/Static.java +++ b/app/src/main/java/info/nerull7/mysqlbrowser/Static.java @@ -52,8 +52,9 @@ public class Static { builder.show(); } - public static void startSQL(Context context) { + 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); } } diff --git a/app/src/main/java/info/nerull7/mysqlbrowser/db/AsyncDatabaseConnector.java b/app/src/main/java/info/nerull7/mysqlbrowser/db/AsyncDatabaseConnector.java index 42a8e04..0162ca8 100644 --- a/app/src/main/java/info/nerull7/mysqlbrowser/db/AsyncDatabaseConnector.java +++ b/app/src/main/java/info/nerull7/mysqlbrowser/db/AsyncDatabaseConnector.java @@ -360,20 +360,29 @@ public class AsyncDatabaseConnector { public void onFinished(String data, String error) { String []response = data.split("\n"); - List<String>headerList = null; - try { - headerList = parseListFromJSON(response[1]); - } catch (JSONException e) { e.printStackTrace(); } - if(listReturnListener!=null) { - listReturnListener.onListReturn(headerList); - } + 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); + 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); diff --git a/app/src/main/res/drawable-hdpi/ic_action_info.png b/app/src/main/res/drawable-hdpi/ic_action_info.png new file mode 100644 index 0000000000000000000000000000000000000000..75ecc1834177da3ec2c3baae4ede59d3bb423cbc GIT binary patch literal 696 zcmV;p0!RIcP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm0007iNkl<ZXhZE; zJt#&|82&!O;;(EhvKf>zkg}jClv!jo8Z8J5o6#yVD-?xAi9soYO%^u!U67yWse8Y! z>)w0rJ@=fi`^u@OudjRFpXZ$Sea~M$C%ol_`=9$KpqN2-fWB<aw5b^=frE_>8t_{O zQ~~9V<8SzV2JV0x;M&1wT4HGl)WCrbpbe-^=*$E9p8+SpV?x<NcU=ON(9jFC1Espg z9k~zuo&x*8OHy4r1X^Ka5U5USOws=d-?xGDBzlt&V4M#CT}cdR^gV*i4iGCp;u0u> z!cm}E!yz4!O9-t4?<(Oq1UT~JMReZvnIu+KGZBZtP!Yl=Y@iuVTT!#1BEW<lQB9-e z?;BBx9YuhpauU$3HjH0)1*RS5kxpZES_T43Y!rcE2zBaMbmDf_lZ14B4q!g%v||Wu z1__1{;0ikh=q^$$fzv($3n>V2v0DUwt=M4%`p~&YXQ&(*(*&sY0NC^U6hwg2%+XJ} zxAE$>LEs(+mYnb`*a{-hgs&4RM&G9B3Y1@Y4FnNj=rDw`*mmL6p^Cs5I<#cbd-!w# ztf>gF_SYLA;NOhtmQb%NxA?;~Au<P8{&<>7)95_QCQo8)Jeg5%S`s|fQEw;#=EOWu zk;Z$-+NeTw=@pm(3TJG85{oB5mZn0;<Vx%YgffKK(L@s43ZYm@Y@&?XA`q*Lc4HR$ zGn&M)7BUlC30pG|Yb%k}%^WYnxTXHFK>o??G{ax~frcbRA1O&d{GpyCL|?18OM&Q% zEs_v_wMY`8FL&Kg5`Dey-5QB~;P8?V{lw%YBKDEbzuOl3%&Iyzh<WH%5wZ4N^+IFK euqnmj348<P?Wr+h%~m%60000<MNUMnLSTaSOF9z( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_info.png b/app/src/main/res/drawable-mdpi/ic_action_info.png new file mode 100644 index 0000000000000000000000000000000000000000..944ab3d239f33c5ab2439a170e146d29744b8c10 GIT binary patch literal 469 zcmV;`0V@89P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004;Nkl<ZSVzT| zKP*H+5XSFZiCl9vi718SBG*#Wi->46dKaBaC)8JIL`3w|v?3CslnAv(P!ivF_9bgG z>&@<SnN7azyLYoQzn%U2>NVq1H;!M+1sDZ*3mSGE_(1&vy`^?21%LrN(3A@<#UjK# zbmf3bc{Bj*<s#IEhDtsD7<@rD&>6(+L`xaKBwDUOBg(*`**jhwLl3d`e*w&((K6J? z3|=(*#KQ@6EBT25u;=Ul5Zs42kTM|waLhL=q&=1}4#$2tCnSI+7|klu{tTN-XE%p> zOwr~VHmAN_2*9P*g*3DM4t7V**(&O31prsa9>nF^FCoAJ-pwl<(If|e?Jl767{C_( zU={{h*!x`xfZOZ#AR~LecktZbw*4WP!0(L&fLGW)Is0+c&4ji+*gl2;+~e00oaD{{ zhB$<HX8g*4IY8<VRLOui1gVp-3V=8XIV35|Fc%=Y3<+Sq5t(nr%!27*L;&;Sm=LBH zl43J7y^<9WrkBzJ!t`41pG{^TCei_E@@bZEQtM62zKryqGA+LW6Sia_0)jgh00000 LNkvXXu0mjf`4r7( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_info.png b/app/src/main/res/drawable-xhdpi/ic_action_info.png new file mode 100644 index 0000000000000000000000000000000000000000..6e10fde30dd53259f71fc77743b17ffa6e375b8a GIT binary patch literal 891 zcmV->1BCpEP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0009*Nkl<ZcwX(B zOQ=mz7{~7o1CJ<=n+$Xdr5I7j9e9i|p%h9H0|q803=9km44B-B0fi`qQcN)N7!ZmP z1EFpPl2?((0Oj|uyLH;mK6|Zo*4let-`Vx=w$J^(_4w`e{Px=Yea5eT<Mr?B0qC^= z;{>Yg0#jf;8x5eTXfhf<%KsOCzo9Sa9eRttR`G070vJaH7NA9F9-8S{p%2)<LeJ0( z^xM<l$vg!BJ=tYwIhyWNigKe*m^?&}Mq5g`hoePI0IK*ZG=wHN=I?9v6Nh`~ZY&V7 z04%0J8__i18U@;a#_t+>8tDJmty=&SNofmGKd<A`_;4Bh2+h130JF$+JDL-kc_hC# zq;mni4@oZ+z+5uhjV6U;n!x8fX`Vr^ebWvBpvvz;8uXfUX&rIa7lJPUHT!)Hdh+=P zpq6mLr#tun(15qM0e!x#)oDyPiJS&T9{@W^w64*<tkU`aYj!y2;^YcI^ZX8%1RG>? zp0bp#6I=jju-lJfE^<al?_&<u4DJUb0@Pw@7-?`Uyj%cmz<YJXf+?ws=t(ZkCERa| zoX;K7yWR}|J^e!{_S(KG0NOho?bHg&TEH5d*GGOTRki@-bpzclszWCL+Rq<Av9`3W zWvHqJC{JyrkE6EngiZh!;-uwnimOThD*tKpyj?{)0oaU#f*SwBrC`bxUjPSj@C{=% z6_&zl$9w=NfO)v7wFxZO5&ZrMv=()N`55mB%&4hurzqIVeBp`!ti*6rQ)?1fuB-Un zcLlHx!?l4Kxwt*RXe4Ji$o&cz=RliV_}z2`ka`BFdKy%{+s*_<U0^E?O9M%}xYYsR zF$KHi+5*f2Fy94I4}x`c0k1(Y^)y%q0Iz8<^+Ko)0A35B)Jx$y0C+8hHCv?I3{?%l zdov^eDQAMJ0R(M_%?Cuxhs4wkOb0~;z<gL-5KO-q$y$NwS7U-;`sHZ0g*N?qToBA3 zkPrmZM`W_DVET|$D+II0<T41R4@zbbOdpkPjWC-%EZqvh^l|w-2$LU7<X^fdo}l2W zx<@yk%;>D2-s+B-PiFEUvU_tMO%;J?)bC}-<Qi4j6ou&lNI`WhrD?te`~g~!#6e&I RlA-_r002ovPDHLkV1ke}kFx*( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_info.png b/app/src/main/res/drawable-xxhdpi/ic_action_info.png new file mode 100644 index 0000000000000000000000000000000000000000..6835e8f56a38d6298b74ec0316501d58e9c8af15 GIT binary patch literal 1577 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 bD4V|rgY8#vZc9{$00000NkvXXu0mjfjmpNB literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4c83cb..e431c16 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,5 +58,6 @@ <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>