From e75b8dc90fe8a4defad4cca25c74fa374ec1f89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Thu, 11 Aug 2016 19:28:05 -0300 Subject: [PATCH 1/9] Updated Build Tools to latest version --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 13249cb..b81cee2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,7 +21,7 @@ repositories { android { compileSdkVersion 23 - buildToolsVersion "23.0.2" + buildToolsVersion "23.0.3" defaultConfig { applicationId "com.bixlabs.smssolidario" From 0c7eb3bce920e5042513bf048abe0d4b17df7a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Fri, 12 Aug 2016 16:56:49 -0300 Subject: [PATCH 2/9] Reduced organizations to a single string array --- .../activity/SettingsActivity.java | 37 +++++++++++++------ app/src/main/res/values/organizations.xml | 26 ++++--------- app/src/main/res/xml/preference_settings.xml | 2 - 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java index ff7ae78..5ad673f 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java @@ -6,8 +6,10 @@ import android.app.TimePickerDialog; import android.content.Context; import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Configuration; import android.os.Build; +import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; @@ -16,7 +18,6 @@ import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.support.annotation.LayoutRes; -import android.os.Bundle; import android.support.v7.app.AppCompatDelegate; import android.support.v7.widget.Toolbar; import android.view.MenuInflater; @@ -27,8 +28,19 @@ import android.widget.TimePicker; import android.widget.Toast; +import com.bixlabs.smssolidario.R; +import com.bixlabs.smssolidario.classes.Scheduler; + +import net.danlew.android.joda.JodaTimeAndroid; + +import org.joda.time.DateTime; + +import java.util.ArrayList; +import java.util.List; + import static com.bixlabs.smssolidario.classes.Constants.DEFAULT_HOUR; import static com.bixlabs.smssolidario.classes.Constants.DEFAULT_MINUTES; +import static com.bixlabs.smssolidario.classes.Constants.ORGANIZATION_INFO; import static com.bixlabs.smssolidario.classes.Constants.PREF_ACTIVE; import static com.bixlabs.smssolidario.classes.Constants.PREF_CONFIGURED; import static com.bixlabs.smssolidario.classes.Constants.PREF_DAY; @@ -37,16 +49,6 @@ import static com.bixlabs.smssolidario.classes.Constants.PREF_MINUTE; import static com.bixlabs.smssolidario.classes.Constants.PREF_MONTH; import static com.bixlabs.smssolidario.classes.Constants.PREF_YEAR; -import static com.bixlabs.smssolidario.classes.Constants.ORGANIZATION_INFO; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; - - -import net.danlew.android.joda.JodaTimeAndroid; - -import org.joda.time.DateTime; - -import com.bixlabs.smssolidario.R; -import com.bixlabs.smssolidario.classes.Scheduler; public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener, android.support.v7.widget.Toolbar.OnMenuItemClickListener{ @@ -113,6 +115,19 @@ public boolean onPreferenceClick(Preference preference) { phonePreference = findPreference(NUMBER_KEY); hideMessageAndPhonePreferences(); + // Load the organizations and add them to the preferences + ListPreference organizations = (ListPreference) findPreference(ORGANIZATION_KEY); + String[] orgs = getResources().getStringArray(R.array.organizations); + List entries = new ArrayList<>(); + List values = new ArrayList<>(); + for (String org : orgs) { + String[] splittedOrg = org.split("\\|", 2); + values.add(splittedOrg[0]); + entries.add(splittedOrg[1]); + } + organizations.setEntries(entries.toArray(new String[entries.size()])); + organizations.setEntryValues(values.toArray(new String[values.size()])); + JodaTimeAndroid.init(this); getPreferencesFromUser(); diff --git a/app/src/main/res/values/organizations.xml b/app/src/main/res/values/organizations.xml index b347d40..4b863fd 100644 --- a/app/src/main/res/values/organizations.xml +++ b/app/src/main/res/values/organizations.xml @@ -1,22 +1,12 @@ - Animales sin hogar - Fundacion Alvarez Caldeiro Barcia - Unicef - Orquestas Juveniles - Peluffo Giguens - Aldeas Infantiles - Personalizada + ASH|Animales sin hogar + FACB|Funcacion Alvarez Caldeiro Barcia + UNCF|Unicef + OJ|Orquestas Juveniles + PG|Peluffo Giguens + AI|Aldeas Infantiles + Personalizada|Personalizada - - ASH - FACB - UNCF - OJ - PG - AI - Personalizada - - - \ No newline at end of file + diff --git a/app/src/main/res/xml/preference_settings.xml b/app/src/main/res/xml/preference_settings.xml index b9c4d2a..f939ecb 100644 --- a/app/src/main/res/xml/preference_settings.xml +++ b/app/src/main/res/xml/preference_settings.xml @@ -8,8 +8,6 @@ From 3d39ecdbe4784f628782bbef4a496c707f08cc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Fri, 12 Aug 2016 16:57:56 -0300 Subject: [PATCH 3/9] Added title to the DatePicker dialog --- .../java/com/bixlabs/smssolidario/activity/SettingsActivity.java | 1 + app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java index 5ad673f..f22348f 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java @@ -379,6 +379,7 @@ protected Dialog onCreateDialog(int id) { if (id == DATE_DIALOG_ID) { DatePickerDialog datePickerDialog = new DatePickerDialog(this, dPickerListener, expirationYear, expirationMonth, expirationDay); datePickerDialog.getDatePicker().setMinDate(DateTime.now().getMillis() - 1000); + datePickerDialog.setTitle(R.string.dialog_datepicker_title); return datePickerDialog; } else if (id == TIME_DIALOG_ID) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4903d0..6fe0356 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,4 +49,5 @@ Ser donante validado :) ¡Gracias por ser parte! Próximo envío automático: + Selecciona una fecha From d9cd529a3fbc71c19ef3492b48fe237cb1f96be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Fri, 12 Aug 2016 16:59:35 -0300 Subject: [PATCH 4/9] Fixed the tools:context of splash, settings and main activitiy layouts --- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/activity_settings.xml | 2 +- app/src/main/res/layout/activity_splash_screen.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 1cd8daa..12c57e6 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -8,7 +8,7 @@ android:background="@color/white" android:orientation="vertical" android:weightSum="1" - tools:context=".MainActivity" > + tools:context=".activity.MainActivity" > diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 021df23..034c3bb 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".SettingsActivity" > + tools:context=".activity.SettingsActivity" > diff --git a/app/src/main/res/layout/activity_splash_screen.xml b/app/src/main/res/layout/activity_splash_screen.xml index dafb2ed..289a7e0 100644 --- a/app/src/main/res/layout/activity_splash_screen.xml +++ b/app/src/main/res/layout/activity_splash_screen.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff6464" - tools:context=".SplashScreenActivity" > + tools:context=".activity.SplashScreenActivity" > Date: Fri, 12 Aug 2016 21:01:14 -0300 Subject: [PATCH 5/9] Added donations historical --- app/src/main/AndroidManifest.xml | 5 + .../activity/HistoryActivity.java | 69 ++++++++++ .../smssolidario/activity/MainActivity.java | 30 +++-- .../adapters/HistoryCursorAdapter.java | 62 +++++++++ .../smssolidario/classes/AlertReceiver.java | 20 ++- .../classes/SimpleCursorLoader.java | 126 ++++++++++++++++++ .../bixlabs/smssolidario/classes/Utils.java | 50 +++++++ .../persistency/DatabaseHelper.java | 63 +++++++++ .../persistency/HistoryDataSource.java | 32 +++++ .../persistency/HistoryLoader.java | 31 +++++ app/src/main/res/layout/activity_history.xml | 20 +++ app/src/main/res/layout/item_history.xml | 29 ++++ app/src/main/res/menu/activity_main.xml | 9 +- app/src/main/res/values/strings.xml | 1 + 14 files changed, 527 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java create mode 100644 app/src/main/java/com/bixlabs/smssolidario/adapters/HistoryCursorAdapter.java create mode 100644 app/src/main/java/com/bixlabs/smssolidario/classes/SimpleCursorLoader.java create mode 100644 app/src/main/java/com/bixlabs/smssolidario/classes/Utils.java create mode 100644 app/src/main/java/com/bixlabs/smssolidario/persistency/DatabaseHelper.java create mode 100644 app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryDataSource.java create mode 100644 app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryLoader.java create mode 100644 app/src/main/res/layout/activity_history.xml create mode 100644 app/src/main/res/layout/item_history.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a570b18..2fa4044 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,6 +36,11 @@ android:label="@string/title_activity_settings" android:screenOrientation="portrait" > + + diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java new file mode 100644 index 0000000..06b484c --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java @@ -0,0 +1,69 @@ +package com.bixlabs.smssolidario.activity; + +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.widget.ListView; + +import com.bixlabs.smssolidario.R; +import com.bixlabs.smssolidario.adapters.HistoryCursorAdapter; +import com.bixlabs.smssolidario.persistency.DatabaseHelper; +import com.bixlabs.smssolidario.persistency.HistoryLoader; + +public class HistoryActivity extends AppCompatActivity + implements LoaderManager.LoaderCallbacks { + + private ListView historyListview; + private HistoryCursorAdapter historyAdapter; + private DatabaseHelper databaseHelper; + + @SuppressWarnings("ConstantConditions") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_history); + + // Set the actionbar title and home button + final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main); + toolbar.setTitle(R.string.donations_history); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + historyListview = (ListView) this.findViewById(R.id.list_history); + historyAdapter = new HistoryCursorAdapter(this, null); + historyListview.setAdapter(historyAdapter); + + databaseHelper = new DatabaseHelper(getApplicationContext()); + + // Initialize the loader + getSupportLoaderManager().initLoader(0, null, this); + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + if (menuItem.getItemId() == android.R.id.home) { + finish(); + } + return super.onOptionsItemSelected(menuItem); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new HistoryLoader(getApplicationContext(), databaseHelper); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + historyAdapter.swapCursor(data); + } + + @Override + public void onLoaderReset(Loader loader) { + historyAdapter.swapCursor(null); + } + +} diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/MainActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/MainActivity.java index 2a4292d..0a14387 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/activity/MainActivity.java +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/MainActivity.java @@ -2,14 +2,14 @@ import android.Manifest; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; -import android.content.Intent; -import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -24,6 +24,9 @@ import android.widget.ViewFlipper; import com.awesomego.widget.ToggleButton; +import com.bixlabs.smssolidario.BuildConfig; +import com.bixlabs.smssolidario.R; +import com.bixlabs.smssolidario.SmsAnalyticsApplication; import com.crashlytics.android.Crashlytics; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; @@ -35,9 +38,6 @@ import org.joda.time.DateTime; import io.fabric.sdk.android.Fabric; -import com.bixlabs.smssolidario.BuildConfig; -import com.bixlabs.smssolidario.R; -import com.bixlabs.smssolidario.SmsAnalyticsApplication; import static com.bixlabs.smssolidario.classes.Constants.COMPANY_NAME; import static com.bixlabs.smssolidario.classes.Constants.DEFAULT_ACTIVE; @@ -123,14 +123,18 @@ public boolean onOptionsItemSelected(MenuItem item) { // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - checkPermissions(); - } - - if (id == R.id.action_about) { - showAbout(); - } + switch (id) { + case R.id.action_settings: + checkPermissions(); + break; + case R.id.action_about: + showAbout(); + break; + case R.id.action_history: + Intent historyIntent = new Intent(this, HistoryActivity.class); + startActivity(historyIntent); + break; + } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/java/com/bixlabs/smssolidario/adapters/HistoryCursorAdapter.java b/app/src/main/java/com/bixlabs/smssolidario/adapters/HistoryCursorAdapter.java new file mode 100644 index 0000000..c88ea97 --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/adapters/HistoryCursorAdapter.java @@ -0,0 +1,62 @@ +package com.bixlabs.smssolidario.adapters; + +import android.content.Context; +import android.database.Cursor; +import android.support.v4.widget.CursorAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.bixlabs.smssolidario.R; +import com.bixlabs.smssolidario.persistency.DatabaseHelper; + +/** + * History ListView Adapter + */ +public class HistoryCursorAdapter extends CursorAdapter { + private int COL_ORGANIZATION = 0; + private int COL_DATE = 0; + + public HistoryCursorAdapter(Context context, Cursor c) { + super(context, c, 0); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View view = LayoutInflater.from(context).inflate(R.layout.item_history, parent, false); + ViewHolder holder = new ViewHolder(view); + view.setTag(holder); + return view; + } + + @Override + public Cursor swapCursor(Cursor c) { + if (c != null) { + COL_ORGANIZATION = c.getColumnIndex(DatabaseHelper.COLUMN_HISTORY_ORG); + COL_DATE = c.getColumnIndex(DatabaseHelper.COLUMN_HISTORY_DATE); + } + return super.swapCursor(c); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ViewHolder holder = (ViewHolder) view.getTag(); + + String organizationName = cursor.getString(COL_ORGANIZATION); + String timestamp = cursor.getString(COL_DATE); + + holder.organization.setText(organizationName); + holder.date.setText(timestamp); + } + + private static class ViewHolder { + final TextView organization; + final TextView date; + + ViewHolder(View view) { + organization = (TextView) view.findViewById(R.id.item_history_organization); + date = (TextView) view.findViewById(R.id.item_history_date); + } + } +} diff --git a/app/src/main/java/com/bixlabs/smssolidario/classes/AlertReceiver.java b/app/src/main/java/com/bixlabs/smssolidario/classes/AlertReceiver.java index 4115f24..380f5d2 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/classes/AlertReceiver.java +++ b/app/src/main/java/com/bixlabs/smssolidario/classes/AlertReceiver.java @@ -8,17 +8,17 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; -import android.support.v4.app.TaskStackBuilder; import android.telephony.SmsManager; import android.widget.Toast; -import net.danlew.android.joda.JodaTimeAndroid; - -import org.joda.time.DateTime; - import com.bixlabs.smssolidario.R; import com.bixlabs.smssolidario.controllers.AlarmController; import com.bixlabs.smssolidario.controllers.MessageController; +import com.bixlabs.smssolidario.persistency.HistoryDataSource; + +import net.danlew.android.joda.JodaTimeAndroid; + +import org.joda.time.DateTime; import static com.bixlabs.smssolidario.classes.Constants.DEFAULT_ACTIVE; import static com.bixlabs.smssolidario.classes.Constants.DEFAULT_ALLOWED_PREMIUM; @@ -48,6 +48,7 @@ public class AlertReceiver extends BroadcastReceiver { String phoneNumber, textMessage; SharedPreferences.Editor editor; MessageController msgController; + HistoryDataSource historyDataSource; @Override public void onReceive(Context context, Intent intent) { @@ -65,6 +66,8 @@ public void onReceive(Context context, Intent intent) { // This is the case when the message is sent case Activity.RESULT_OK: settings = PreferenceManager.getDefaultSharedPreferences(context); + phoneNumber = settings.getString(PREF_PHONE, DEFAULT_PHONE); + boolean allowedPremium = settings.getBoolean(PREF_ALLOWED_PREMIUM, DEFAULT_ALLOWED_PREMIUM); // If the messages were sent successfully then we don't // Need to show again the validation dialog @@ -84,6 +87,12 @@ public void onReceive(Context context, Intent intent) { editor.putInt(PREF_SMS_TO_SEND, messagesToSend); editor.putBoolean(PREF_ERROR, false); editor.apply(); + + // Add the newly sent message to the History DB + historyDataSource = new HistoryDataSource(context); + historyDataSource.addToHistory(Utils.getOrganizationNameFromNumber(phoneNumber, + context.getResources().getStringArray(R.array.organizations))); + // If the day changes we stop sending messages to prevent spending wrong credit DateTime actualTime = DateTime.now(); DateTime actualExpirationDate = DateTime.now(); @@ -91,7 +100,6 @@ public void onReceive(Context context, Intent intent) { boolean stopForChangeOfDay = actualTime.getDayOfMonth() != expirationDay; boolean stopForMax = messagesToSend == 0; if (!stopForMax && !stopForChangeOfDay) { - phoneNumber = settings.getString(PREF_PHONE, DEFAULT_PHONE); textMessage = settings.getString(PREF_MESSAGE, DEFAULT_MESSAGE); msgController = MessageController.getInstance(); msgController.sendMessage(phoneNumber, textMessage, context); diff --git a/app/src/main/java/com/bixlabs/smssolidario/classes/SimpleCursorLoader.java b/app/src/main/java/com/bixlabs/smssolidario/classes/SimpleCursorLoader.java new file mode 100644 index 0000000..3068fa6 --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/classes/SimpleCursorLoader.java @@ -0,0 +1,126 @@ +package com.bixlabs.smssolidario.classes; + +import android.content.Context; +import android.database.Cursor; +import android.support.v4.content.AsyncTaskLoader; +import android.util.Log; + +/** + * CursorLoader that doesn't require of a ContentProvider. + * This was based on the CursorLoader class. + */ +public abstract class SimpleCursorLoader extends AsyncTaskLoader { + private Cursor mCursor; + + public SimpleCursorLoader(Context context) { + // Loaders may be used across multiple Activities (assuming they aren't + // bound to the LoaderManager), so NEVER hold a reference to the context + // directly. Doing so will cause you to leak an entire Activity's context. + // The superclass constructor will store a reference to the Application + // Context instead, and can be retrieved with a call to getContext(). + super(context); + } + + /* Runs on a worker thread */ + @Override + public abstract Cursor loadInBackground(); + + /* Runs on the UI thread */ + /** + * Called when there is new data to deliver to the client. The superclass will + * deliver it to the registered listener (i.e. the LoaderManager), which will + * forward the results to the client through a call to onLoadFinished. + */ + @Override + public void deliverResult(Cursor cursor) { + if (isReset()) { + // The loader has been reset; ignore the result and invalidate the data. + // This can happen when the Loader is reset while an asynchronous query + // is working in the background. That is, when the background thread + // finishes its work and attempts to deliver the results to the client, + // it will see here that the Loader has been reset and discard any + // resources associated with the new data as necessary + releaseResource(cursor); + return; + } + + // Hold a reference to the old data so it doesn't get garbage collected. + // We must protect it until the new data has been delivered. + Cursor oldCursor = mCursor; + mCursor = cursor; + + if (isStarted()) { + // If the loader is in a started state, have the superclass deliver the + // result to the client. + super.deliverResult(cursor); + } + + // Invalidate the old data as we don't need it anymore + if (oldCursor != null && oldCursor != cursor) { + releaseResource(oldCursor); + } + } + + /** + * Starts an asynchronous load of the data. When the result is ready the callbacks + * will be called on the UI thread. If a previous load has been completed and is still valid + * the result may be passed to the callbacks immediately. + *

+ * Must be called from the UI thread + */ + @Override + protected void onStartLoading() { + if (mCursor != null) { + deliverResult(mCursor); + } + + // If the method onContentchanged() of the Loader is called, it will cause + // the next call to takeContentChanged() to return true. If this is ever + // the case (or if the current data is null), we force a new load. + if (takeContentChanged() || mCursor == null) { + forceLoad(); + } + } + + /** + * Must be called from the UI thread + */ + @Override + protected void onStopLoading() { + // The Loader has been put in a stopped state, so we should attempt to + // cancel the current load (if there is one). + cancelLoad(); + } + + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader is stopped + onStopLoading(); + + // At this point we can release the resources + releaseResource(mCursor); + mCursor = null; + } + + @Override + public void onCanceled(Cursor cursor) { + // Attempt to cancel the current asynchronous load. + super.onCanceled(cursor); + + // The load has been canceled, so we should release the resources + releaseResource(cursor); + } + + + /** + * Helper method to take care of releasing resources. + */ + private void releaseResource(Cursor cursor) { + if (cursor != null && cursor.isClosed()) { + cursor.close(); + Log.d(SimpleCursorLoader.class.getSimpleName(), "Cursor has been closed"); + } + } +} diff --git a/app/src/main/java/com/bixlabs/smssolidario/classes/Utils.java b/app/src/main/java/com/bixlabs/smssolidario/classes/Utils.java new file mode 100644 index 0000000..b1f9259 --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/classes/Utils.java @@ -0,0 +1,50 @@ +package com.bixlabs.smssolidario.classes; + +import java.sql.Date; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.Map; + +/** + * Utility methods + */ +public class Utils { + + /** + * Get an organization name based on its phone number + * @param phoneNumber The phone number + * @param organizations The organizations list + * @return The organization name as String + */ + public static String getOrganizationNameFromNumber(String phoneNumber, String[] organizations) { + String organizationName = null; + + for (Map.Entry organization : Constants.ORGANIZATION_INFO.entrySet() ) { + if (phoneNumber.equals(organization.getValue()[1])) { + for(String orgs : organizations) { + String[] splittedOrg = orgs.split("\\|", 2); + if (splittedOrg[0].equals(organization.getKey())) { + organizationName = splittedOrg[1]; + break; + } + } + break; + } + } + + return organizationName; + } + + /** + * Private helper method to convert timestamps to formatted dates + * @param dateInMillis The timestamp + * @return The formatted date as String + */ + public static String formatDate(Long dateInMillis) { + DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault()); + Date netDate = (new Date(dateInMillis)); + return sdf.format(netDate); + } + +} diff --git a/app/src/main/java/com/bixlabs/smssolidario/persistency/DatabaseHelper.java b/app/src/main/java/com/bixlabs/smssolidario/persistency/DatabaseHelper.java new file mode 100644 index 0000000..63b5953 --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/persistency/DatabaseHelper.java @@ -0,0 +1,63 @@ +package com.bixlabs.smssolidario.persistency; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + + +/** + * Database Helper class + */ +public class DatabaseHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "sms_solidario.db"; + private static final int DATABASE_VERSION = 1; + + // Tables + public static final String TABLE_HISTORY = "history"; + + // Columns + public static final String COLUMN_HISTORY_ID = "_id"; + public static final String COLUMN_HISTORY_ORG = "organization"; + public static final String COLUMN_HISTORY_DATE = "date"; + + /* + Table History: + ------------------------------------------ + | _id | organization | date + ------------------------------------------ + | 1 | Animales sin hogar | El 12/08/2016 a las 20:30 hrs. + | 2 | Aldeas Infantiles | El 12/09/2016 a las 20:30 hrs. + ------------------------------------------ + */ + private static final String TABLE_HISTORY_CREATE = + TABLE_HISTORY + "( " + + COLUMN_HISTORY_ID + " integer primary key autoincrement, " + + COLUMN_HISTORY_ORG + " text not null, " + + COLUMN_HISTORY_DATE + " text not null" + + ");"; + + private static final String DATABASE_CREATE = "create table " + TABLE_HISTORY_CREATE; + + public DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(DATABASE_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(DatabaseHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + + newVersion + ", which will destroy all old data"); + + // Drop table if exists and re-create it + db.execSQL("DROP TABLE IF EXISTS " + TABLE_HISTORY); + + onCreate(db); + } + +} diff --git a/app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryDataSource.java b/app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryDataSource.java new file mode 100644 index 0000000..9a078e5 --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryDataSource.java @@ -0,0 +1,32 @@ +package com.bixlabs.smssolidario.persistency; + +import android.content.ContentValues; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; + +import com.bixlabs.smssolidario.classes.Utils; + +/** + * Donations History DAO + */ +public class HistoryDataSource { + private DatabaseHelper databaseHelper; + + public HistoryDataSource(Context ctx) { + databaseHelper = new DatabaseHelper(ctx); + } + + /** + * Adds a new entry to the History table + * @param organizationName The name of the organization which we donated + */ + public void addToHistory(String organizationName) { + SQLiteDatabase database = databaseHelper.getWritableDatabase(); + ContentValues values = new ContentValues(); + values.put(DatabaseHelper.COLUMN_HISTORY_ORG, organizationName); + values.put(DatabaseHelper.COLUMN_HISTORY_DATE, Utils.formatDate(System.currentTimeMillis())); + database.insert(DatabaseHelper.TABLE_HISTORY, null, values); + database.close(); + } + +} diff --git a/app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryLoader.java b/app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryLoader.java new file mode 100644 index 0000000..31b3d1c --- /dev/null +++ b/app/src/main/java/com/bixlabs/smssolidario/persistency/HistoryLoader.java @@ -0,0 +1,31 @@ +package com.bixlabs.smssolidario.persistency; + +import android.content.Context; +import android.database.Cursor; + +import com.bixlabs.smssolidario.classes.SimpleCursorLoader; + +public final class HistoryLoader extends SimpleCursorLoader { + private DatabaseHelper mDatabaseHelper; + private String[] allColumns = { DatabaseHelper.COLUMN_HISTORY_ID, + DatabaseHelper.COLUMN_HISTORY_ORG, DatabaseHelper.COLUMN_HISTORY_DATE}; + + public HistoryLoader(Context context, DatabaseHelper helper) { + super(context); + this.mDatabaseHelper = helper; + } + + @Override + public Cursor loadInBackground() { + return mDatabaseHelper.getReadableDatabase() + .query(DatabaseHelper.TABLE_HISTORY, allColumns, null, null, null, null, null); + } + + @Override + public void deliverResult(Cursor cursor) { + super.deliverResult(cursor); + + // Close the underlying DB connection and release it. + mDatabaseHelper.close(); + } +} diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml new file mode 100644 index 0000000..ac3062a --- /dev/null +++ b/app/src/main/res/layout/activity_history.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/item_history.xml b/app/src/main/res/layout/item_history.xml new file mode 100644 index 0000000..7cb221c --- /dev/null +++ b/app/src/main/res/layout/item_history.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/app/src/main/res/menu/activity_main.xml b/app/src/main/res/menu/activity_main.xml index 8e256fc..f808952 100644 --- a/app/src/main/res/menu/activity_main.xml +++ b/app/src/main/res/menu/activity_main.xml @@ -7,9 +7,16 @@ android:title="@string/action_settings" android:orderInCategory="100" app:showAsAction="never"/> + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6fe0356..6e7e4f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,5 +49,6 @@ Ser donante validado :) ¡Gracias por ser parte! Próximo envío automático: + Historial de donaciones Selecciona una fecha From 750b7633086e8a6849771155d4dfe78990259089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Fri, 12 Aug 2016 21:03:57 -0300 Subject: [PATCH 6/9] Added title to the TimePicker dialog --- .../com/bixlabs/smssolidario/activity/SettingsActivity.java | 4 +++- app/src/main/res/values/strings.xml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java index f22348f..64be861 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/SettingsActivity.java @@ -383,7 +383,9 @@ protected Dialog onCreateDialog(int id) { return datePickerDialog; } else if (id == TIME_DIALOG_ID) { - return new TimePickerDialog(this, timePickerListener, expirationHour, expirationMinute, true); + TimePickerDialog timePickerDialog = new TimePickerDialog(this, timePickerListener, expirationHour, expirationMinute, true); + timePickerDialog.setTitle(R.string.dialog_timepicker_title); + return timePickerDialog; } return null; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6e7e4f3..86152a1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,4 +51,5 @@ Próximo envío automático: Historial de donaciones Selecciona una fecha + Selecciona una hora From 284833b1e216b419b4590787d500338824a870b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Sat, 13 Aug 2016 01:40:44 -0300 Subject: [PATCH 7/9] Added empty history layout --- .../activity/HistoryActivity.java | 10 ++++++- app/src/main/res/layout/activity_history.xml | 30 ++++++++++++++++--- app/src/main/res/values/strings.xml | 1 + 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java index 06b484c..98c0922 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java @@ -8,6 +8,7 @@ import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.widget.ListView; +import android.widget.ViewFlipper; import com.bixlabs.smssolidario.R; import com.bixlabs.smssolidario.adapters.HistoryCursorAdapter; @@ -17,6 +18,7 @@ public class HistoryActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { + private ViewFlipper viewFlipper; private ListView historyListview; private HistoryCursorAdapter historyAdapter; private DatabaseHelper databaseHelper; @@ -33,6 +35,7 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + viewFlipper = (ViewFlipper) this.findViewById(R.id.view_flipper_history); historyListview = (ListView) this.findViewById(R.id.list_history); historyAdapter = new HistoryCursorAdapter(this, null); historyListview.setAdapter(historyAdapter); @@ -58,7 +61,12 @@ public Loader onCreateLoader(int id, Bundle args) { @Override public void onLoadFinished(Loader loader, Cursor data) { - historyAdapter.swapCursor(data); + if (data.getCount() == 0) { + viewFlipper.setDisplayedChild(1); + } else { + viewFlipper.setDisplayedChild(0); + historyAdapter.swapCursor(data); + } } @Override diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml index ac3062a..5df1356 100644 --- a/app/src/main/res/layout/activity_history.xml +++ b/app/src/main/res/layout/activity_history.xml @@ -12,9 +12,31 @@ - + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86152a1..05b44ac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,4 +52,5 @@ Historial de donaciones Selecciona una fecha Selecciona una hora + Aún no has colaborado.\n¿Qué esperas para hacerlo? From 30ef50d1a74a63af43c7683fa205382348399cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Sat, 13 Aug 2016 01:49:41 -0300 Subject: [PATCH 8/9] Extracted all preferences hardcoded messages into strings --- app/src/main/res/values/strings.xml | 10 ++++++++++ app/src/main/res/xml/preference_settings.xml | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 05b44ac..9d81bf8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,4 +53,14 @@ Selecciona una fecha Selecciona una hora Aún no has colaborado.\n¿Qué esperas para hacerlo? + Organización que recibirá la donación + Nuevo número + Mensaje + Ingrese texto + Cantidad máxima de SMS + Seleccionar fecha + Hora de envío + Notificar al enviar + Selecciona una ONG + Ingresa un número de teléfono diff --git a/app/src/main/res/xml/preference_settings.xml b/app/src/main/res/xml/preference_settings.xml index f939ecb..6c3d444 100644 --- a/app/src/main/res/xml/preference_settings.xml +++ b/app/src/main/res/xml/preference_settings.xml @@ -8,40 +8,40 @@ + android:summary="@string/preferences_organization" + android:title="@string/preferences_organization_title" /> + android:title="@string/preferences_new_number_title" /> + android:title="@string/preferences_message" /> + android:title="@string/preferences_date" /> + android:title="@string/preferences_time" /> + android:title="@string/preferences_notify" /> From 9e5e2209d73c097c0d64be2632d1c5339b8a5b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Radzinski?= Date: Sun, 14 Aug 2016 17:10:35 -0300 Subject: [PATCH 9/9] Added a ProgressDialog to HistoryActivity --- .../activity/HistoryActivity.java | 46 +++++++++++++++---- app/src/main/res/values/strings.xml | 2 + 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java b/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java index 98c0922..32234a1 100644 --- a/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java +++ b/app/src/main/java/com/bixlabs/smssolidario/activity/HistoryActivity.java @@ -1,12 +1,16 @@ package com.bixlabs.smssolidario.activity; +import android.app.ProgressDialog; import android.database.Cursor; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.MenuItem; +import android.view.View; import android.widget.ListView; import android.widget.ViewFlipper; @@ -22,6 +26,23 @@ public class HistoryActivity extends AppCompatActivity private ListView historyListview; private HistoryCursorAdapter historyAdapter; private DatabaseHelper databaseHelper; + private ProgressDialog progressDialog; + + // Dismiss the Progress Dialog and make the ViewFlipper visible + // inside a Handler (which runs on the UI thread). + private final Handler progressDialogHandler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + if (historyAdapter.getCount() == 0) { + viewFlipper.setDisplayedChild(1); + } else { + viewFlipper.setDisplayedChild(0); + } + viewFlipper.setVisibility(View.VISIBLE); + progressDialog.dismiss(); + return true; + } + }); @SuppressWarnings("ConstantConditions") @Override @@ -35,6 +56,9 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + progressDialog = ProgressDialog.show(this, getString(R.string.history_progressdialog_title), + getString(R.string.history_progressdialog_message), true, false); + viewFlipper = (ViewFlipper) this.findViewById(R.id.view_flipper_history); historyListview = (ListView) this.findViewById(R.id.list_history); historyAdapter = new HistoryCursorAdapter(this, null); @@ -42,6 +66,9 @@ protected void onCreate(Bundle savedInstanceState) { databaseHelper = new DatabaseHelper(getApplicationContext()); + // Make the ViewFlipper invisible until the loader has finished loading data + viewFlipper.setVisibility(View.INVISIBLE); + // Initialize the loader getSupportLoaderManager().initLoader(0, null, this); } @@ -60,18 +87,21 @@ public Loader onCreateLoader(int id, Bundle args) { } @Override - public void onLoadFinished(Loader loader, Cursor data) { - if (data.getCount() == 0) { - viewFlipper.setDisplayedChild(1); - } else { - viewFlipper.setDisplayedChild(0); - historyAdapter.swapCursor(data); - } + public void onLoadFinished(Loader loader, final Cursor data) { + // We can't swap the cursor inside the Handler because the DB + // would be already closed by that time. The good thing is that + // swapping takes a few milliseconds (tested with 10.000 rows of data) so + // it's completely transparent to the user. + historyAdapter.swapCursor(data); + + // Send a delayed message to the ProgressDialog handler to avoid dialog flickering + // in case the data is loaded too fast. From a user perspective it introduces + // consistency. + progressDialogHandler.sendEmptyMessageDelayed(0, 1200); // 1.2 second } @Override public void onLoaderReset(Loader loader) { historyAdapter.swapCursor(null); } - } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d81bf8..96c9a34 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,4 +63,6 @@ Notificar al enviar Selecciona una ONG Ingresa un número de teléfono + Cargando + Un momento por favor...