From bd81a472f9d4f997bd1dc2a29ce2f59f788d4b64 Mon Sep 17 00:00:00 2001 From: cody caughlan Date: Thu, 2 Apr 2015 16:45:09 -0700 Subject: [PATCH] Initial commit --- .gitignore | 6 + .idea/.name | 1 + .idea/compiler.xml | 23 ++ .idea/copyright/profiles_settings.xml | 3 + .idea/encodings.xml | 5 + .idea/gradle.xml | 19 + .idea/misc.xml | 10 + .idea/modules.xml | 10 + .idea/scopes/scope_settings.xml | 5 + .idea/vcs.xml | 7 + SMSButler.iml | 19 + app/.gitignore | 1 + app/app.iml | 99 ++++++ app/build.gradle | 37 ++ app/proguard-rules.pro | 17 + .../smsbutler/ApplicationTest.java | 13 + app/src/main/AndroidManifest.xml | 33 ++ .../smsbutler/ChooseMessageAdapter.java | 70 ++++ .../com/codycaughlan/smsbutler/Constants.java | 19 + .../codycaughlan/smsbutler/IncomingSms.java | 58 +++ .../smsbutler/NavigationDrawerFragment.java | 282 +++++++++++++++ .../activities/BaseActionBarActivity.java | 21 ++ .../activities/ChooseMessageActivity.java | 165 +++++++++ .../smsbutler/activities/MainActivity.java | 233 +++++++++++++ .../smsbutler/events/BusProvider.java | 17 + .../events/CreateMessageRequest.java | 4 + .../smsbutler/events/DidEditMessage.java | 13 + .../smsbutler/events/EditMessageRequest.java | 11 + .../smsbutler/events/MessageChosen.java | 9 + .../smsbutler/events/SmsButlerBus.java | 37 ++ .../events/UserDidChooseMessage.java | 9 + .../fragment/BaseDialogFragment.java | 35 ++ .../smsbutler/fragment/EditMessage.java | 92 +++++ .../smsbutler/realm/StockMessage.java | 23 ++ .../smsbutler/util/AlertUtil.java | 41 +++ .../codycaughlan/smsbutler/util/TextUtil.java | 8 + .../smsbutler/viewholder/EmptyViewHolder.java | 33 ++ .../viewholder/StockMessageHolder.java | 55 +++ .../SwipeToDismissTouchListener.java | 329 ++++++++++++++++++ .../res/drawable-hdpi/drawer_shadow.9.png | Bin 0 -> 161 bytes app/src/main/res/drawable-hdpi/ic_drawer.png | Bin 0 -> 2829 bytes app/src/main/res/drawable-hdpi/icon.png | Bin 0 -> 3466 bytes .../res/drawable-mdpi/drawer_shadow.9.png | Bin 0 -> 142 bytes app/src/main/res/drawable-mdpi/ic_drawer.png | Bin 0 -> 2820 bytes app/src/main/res/drawable-mdpi/icon.png | Bin 0 -> 26865 bytes .../res/drawable-xhdpi/drawer_shadow.9.png | Bin 0 -> 174 bytes app/src/main/res/drawable-xhdpi/ic_drawer.png | Bin 0 -> 2836 bytes app/src/main/res/drawable-xhdpi/icon.png | Bin 0 -> 4773 bytes .../res/drawable-xxhdpi/drawer_shadow.9.png | Bin 0 -> 208 bytes .../main/res/drawable-xxhdpi/ic_drawer.png | Bin 0 -> 202 bytes app/src/main/res/drawable/button.xml | 17 + app/src/main/res/drawable/button_normal.xml | 16 + app/src/main/res/drawable/button_pressed.xml | 16 + .../res/layout/activity_choose_message.xml | 19 + app/src/main/res/layout/activity_main.xml | 86 +++++ .../res/layout/choose_message_empty_view.xml | 19 + .../main/res/layout/fragment_edit_message.xml | 72 ++++ app/src/main/res/layout/fragment_main.xml | 22 ++ .../res/layout/fragment_navigation_drawer.xml | 5 + .../res/layout/list_item_stock_message.xml | 106 ++++++ app/src/main/res/layout/toolbar.xml | 9 + .../main/res/menu/choose_message_activity.xml | 11 + app/src/main/res/menu/global.xml | 5 + app/src/main/res/menu/main.xml | 8 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes app/src/main/res/values-w820dp/dimens.xml | 6 + app/src/main/res/values/color.xml | 23 ++ app/src/main/res/values/dimens.xml | 9 + app/src/main/res/values/strings.xml | 22 ++ app/src/main/res/values/styles.xml | 39 +++ build.gradle | 19 + gradle.properties | 18 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 +++++++++ gradlew.bat | 90 +++++ settings.gradle | 1 + 80 files changed, 2680 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/vcs.xml create mode 100644 SMSButler.iml create mode 100644 app/.gitignore create mode 100644 app/app.iml create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/codycaughlan/smsbutler/ApplicationTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/ChooseMessageAdapter.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/Constants.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/IncomingSms.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/NavigationDrawerFragment.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/activities/BaseActionBarActivity.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/activities/ChooseMessageActivity.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/activities/MainActivity.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/BusProvider.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/CreateMessageRequest.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/DidEditMessage.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/EditMessageRequest.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/MessageChosen.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/SmsButlerBus.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/events/UserDidChooseMessage.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/fragment/BaseDialogFragment.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/fragment/EditMessage.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/realm/StockMessage.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/util/AlertUtil.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/util/TextUtil.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/viewholder/EmptyViewHolder.java create mode 100644 app/src/main/java/com/codycaughlan/smsbutler/viewholder/StockMessageHolder.java create mode 100644 app/src/main/java/com/du/android/recyclerview/SwipeToDismissTouchListener.java create mode 100644 app/src/main/res/drawable-hdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-hdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-hdpi/icon.png create mode 100644 app/src/main/res/drawable-mdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-mdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-mdpi/icon.png create mode 100644 app/src/main/res/drawable-xhdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-xhdpi/icon.png create mode 100644 app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable/button.xml create mode 100644 app/src/main/res/drawable/button_normal.xml create mode 100644 app/src/main/res/drawable/button_pressed.xml create mode 100644 app/src/main/res/layout/activity_choose_message.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/choose_message_empty_view.xml create mode 100644 app/src/main/res/layout/fragment_edit_message.xml create mode 100644 app/src/main/res/layout/fragment_main.xml create mode 100644 app/src/main/res/layout/fragment_navigation_drawer.xml create mode 100644 app/src/main/res/layout/list_item_stock_message.xml create mode 100644 app/src/main/res/layout/toolbar.xml create mode 100644 app/src/main/res/menu/choose_message_activity.xml create mode 100644 app/src/main/res/menu/global.xml create mode 100644 app/src/main/res/menu/main.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/color.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afbdab3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..07cac5f --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +SMS Butler \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..217af47 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..fe865d3 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..59436c9 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..65eb0e5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..def6a6a --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/SMSButler.iml b/SMSButler.iml new file mode 100644 index 0000000..0bb6048 --- /dev/null +++ b/SMSButler.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..a7323b1 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..3faac38 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "com.codycaughlan.smsbutler" + minSdkVersion 16 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + packagingOptions { + exclude 'META-INF/services/javax.annotation.processing.Processor' + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:21.0.3' + + compile 'com.squareup:otto:1.3.6' + compile 'com.android.support:cardview-v7:+' + compile 'com.android.support:recyclerview-v7:+' + compile 'io.realm:realm-android:0.80.0' + compile 'com.joanzapata.android:android-iconify:1.0.9' + compile 'com.jakewharton:butterknife:6.1.0' + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..24a2ee6 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /AndroidSDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/codycaughlan/smsbutler/ApplicationTest.java b/app/src/androidTest/java/com/codycaughlan/smsbutler/ApplicationTest.java new file mode 100644 index 0000000..35a7d9e --- /dev/null +++ b/app/src/androidTest/java/com/codycaughlan/smsbutler/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.codycaughlan.smsbutler; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1e82aa0 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/codycaughlan/smsbutler/ChooseMessageAdapter.java b/app/src/main/java/com/codycaughlan/smsbutler/ChooseMessageAdapter.java new file mode 100644 index 0000000..3a72e6f --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/ChooseMessageAdapter.java @@ -0,0 +1,70 @@ +package com.codycaughlan.smsbutler; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.codycaughlan.smsbutler.realm.StockMessage; +import com.codycaughlan.smsbutler.viewholder.EmptyViewHolder; +import com.codycaughlan.smsbutler.viewholder.StockMessageHolder; + +import java.util.List; + +public class ChooseMessageAdapter extends RecyclerView.Adapter { + private List mMessages; + private static final int EMPTY_VIEW = 10; + + public ChooseMessageAdapter(List messages) { + mMessages = messages; + } + + @Override + public int getItemCount() { + return mMessages.size() > 0 ? mMessages.size() : 1; + } + + @Override + public int getItemViewType(int position) { + if (mMessages.size() == 0) { + return EMPTY_VIEW; + } + return super.getItemViewType(position); + } + + public void removeItem(int position) { + mMessages.remove(position); + } + + public StockMessage get(int index) { + return mMessages.get(index); + } + + public void save(int index, StockMessage item) { + mMessages.set(index, item); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v; + + if(viewType == EMPTY_VIEW) { + v = LayoutInflater.from(parent.getContext()).inflate(R.layout.choose_message_empty_view, parent, false); + EmptyViewHolder evh = new EmptyViewHolder(v); + return evh; + } + + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_item_stock_message, parent, false); + return new StockMessageHolder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int pos) { + if(holder instanceof StockMessageHolder) { + StockMessage message = mMessages.get(pos); + ((StockMessageHolder)holder).bindStockMessage(message); + } + } + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/Constants.java b/app/src/main/java/com/codycaughlan/smsbutler/Constants.java new file mode 100644 index 0000000..3ff541f --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/Constants.java @@ -0,0 +1,19 @@ +package com.codycaughlan.smsbutler; + +public class Constants { + + public static final String PREFS_AUTO_REPLY_KEY = "auto_reply_message"; + public static final String PREFS_TITLE = "SmsButler"; + public static final String PREFS_ENABLED = "enabled"; + public static final String PREFS_FIRST_INSTALL = "first_install"; + + public static final String KEY_MESSAGE_TEXT = "message_text"; + public static final String KEY_POSITION = "position"; + public static final String KEY_ACTION = "action"; + + public static final int DID_CHOOSE_MESSAGE = 1; + + public static final int ACTION_CREATE = 1; + public static final int ACTION_EDIT = 2; + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/IncomingSms.java b/app/src/main/java/com/codycaughlan/smsbutler/IncomingSms.java new file mode 100644 index 0000000..20fcaa1 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/IncomingSms.java @@ -0,0 +1,58 @@ +package com.codycaughlan.smsbutler; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; +import android.util.Log; +import android.widget.Toast; + +public class IncomingSms extends BroadcastReceiver { + private static final String TAG = "IncomingSms"; + + final SmsManager sms = SmsManager.getDefault(); + + public void onReceive(Context context, Intent intent) { + + SharedPreferences preferences = context.getApplicationContext(). + getSharedPreferences(Constants.PREFS_TITLE, Context.MODE_PRIVATE); + + boolean enabled = preferences.getBoolean(Constants.PREFS_ENABLED, false); + if(!enabled) { + Log.i(TAG, "SMS Butler: not enabled."); + return; + } else { + Log.i(TAG, "SMS Butler: Enabled. At your bidding!"); + } + + final Bundle bundle = intent.getExtras(); + + try { + if (bundle != null) { + final Object[] pdusObj = (Object[]) bundle.get("pdus"); + for (int i = 0; i < pdusObj.length; i++) { + + SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]); + String phoneNumber = currentMessage.getDisplayOriginatingAddress(); + + String senderNum = phoneNumber; + String message = currentMessage.getDisplayMessageBody(); + + Log.i(TAG, "senderNum: " + senderNum + "; message: " + message); + + String autoReplyMessage = preferences.getString(Constants.PREFS_AUTO_REPLY_KEY, ""); + if(autoReplyMessage != null && autoReplyMessage.trim().length() > 0) { + Log.i(TAG, "sending back: " + autoReplyMessage); + sms.sendTextMessage(phoneNumber, null, autoReplyMessage, null, null); + } + } + } + } catch (Exception e) { + Log.e(TAG, "Exception smsReceiver: " + e.toString()); + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/codycaughlan/smsbutler/NavigationDrawerFragment.java b/app/src/main/java/com/codycaughlan/smsbutler/NavigationDrawerFragment.java new file mode 100644 index 0000000..cf415de --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/NavigationDrawerFragment.java @@ -0,0 +1,282 @@ +package com.codycaughlan.smsbutler; + +import android.support.v7.app.ActionBarActivity; +import android.app.Activity; +import android.support.v7.app.ActionBar; +import android.support.v4.app.Fragment; +import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.content.SharedPreferences; +import android.content.res.Configuration; +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.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.Toast; + +/** + * Fragment used for managing interactions for and presentation of a navigation drawer. + * See the + * design guidelines for a complete explanation of the behaviors implemented here. + */ +public class NavigationDrawerFragment extends Fragment { + + /** + * Remember the position of the selected item. + */ + private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; + + /** + * Per the design guidelines, you should show the drawer on launch until the user manually + * expands it. This shared preference tracks this. + */ + private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; + + /** + * A pointer to the current callbacks instance (the Activity). + */ + private NavigationDrawerCallbacks mCallbacks; + + /** + * Helper component that ties the action bar to the navigation drawer. + */ + private ActionBarDrawerToggle mDrawerToggle; + + private DrawerLayout mDrawerLayout; + private ListView mDrawerListView; + private View mFragmentContainerView; + + private int mCurrentSelectedPosition = 0; + private boolean mFromSavedInstanceState; + private boolean mUserLearnedDrawer; + + public NavigationDrawerFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Read in the flag indicating whether or not the user has demonstrated awareness of the + // drawer. See PREF_USER_LEARNED_DRAWER for details. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); + mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); + + if (savedInstanceState != null) { + mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION); + mFromSavedInstanceState = true; + } + + // Select either the default item (0) or the last selected item. + selectItem(mCurrentSelectedPosition); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + // Indicate that this fragment would like to influence the set of actions in the action bar. + setHasOptionsMenu(true); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mDrawerListView = (ListView) inflater.inflate( + R.layout.fragment_navigation_drawer, container, false); + mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + selectItem(position); + } + }); + mDrawerListView.setAdapter(new ArrayAdapter( + getActionBar().getThemedContext(), + android.R.layout.simple_list_item_activated_1, + android.R.id.text1, + new String[]{ + getString(R.string.title_section1), + getString(R.string.title_section2), + getString(R.string.title_section3), + })); + mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); + return mDrawerListView; + } + + public boolean isDrawerOpen() { + return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView); + } + + /** + * Users of this fragment must call this method to set up the navigation drawer interactions. + * + * @param fragmentId The android:id of this fragment in its activity's layout. + * @param drawerLayout The DrawerLayout containing this fragment's UI. + */ + public void setUp(int fragmentId, DrawerLayout drawerLayout) { + mFragmentContainerView = getActivity().findViewById(fragmentId); + mDrawerLayout = drawerLayout; + + // set a custom shadow that overlays the main content when the drawer opens + mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); + // set up the drawer's list view with items and click listener + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeButtonEnabled(true); + + // ActionBarDrawerToggle ties together the the proper interactions + // between the navigation drawer and the action bar app icon. + mDrawerToggle = new ActionBarDrawerToggle( + getActivity(), /* host Activity */ + mDrawerLayout, /* DrawerLayout object */ + R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ + R.string.navigation_drawer_open, /* "open drawer" description for accessibility */ + R.string.navigation_drawer_close /* "close drawer" description for accessibility */ + ) { + @Override + public void onDrawerClosed(View drawerView) { + super.onDrawerClosed(drawerView); + if (!isAdded()) { + return; + } + + getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu() + } + + @Override + public void onDrawerOpened(View drawerView) { + super.onDrawerOpened(drawerView); + if (!isAdded()) { + return; + } + + if (!mUserLearnedDrawer) { + // The user manually opened the drawer; store this flag to prevent auto-showing + // the navigation drawer automatically in the future. + mUserLearnedDrawer = true; + SharedPreferences sp = PreferenceManager + .getDefaultSharedPreferences(getActivity()); + sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply(); + } + + getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu() + } + }; + + // If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer, + // per the navigation drawer design guidelines. + if (!mUserLearnedDrawer && !mFromSavedInstanceState) { + mDrawerLayout.openDrawer(mFragmentContainerView); + } + + // Defer code dependent on restoration of previous instance state. + mDrawerLayout.post(new Runnable() { + @Override + public void run() { + mDrawerToggle.syncState(); + } + }); + + mDrawerLayout.setDrawerListener(mDrawerToggle); + } + + private void selectItem(int position) { + mCurrentSelectedPosition = position; + if (mDrawerListView != null) { + mDrawerListView.setItemChecked(position, true); + } + if (mDrawerLayout != null) { + mDrawerLayout.closeDrawer(mFragmentContainerView); + } + if (mCallbacks != null) { + mCallbacks.onNavigationDrawerItemSelected(position); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mCallbacks = (NavigationDrawerCallbacks) activity; + } catch (ClassCastException e) { + throw new ClassCastException("Activity must implement NavigationDrawerCallbacks."); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mCallbacks = null; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Forward the new configuration the drawer toggle component. + mDrawerToggle.onConfigurationChanged(newConfig); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // If the drawer is open, show the global app actions in the action bar. See also + // showGlobalContextActionBar, which controls the top-left area of the action bar. + if (mDrawerLayout != null && isDrawerOpen()) { + inflater.inflate(R.menu.global, menu); + showGlobalContextActionBar(); + } + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (mDrawerToggle.onOptionsItemSelected(item)) { + return true; + } + + if (item.getItemId() == R.id.action_example) { + Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + /** + * Per the navigation drawer design guidelines, updates the action bar to show the global app + * 'context', rather than just what's in the current screen. + */ + private void showGlobalContextActionBar() { + ActionBar actionBar = getActionBar(); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + actionBar.setTitle(R.string.app_name); + } + + private ActionBar getActionBar() { + return ((ActionBarActivity) getActivity()).getSupportActionBar(); + } + + /** + * Callbacks interface that all activities using this fragment must implement. + */ + public static interface NavigationDrawerCallbacks { + /** + * Called when an item in the navigation drawer is selected. + */ + void onNavigationDrawerItemSelected(int position); + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/activities/BaseActionBarActivity.java b/app/src/main/java/com/codycaughlan/smsbutler/activities/BaseActionBarActivity.java new file mode 100644 index 0000000..77b25b8 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/activities/BaseActionBarActivity.java @@ -0,0 +1,21 @@ +package com.codycaughlan.smsbutler.activities; + +import android.support.v7.app.ActionBarActivity; + +import com.codycaughlan.smsbutler.events.BusProvider; + +public class BaseActionBarActivity extends ActionBarActivity { + + @Override + protected void onResume() { + super.onResume(); + BusProvider.instance().register(this); + } + + @Override + public void onPause() { + super.onPause(); + BusProvider.instance().unregister(this); + } + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/activities/ChooseMessageActivity.java b/app/src/main/java/com/codycaughlan/smsbutler/activities/ChooseMessageActivity.java new file mode 100644 index 0000000..addac57 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/activities/ChooseMessageActivity.java @@ -0,0 +1,165 @@ +package com.codycaughlan.smsbutler.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.Toast; + +import com.codycaughlan.smsbutler.ChooseMessageAdapter; +import com.codycaughlan.smsbutler.Constants; +import com.codycaughlan.smsbutler.R; +import com.codycaughlan.smsbutler.events.CreateMessageRequest; +import com.codycaughlan.smsbutler.events.DidEditMessage; +import com.codycaughlan.smsbutler.events.EditMessageRequest; +import com.codycaughlan.smsbutler.events.MessageChosen; +import com.codycaughlan.smsbutler.fragment.EditMessage; +import com.codycaughlan.smsbutler.realm.StockMessage; +import com.du.android.recyclerview.SwipeToDismissTouchListener; +import com.squareup.otto.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +import io.realm.Realm; +import io.realm.RealmResults; + +public class ChooseMessageActivity extends BaseActionBarActivity { + + private static final String TAG = "ChooseMessageActivity"; + private RecyclerView mList; + private ChooseMessageAdapter mAdapter; + private RealmResults mMessages; + private Realm mRealm; + private SwipeToDismissTouchListener mSwipeListener; + private Toolbar mToolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_choose_message); + + setTitle("Manage Messages"); + + mToolbar = (Toolbar)findViewById(R.id.toolbar); + setSupportActionBar(mToolbar); + + mRealm = Realm.getInstance(this); + + mList = (RecyclerView)findViewById(R.id.list_view); + LinearLayoutManager layoutManager = new LinearLayoutManager(this); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + mList.setLayoutManager(layoutManager); + + refreshMessagesList(); + mAdapter = new ChooseMessageAdapter(mMessages); + mList.setAdapter(mAdapter); + + mSwipeListener = new SwipeToDismissTouchListener(mList, new SwipeToDismissTouchListener.DismissCallbacks() { + @Override + public SwipeToDismissTouchListener.SwipeDirection canDismiss(int position) { + return SwipeToDismissTouchListener.SwipeDirection.RIGHT; + } + @Override + public void onDismiss(RecyclerView view, List dismissData) { + mRealm.beginTransaction(); + for (SwipeToDismissTouchListener.PendingDismissData data : dismissData) { + mMessages.remove(data.position); + mAdapter.notifyItemRemoved(data.position); + } + mRealm.commitTransaction(); + Toast.makeText(getApplicationContext(), "Deleted that message.", Toast.LENGTH_LONG).show(); + } + }); + + mList.addOnItemTouchListener(mSwipeListener); + } + + private void refreshMessagesList() { + mMessages = mRealm.where(StockMessage.class).findAll(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mRealm.close(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu items for use in the action bar + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.choose_message_activity, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle presses on the action bar items + switch (item.getItemId()) { + case R.id.action_add: + promptForMessageInput(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private void promptForMessageInput() { + FragmentManager fm = getSupportFragmentManager(); + EditMessage frag = EditMessage.newInstance(Constants.ACTION_CREATE, 0, null); + frag.show(fm, "editor"); + } + + /* Event Subscriptions */ + + @Subscribe + public void onMessageChosen(MessageChosen event) { + Log.i(TAG, "onMessageChosen: " + event.message); + Intent resultIntent = new Intent(); + resultIntent.putExtra(Constants.KEY_MESSAGE_TEXT, event.message); + setResult(Constants.DID_CHOOSE_MESSAGE, resultIntent); + finish(); + } + + @Subscribe + public void onEditMessageRequest(EditMessageRequest event) { + Log.i(TAG, "onEditMessageRequest"); + FragmentManager fm = getSupportFragmentManager(); + EditMessage frag = EditMessage.newInstance(Constants.ACTION_EDIT, event.position, event.message); + frag.show(fm, "editor"); + } + + @Subscribe + public void onCreateMessageRequest(CreateMessageRequest event) { + Log.i(TAG, "onCreateMessageRequest"); + FragmentManager fm = getSupportFragmentManager(); + EditMessage frag = EditMessage.newInstance(Constants.ACTION_CREATE, 0, null); + frag.show(fm, "editor"); + } + + @Subscribe + public void onDidEditMessage(DidEditMessage event) { + Log.i(TAG, "onDidEditMessage"); + + if(event.action == Constants.ACTION_CREATE) { + // Its an Add New + mRealm.beginTransaction(); + mRealm.createObject(StockMessage.class).setMessage(event.message); + mRealm.commitTransaction(); + refreshMessagesList(); + } else if(event.action == Constants.ACTION_EDIT) { + StockMessage item = mAdapter.get(event.position); + mRealm.beginTransaction(); + item.setMessage(event.message); + mRealm.commitTransaction(); + mAdapter.notifyItemChanged(event.position); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/codycaughlan/smsbutler/activities/MainActivity.java b/app/src/main/java/com/codycaughlan/smsbutler/activities/MainActivity.java new file mode 100644 index 0000000..1353914 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/activities/MainActivity.java @@ -0,0 +1,233 @@ +package com.codycaughlan.smsbutler.activities; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Paint; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ToggleButton; + +import com.codycaughlan.smsbutler.Constants; +import com.codycaughlan.smsbutler.R; +import com.codycaughlan.smsbutler.realm.StockMessage; +import com.codycaughlan.smsbutler.util.TextUtil; +import com.codycaughlan.smsbutler.events.UserDidChooseMessage; +import com.joanzapata.android.iconify.IconDrawable; +import com.joanzapata.android.iconify.Iconify; +import com.squareup.otto.Subscribe; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import io.realm.Realm; + + +public class MainActivity extends BaseActionBarActivity { + private static final String TAG = "MainActivity"; + + @InjectView(R.id.message_edit) + EditText mMessageEdit; + + @InjectView(R.id.save_button) + Button mSave; + + @InjectView(R.id.choose_message) + ImageView mChoose; + + @InjectView(R.id.toggle) + ToggleButton mToggle; + + @InjectView(R.id.manage_messages) + TextView mManage; + + @InjectView(R.id.manage_container) + LinearLayout mManageContainer; + + SharedPreferences mPreferences; + private Realm mRealm; + private Toolbar mToolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mPreferences = getSharedPreferences(Constants.PREFS_TITLE, Context.MODE_PRIVATE); + ButterKnife.inject(this); + + mToolbar = (Toolbar)findViewById(R.id.toolbar); + setSupportActionBar(mToolbar); + + mToggle.setChecked(isEnabled()); + + mMessageEdit.setText(fetchMessage()); + + IconDrawable icon = new IconDrawable(this, Iconify.IconValue.fa_inbox).colorRes(R.color.black).sizeDp(20); + mManage.setCompoundDrawables(null, null, icon, null); + mManage.setCompoundDrawablePadding(16); + mManage.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.UNDERLINE_TEXT_FLAG); + + mSave.setOnClickListener(new Button.OnClickListener() { + @Override + public void onClick(View view) { + String message = getEditMessage(); + Log.i(TAG, message); + if(!TextUtil.isBlank(message)) { + dismissKeyboard(); + persistMessage(message); + } + } + }); + + mMessageEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + boolean handled = false; + dismissKeyboard(); + if (actionId == EditorInfo.IME_ACTION_DONE) { + persistMessage(getEditMessage()); + handled = true; + } + return handled; + } + }); + + mToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + toggleAutoReply(compoundButton.isChecked()); + } + }); + + mManageContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + launchChooseMessage(); + } + }); + //performFirstInstallActions(); + } + + @Override + protected void onResume() { + super.onResume(); + updateToggleColorState(); + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + if(mRealm != null) { + mRealm.close(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if(requestCode == Constants.DID_CHOOSE_MESSAGE) { + if(data != null) { + Bundle extras = data.getExtras(); + String message = extras.getString(Constants.KEY_MESSAGE_TEXT); + mMessageEdit.setText(message); + } + } + } + + private String getEditMessage() { + return mMessageEdit.getText().toString(); + } + + private void persistMessage(String message) { + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(Constants.PREFS_AUTO_REPLY_KEY, message); + editor.commit(); + Toast.makeText(getApplicationContext(), "Saved your message.", Toast.LENGTH_LONG).show(); + } + + private String fetchMessage() { + return mPreferences.getString(Constants.PREFS_AUTO_REPLY_KEY, ""); + } + + private void dismissKeyboard() { + InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mMessageEdit.getWindowToken(), 0); + } + + private void updateToggleColorState() { + if(mToggle.isChecked()) { + mToggle.setTextColor(getResources().getColor(R.color.toggle_on)); + } else { + mToggle.setTextColor(getResources().getColor(R.color.toggle_off)); + } + } + + private void toggleAutoReply(boolean enable) { + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(Constants.PREFS_ENABLED, enable); + editor.commit(); + updateToggleColorState(); + } + + private boolean isEnabled() { + return mPreferences.getBoolean(Constants.PREFS_ENABLED, true); + } + + private void launchChooseMessage() { + Intent intent = new Intent(getApplicationContext(), ChooseMessageActivity.class); + startActivityForResult(intent, Constants.DID_CHOOSE_MESSAGE); + } + + private boolean isFirstRun() { + return mPreferences.getBoolean(Constants.PREFS_FIRST_INSTALL, true); + } + + private void setDidFirstInstall() { + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean(Constants.PREFS_FIRST_INSTALL, false); + editor.commit(); + } + + /* + private void performFirstInstallActions() { + if(isFirstRun()) { + Realm.deleteRealmFile(this); + + mRealm = Realm.getInstance(this); + mRealm.beginTransaction(); + + String[] stockMessages = getResources().getStringArray(R.array.stock_messages); + for(int i = 0; i < stockMessages.length; i++) { + StockMessage message = mRealm.createObject(StockMessage.class); + message.setMessage(stockMessages[i]); + Log.i(TAG, "storing: " + stockMessages[i]); + } + mRealm.commitTransaction(); + + setDidFirstInstall(); + } + } + */ + + /* Event Subscriptions */ + + @Subscribe + public void onUserDidChooseMessage(UserDidChooseMessage event) { + Log.i(TAG, "onUserDidChooseMessage: " + event.message); + } + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/BusProvider.java b/app/src/main/java/com/codycaughlan/smsbutler/events/BusProvider.java new file mode 100644 index 0000000..66d9903 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/BusProvider.java @@ -0,0 +1,17 @@ +package com.codycaughlan.smsbutler.events; + +import com.squareup.otto.Bus; +import com.squareup.otto.ThreadEnforcer; + +public final class BusProvider { + + private static final Bus BUS = new SmsButlerBus(ThreadEnforcer.ANY); + + public static Bus instance(){ + return BUS; + } + + private BusProvider(){} + +} + diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/CreateMessageRequest.java b/app/src/main/java/com/codycaughlan/smsbutler/events/CreateMessageRequest.java new file mode 100644 index 0000000..b8dcfdb --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/CreateMessageRequest.java @@ -0,0 +1,4 @@ +package com.codycaughlan.smsbutler.events; + +public class CreateMessageRequest { +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/DidEditMessage.java b/app/src/main/java/com/codycaughlan/smsbutler/events/DidEditMessage.java new file mode 100644 index 0000000..30dd450 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/DidEditMessage.java @@ -0,0 +1,13 @@ +package com.codycaughlan.smsbutler.events; + +public class DidEditMessage { + public int action; + public int position; + public String message; + + public DidEditMessage(int action, int position, String message) { + this.action = action; + this.position = position; + this.message = message; + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/EditMessageRequest.java b/app/src/main/java/com/codycaughlan/smsbutler/events/EditMessageRequest.java new file mode 100644 index 0000000..a7311a8 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/EditMessageRequest.java @@ -0,0 +1,11 @@ +package com.codycaughlan.smsbutler.events; + +public class EditMessageRequest { + public int position; + public String message; + + public EditMessageRequest(int position, String message) { + this.position = position; + this.message = message; + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/MessageChosen.java b/app/src/main/java/com/codycaughlan/smsbutler/events/MessageChosen.java new file mode 100644 index 0000000..c5cd374 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/MessageChosen.java @@ -0,0 +1,9 @@ +package com.codycaughlan.smsbutler.events; + +public class MessageChosen { + public String message; + + public MessageChosen(String message) { + this.message = message; + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/SmsButlerBus.java b/app/src/main/java/com/codycaughlan/smsbutler/events/SmsButlerBus.java new file mode 100644 index 0000000..ba8d170 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/SmsButlerBus.java @@ -0,0 +1,37 @@ +package com.codycaughlan.smsbutler.events; + + +// https://github.com/square/otto/issues/38 + +import android.os.Handler; +import android.os.Looper; + +import com.squareup.otto.Bus; +import com.squareup.otto.ThreadEnforcer; + +public class SmsButlerBus extends Bus { + private final Handler mainThread = new Handler(Looper.getMainLooper()); + + public SmsButlerBus(ThreadEnforcer enforcer) { + super(enforcer); + } + + /* + Post on the main thread if we are being invoked from the main thread. + If we're not on the main thread than get a handler to the main thread + and post it there. + */ + @Override public void post(final Object event) { + if (Looper.myLooper() == Looper.getMainLooper()) { + super.post(event); + } else { + mainThread.post(new Runnable() { + @Override + public void run() { + post(event); + } + }); + } + } + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/events/UserDidChooseMessage.java b/app/src/main/java/com/codycaughlan/smsbutler/events/UserDidChooseMessage.java new file mode 100644 index 0000000..c258be7 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/events/UserDidChooseMessage.java @@ -0,0 +1,9 @@ +package com.codycaughlan.smsbutler.events; + +public class UserDidChooseMessage { + public String message; + + public UserDidChooseMessage(String message) { + this.message = message; + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/fragment/BaseDialogFragment.java b/app/src/main/java/com/codycaughlan/smsbutler/fragment/BaseDialogFragment.java new file mode 100644 index 0000000..bb46983 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/fragment/BaseDialogFragment.java @@ -0,0 +1,35 @@ +package com.codycaughlan.smsbutler.fragment; + +import android.app.ProgressDialog; +import android.support.v4.app.DialogFragment; + +import com.codycaughlan.smsbutler.events.BusProvider; +import com.codycaughlan.smsbutler.util.AlertUtil; + +public class BaseDialogFragment extends DialogFragment { + protected ProgressDialog mProgressDialog; + + @Override + public void onResume() { + super.onResume(); + BusProvider.instance().register(this); + } + + @Override + public void onPause() { + super.onPause(); + BusProvider.instance().unregister(this); + } + + protected void startProgressSpinner(String title, String message) { + mProgressDialog = AlertUtil.createProgressSpinner(getActivity(), title, message); + } + + protected void stopProgressSpinner() { + if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } + } + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/fragment/EditMessage.java b/app/src/main/java/com/codycaughlan/smsbutler/fragment/EditMessage.java new file mode 100644 index 0000000..86d0892 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/fragment/EditMessage.java @@ -0,0 +1,92 @@ +package com.codycaughlan.smsbutler.fragment; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import com.codycaughlan.smsbutler.Constants; +import com.codycaughlan.smsbutler.R; +import com.codycaughlan.smsbutler.events.BusProvider; +import com.codycaughlan.smsbutler.events.DidEditMessage; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +public class EditMessage extends BaseDialogFragment { + + @InjectView(R.id.title) + TextView mTitle; + @InjectView(R.id.message) + EditText mEditText; + @InjectView(R.id.cancel) + Button mCancel; + @InjectView(R.id.save) + Button mSave; + + private int mPosition; + private int mAction; + + public static EditMessage newInstance(int action, int position, String message) { + EditMessage fragment = new EditMessage(); + Bundle args = new Bundle(); + args.putInt(Constants.KEY_ACTION, action); + args.putString(Constants.KEY_MESSAGE_TEXT, message); + args.putInt(Constants.KEY_POSITION, position); + fragment.setArguments(args); + + return fragment; + } + + /* + We override this method and specify no-title so we have more control + over the dialog UI in our layout XML + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + return dialog; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + String message = getArguments().getString(Constants.KEY_MESSAGE_TEXT); + mPosition = getArguments().getInt(Constants.KEY_POSITION, -1); + mAction = getArguments().getInt(Constants.KEY_ACTION, -1); + + View rootView = inflater.inflate(R.layout.fragment_edit_message, null); + ButterKnife.inject(this, rootView); + + mEditText.setText(message); + + if(mAction == Constants.ACTION_CREATE) { + mTitle.setText("Create a New Message"); + } else if(mAction == Constants.ACTION_EDIT) { + mTitle.setText("Edit your Message"); + } + + mCancel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + } + }); + + mSave.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + BusProvider.instance().post(new DidEditMessage(mAction, mPosition, mEditText.getText().toString())); + dismiss(); + } + }); + + return rootView; + } + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/realm/StockMessage.java b/app/src/main/java/com/codycaughlan/smsbutler/realm/StockMessage.java new file mode 100644 index 0000000..6c05583 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/realm/StockMessage.java @@ -0,0 +1,23 @@ +package com.codycaughlan.smsbutler.realm; + +import io.realm.RealmObject; + +public class StockMessage extends RealmObject { + + private String message; + + public StockMessage() { + } + + public StockMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/util/AlertUtil.java b/app/src/main/java/com/codycaughlan/smsbutler/util/AlertUtil.java new file mode 100644 index 0000000..ecf7088 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/util/AlertUtil.java @@ -0,0 +1,41 @@ +package com.codycaughlan.smsbutler.util; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; + +import com.codycaughlan.smsbutler.R; + +public class AlertUtil { + + public static ProgressDialog createProgressSpinner(Context context, String title, String message) { + ProgressDialog dialog = null; + if (dialog == null) { + dialog = ProgressDialog.show(context, title, message); + } else { + dialog.setTitle(title); + dialog.setMessage(message); + } + dialog.show(); + + return dialog; + } + + public static AlertDialog createModalAlert(Context context, String title, String message) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(title); + builder.setCancelable(false); + builder.setMessage(message); + builder.setPositiveButton(R.string.alert_dialog_ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + + return builder.create(); + } + + +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/util/TextUtil.java b/app/src/main/java/com/codycaughlan/smsbutler/util/TextUtil.java new file mode 100644 index 0000000..b774708 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/util/TextUtil.java @@ -0,0 +1,8 @@ +package com.codycaughlan.smsbutler.util; + +public class TextUtil { + + public static boolean isBlank(String text) { + return(text == null || text.trim().length() == 0); + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/viewholder/EmptyViewHolder.java b/app/src/main/java/com/codycaughlan/smsbutler/viewholder/EmptyViewHolder.java new file mode 100644 index 0000000..20db3bb --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/viewholder/EmptyViewHolder.java @@ -0,0 +1,33 @@ +package com.codycaughlan.smsbutler.viewholder; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.TextView; + +import com.codycaughlan.smsbutler.R; +import com.codycaughlan.smsbutler.events.BusProvider; +import com.codycaughlan.smsbutler.events.CreateMessageRequest; +import com.joanzapata.android.iconify.IconDrawable; +import com.joanzapata.android.iconify.Iconify; + +public class EmptyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + + private TextView mMessage; + + public EmptyViewHolder(View itemView) { + super(itemView); + + mMessage = (TextView)itemView.findViewById(R.id.empty_view_add_message); + mMessage.setOnClickListener(this); + + IconDrawable plusIcon = new IconDrawable(itemView.getContext(), Iconify.IconValue.fa_plus_circle) + .colorRes(R.color.black) + .sizeDp(20); + mMessage.setCompoundDrawables(plusIcon, null, null, null); + } + + @Override + public void onClick(View view) { + BusProvider.instance().post(new CreateMessageRequest()); + } +} diff --git a/app/src/main/java/com/codycaughlan/smsbutler/viewholder/StockMessageHolder.java b/app/src/main/java/com/codycaughlan/smsbutler/viewholder/StockMessageHolder.java new file mode 100644 index 0000000..149db47 --- /dev/null +++ b/app/src/main/java/com/codycaughlan/smsbutler/viewholder/StockMessageHolder.java @@ -0,0 +1,55 @@ +package com.codycaughlan.smsbutler.viewholder; + +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.codycaughlan.smsbutler.R; +import com.codycaughlan.smsbutler.events.BusProvider; +import com.codycaughlan.smsbutler.events.EditMessageRequest; +import com.codycaughlan.smsbutler.events.MessageChosen; +import com.codycaughlan.smsbutler.realm.StockMessage; +import com.joanzapata.android.iconify.IconDrawable; +import com.joanzapata.android.iconify.Iconify; + +public class StockMessageHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + + private static final String TAG = "StockMessageHolder"; + private StockMessage mMessage; + private TextView mTextView; + private FrameLayout mSettingsLayout; + private ImageView mSettingsIcon; + + public StockMessageHolder(View itemView) { + super(itemView); + + mTextView = (TextView)itemView.findViewById(R.id.message_text); + mSettingsLayout = (FrameLayout)itemView.findViewById(R.id.settings_container); + mSettingsIcon = (ImageView)itemView.findViewById(R.id.settings_icon); + + mTextView.setOnClickListener(this); + mSettingsLayout.setOnClickListener(this); + } + + public void bindStockMessage(StockMessage message) { + mMessage = message; + mTextView.setText(mMessage.getMessage()); + + IconDrawable settings = new IconDrawable(mTextView.getContext(), Iconify.IconValue.fa_pencil) + .colorRes(R.color.settings_label).sizeDp(20); + mSettingsIcon.setImageDrawable(settings); + } + + @Override + public void onClick(View view) { + Log.i(TAG, String.valueOf(view.getId())); + if(view.getId() == R.id.message_text) { + BusProvider.instance().post(new MessageChosen(mMessage.getMessage())); + } else if(view.getId() == R.id.settings_container) { + BusProvider.instance().post(new EditMessageRequest(getPosition(), mMessage.getMessage())); + } + } +} diff --git a/app/src/main/java/com/du/android/recyclerview/SwipeToDismissTouchListener.java b/app/src/main/java/com/du/android/recyclerview/SwipeToDismissTouchListener.java new file mode 100644 index 0000000..ad3b277 --- /dev/null +++ b/app/src/main/java/com/du/android/recyclerview/SwipeToDismissTouchListener.java @@ -0,0 +1,329 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.du.android.recyclerview; + +import android.support.v7.widget.RecyclerView; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Based on Roman Nurik's Android-SwipeToDismiss lib https://github.com/romannurik/Android-SwipeToDismiss + *

+ * RecyclerView.OnItemTouchListener that allows items to be swiped and dismissed. + *

+ * Typical usage: + *

+ *

+ * {@code
+ * swipeToDismissTouchListener = new SwipeToDismissTouchListener(recyclerView, new SwipeToDismissTouchListener.DismissCallbacks() {
+ *           @Override
+ *          public SwipeToDismissTouchListener.SwipeDirection canDismiss(int position) {
+ *              return SwipeToDismissTouchListener.SwipeDirection.RIGHT;
+ *          }
+ *           @Override
+ *          public void onDismiss(RecyclerView view, List dismissData) {
+ *             for (SwipeToDismissTouchListener.PendingDismissData data : dismissData) {
+ *                 adapter.removeItem(data.position);
+ *                 adapter.notifyItemRemoved(data.position);
+ *             }
+ *          }
+ *  });
+ *
+ * }
+ * 
+ */ +public class SwipeToDismissTouchListener implements RecyclerView.OnItemTouchListener { + + private final RecyclerView mRecyclerView; + private int mSlop; + private int mMinFlingVelocity; + private int mMaxFlingVelocity; + private long mAnimationTime; + + private DismissCallbacks mCallbacks; + private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero + + // Transient properties + private float mDownX; + private float mDownY; + private boolean mSwiping; + private int mSwipingSlop; + private VelocityTracker mVelocityTracker; + private float mTranslationX; + private boolean mPaused = false; + private View mSwipeView; + private int mDismissCount = 0; + private List mPendingDismisses = new ArrayList(); + private SwipeDirection mAllowedSwipeDirection = SwipeDirection.NONE; + + + /** + * Constructs a new swipe-to-dismiss OnItemTouchListener for RecyclerView + * + * @param recyclerView RecyclerView + * @param callbacks The callback to trigger when the user has indicated that she would like to + * dismiss this view. + */ + public SwipeToDismissTouchListener(RecyclerView recyclerView, DismissCallbacks callbacks) { + ViewConfiguration vc = ViewConfiguration.get(recyclerView.getContext()); + mSlop = vc.getScaledTouchSlop(); + mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 4; + mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); + mAnimationTime = recyclerView.getContext().getResources().getInteger(android.R.integer.config_shortAnimTime); + mRecyclerView = recyclerView; + mCallbacks = callbacks; + } + + public void setEnabled(boolean enabled) { + mPaused = !enabled; + } + + @Override + public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) { + motionEvent.offsetLocation(mTranslationX, 0); + + switch (motionEvent.getActionMasked()) { + case MotionEvent.ACTION_UP: { + up(motionEvent); + break; + } + + case MotionEvent.ACTION_CANCEL: { + cancel(); + break; + } + + case MotionEvent.ACTION_MOVE: { + move(motionEvent); + break; + } + } + } + + @Override + public boolean onInterceptTouchEvent(final RecyclerView view, MotionEvent motionEvent) { + if (mPaused) return false; + // offset because the view is translated during swipe + motionEvent.offsetLocation(mTranslationX, 0); + + if (mViewWidth < 2) { + mViewWidth = view.getWidth(); + } + + switch (motionEvent.getActionMasked()) { + case MotionEvent.ACTION_DOWN: { + return down(motionEvent); + } + case MotionEvent.ACTION_MOVE: { + return move(motionEvent); + + } + + } + return false; + } + + private boolean down(MotionEvent motionEvent) { + if (mPaused) return false; + + mDownX = motionEvent.getRawX(); + mDownY = motionEvent.getRawY(); + mSwipeView = mRecyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY()); + if (mSwipeView == null) return false; + int pos = mRecyclerView.getChildPosition(mSwipeView); + mAllowedSwipeDirection = mCallbacks.canDismiss(pos); + if (mAllowedSwipeDirection != SwipeDirection.NONE) { + + mVelocityTracker = VelocityTracker.obtain(); + mVelocityTracker.addMovement(motionEvent); + return false; + } + resetMotion(); + return false; + } + + private void cancel() { + if (mVelocityTracker == null) { + return; + } + + mSwipeView.animate() + .translationX(0) + .alpha(1) + .setDuration(mAnimationTime) + .setListener(null); + mVelocityTracker.recycle(); + mVelocityTracker = null; + mTranslationX = 0; + mDownX = 0; + mDownY = 0; + mSwiping = false; + mSwipeView = null; + } + + private void up(MotionEvent motionEvent) { + if (mPaused || mVelocityTracker == null || mSwipeView == null) { + return; + } + mSwipeView.setPressed(false); + float deltaX = motionEvent.getRawX() - mDownX; + mVelocityTracker.addMovement(motionEvent); + mVelocityTracker.computeCurrentVelocity(1000); + float velocityX = mVelocityTracker.getXVelocity(); + float absVelocityX = Math.abs(velocityX); + float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); + boolean dismiss = false; + boolean dismissRight = false; + if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) { + dismiss = true; + dismissRight = deltaX > 0; + } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity + && absVelocityY < absVelocityX + && absVelocityY < absVelocityX && mSwiping) { + // dismiss only if flinging in the same direction as dragging + dismiss = (velocityX < 0) == (deltaX < 0); + dismissRight = mVelocityTracker.getXVelocity() > 0; + } + if (dismiss) { + // dismiss + final int pos = mRecyclerView.getChildPosition(mSwipeView); + final View swipeViewCopy = mSwipeView; + final SwipeDirection swipeDirection = dismissRight ? SwipeDirection.RIGHT : SwipeDirection.LEFT; + ++mDismissCount; + mSwipeView.animate() + .translationX(dismissRight ? mViewWidth : -mViewWidth) + .alpha(0) + .setDuration(mAnimationTime); + + //this is instead of unreliable onAnimationEnd callback + swipeViewCopy.postDelayed(new Runnable() { + @Override + public void run() { + performDismiss(swipeViewCopy, pos, swipeDirection); + swipeViewCopy.setTranslationX(0); +// swipeViewCopy.setAlpha(1); + + } + }, mAnimationTime + 100); + + } else if (mSwiping) { + // cancel + mSwipeView.animate() + .translationX(0) + .alpha(1) + .setDuration(mAnimationTime) + .setListener(null); + } + + + resetMotion(); + } + + private boolean move(MotionEvent motionEvent) { + if (mSwipeView == null || mVelocityTracker == null || mPaused) { + return false; + } + + mVelocityTracker.addMovement(motionEvent); + float deltaX = motionEvent.getRawX() - mDownX; + float deltaY = motionEvent.getRawY() - mDownY; + if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) { + mSwiping = true; + mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop); + mSwipeView.setPressed(false); + + MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); + cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); + mSwipeView.onTouchEvent(cancelEvent); + } + + //Prevent swipes to disallowed directions + if ((deltaX < 0 && mAllowedSwipeDirection == SwipeDirection.RIGHT) || (deltaX > 0 && mAllowedSwipeDirection == SwipeDirection.LEFT)) { + resetMotion(); + return false; + } + + if (mSwiping) { + mTranslationX = deltaX; + mSwipeView.setTranslationX(deltaX - mSwipingSlop); + mSwipeView.setAlpha(Math.max(0f, Math.min(1f, + 1f - 2f * Math.abs(deltaX) / mViewWidth))); + return true; + } + return false; + } + + private void resetMotion() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + mTranslationX = 0; + mDownX = 0; + mDownY = 0; + mSwiping = false; + mSwipeView = null; + mAllowedSwipeDirection = SwipeDirection.NONE; + } + + private void performDismiss(View dismissView, int pos, SwipeDirection direction) { + --mDismissCount; + mPendingDismisses.add(new PendingDismissData(pos, dismissView, direction)); + if (mDismissCount == 0) { + Collections.sort(mPendingDismisses); + List dismissData = new ArrayList(mPendingDismisses); + mCallbacks.onDismiss(mRecyclerView, dismissData); + mPendingDismisses.clear(); + } + } + + + public interface DismissCallbacks { + SwipeDirection canDismiss(int position); + + void onDismiss(RecyclerView view, List dismissData); + } + + + public class PendingDismissData implements Comparable { + public int position; + public View view; + public SwipeDirection direction; + + public PendingDismissData(int position, View view, SwipeDirection direction) { + this.position = position; + this.view = view; + this.direction = direction; + + } + + @Override + public int compareTo(PendingDismissData other) { + return other.position - position; + } + } + + public enum SwipeDirection { + LEFT, RIGHT, BOTH, NONE + } +} + diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..236bff558af07faa3921ba35e2515edf62d04bb9 GIT binary patch literal 161 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 SA$k1g1Q_X?>pjy!MEnzU@-6QG literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe3a28d77c72094021013c6442560803b3d344c GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^96+qZ!3HFgEN0vWQY^(zo*^7SP{WbZ0pxQQctjR6 zFmQK*Fr)d&(`$i(2A(dCAr_~TfBgS%&&>BhUX5L;x$y=|hic;t)=0q~!&M0(2Uj#r iT+R^X@#lD(V-Z7IzK5^$KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0000lNkl)HFiry~4#d$|ph7GRd^8UISO5Sz WZ0AQhyumIq{4{svz3g`#Cg{Xok z08kx|`eK9tO;ec2s3-scUUUFJKnMWv1kDOK003NB0DvPy0DvzY0Kj+1Zuu+#{Q}uR zM#~uh0CWHQhp~G6%LHwm&FYJ$i>87+pNYLKvyrL2u^F?6tpl_)03hJO2Ys|Pb1|au zu(h#s=JODw`cDZy=<~m9Fcrmrinv${QfVqEQ;6F;nNe^ub1<_|387F>PzX4gn)9hh zNc~rJXiAXE(#6Gr4-9s9cV~8IXSR2;0JHM)@`72|z-(+x&=O3}o^~!q9!z%5)c>uK z|K5&-nX`$Lm4l0wy&c8Bc8!efU0npJsQz{IKmPt}oVE`Cqa!=#|C$waeqawH2QVu$ z3;6%5l8cr3{~X@`tJc47{#&*G%<8{&CIA%;pSY8mk&C_47khgfAyE^1Cp!u^GbiVN zBjjL)%0U49zZd$SgBAGKDxbK$t%H-9^S>%WoC4tgBkzANucczB< z5D;5JgoYYh!f6b3c<)A#eYc^0m0eJfT~L*sU+FFEM{#TE+L8ZloBga#fgUF(ClLlV z1q?Pt-~)96rhnrIKOHmygYAHm53}Jc0!t$T>-Z@EkwTF%w^89=iUZ(-C=&oLL!pQ~ z0qC>pziyC)rUDQH#sSC)0OY>+Fhl`76&`C`|56ix3&Q_2&O<8#hgpI}*O3LNp$({h~^Xtdw zpF!?*4`1vnMZx+v?sbW`*ghp>D?pFV{11M&k1Y@{j!;uplY#o@%HzAlyX`qoQjX?{}hL#Qa~apax;ms>&o(Tpf4AdOLjBw}u% z<%W6|`bMGa?ZcAR*2h#N?a`*RY{+ZtinG$!T66vFu#|L-NI#`Q< zwutQM3&gug7nHHV7z6*b7y0Ygo*ZRv;Ps%`vjv%(W-H@wOCd|;q|O&wR;E!g^`=Oz zh=!(+GmZJnZAti;#gj}fv|O~{&-fZRQ&TnQ{2z;Kmt(kWRcdNC6NCBD5y@7IwiL3^ zKk7v(W_<*1i=bAv-%Z$ek_uXVn^(*w;T`Jb?|8*qBIhEDV}l=ZJ7s&v!%AJWOK3r$ zcvYqidjb;@{nqh#Z2=;ADB*H%&M)5_uZHB9IC$)J1%~^*=`pLDKi~DvRV0mTh8I|O zoGnxr7xs{ho(9@3&-n-?vmZS8&)1h#2F9Y#>xC0HvX@sRXks>YzT|qV3*978QrG^Y5rBG==wY9&n!ZS^j0dth)&ho zInHq}v-Ui!>^Rg3`bE6Q-I!E(afI7)&nBRv{p<1NNyyhoPct)LHfrH@l7jw=&Ap^2 zLeSy8&t-pLtwq)=q>N5JfL%GBFd9bQP|kWy*T09D%=7yuGs~}ThcJT_sQq&2K-pl+ zs9xPoJGR2AQfG9M#~SG4H~76UmBT-JDb8DadD__cdf(aM zbl`Ga(ZT$8KLsZV)r7t6d_ND3)d-u2)HQkY`y=CklgnU^AFis|T>DiNq@E1^ZY+a( z9bt)sDGV)XoP`7pYO}H{Lz&3^L6z;<-~oZ%O21x$4-?y6@hc}GI5(AUu*+}v!UmJs zr!Zafbr1IbI5iXZ+`xX*i9Px}8=k}4GACnwIWu3U^)}Bi;2o~+AhF#a%lWZ{myN64 zFm~40Sr)nwEsV&+Lsnnu+nNgw0J;VvQ7t2xhsfAFXZy_CQ^veY;sKFDG9=Z#Q8KvK zQr-X~se6a)eU@VbByT|aj?np(T>lC6O9Ov~?t-Uyc+38uXZ~cIYYh?b{N@#(;nX~g z>kN_mx!oUpYWOhr&sVrONOxmd?v|(8&%2`G1BMibZ`DfRZ>&}Tl47*+fP(kop~8Vf zB4q|jQ*}z@f;RM37Gos7hYAq0wC1DVyiQd}RZcx2g2FEpQ8TBB(&!ahCJg$~(@Nag zmrrWEtd&1%gd#oF5$TELDT;ZuO1@PZ^Oe8gZnBlMJBPglL!xLuPCwmf-T1#*2qSTb z?mQ}5!WD2D3iFys#XyZx?@tWKQyHanWvwH~5oEACR^$29Nm;Xb99P*1*^U_wHOT2^ z-%f^Ec%D{bggh!y0;5wgo;%-`)#uOQdrhWk3$xQ<@^dQFe}9cgb)J%Ssv!KG**V0e zuiKvqaOT*xXz+d9J%4+`k4p4E{Beg`tLG0Cw9?LXRTpX3d=4UDmw-AUl&~Ch!c9&; zHfOrk%3xPvCQ~jf+Bw)BQ9zHx9Y>w*1A`<FqyhWn(XapC8$c4yU< zopI`I1u$98Tam`(K&_Vfs{dL5^E1D~fH05#33$EqVI*wr3XE)hkrx_GzIz6a2qDJ$ z8Lz)AJ(gVQzcV--JCDaY{Cz)07buJyI|?6TuFzF(R840+e{(qZ3#74$hi@_AjxGZ> zWWEbD8&3+K_BO1}-TdCKv2eJ`ZZU+FPrEEJO@>VH zkmEbX+v3j5@}{&(D!LI4`ol|SV#Koo--H{|8$x`4U^IqBENlEq-yqInaOH(~wo#C) zxBQKm>xQU%UUro`_I>(d?xe}b@kDBkl;p0!q?MnEK2v@KXXX9eYYbZ^1hvcGWq~HE zSKTe%Bbz)|VL#3-r0yFUki<8Do(TGMn4-Ye82@NSq1x^C#b%g--^ipGZ!meqnfI*Pw*sVqmtZo) zE*Fv4##pA)8?{PvI6#iwo76k(S_2tDI(K?V_^0##N%YIa;c*yJe+dxAk*LCnO$nIHd+KN}15bIJx zRbdro?R@Hr&-K)@o%lJS0*QEt*ISApV85*Cn$*2Z!N%>K;qAl-r8pww0;mByfwihInmYOQezeWH>$RRy1xxuC@ zxU~z zCEU6)W!oedfoo64@4Wr#qwR*^T`c#Ko?8Y<#ag%()GQgxZ=Jl(>8Q52bK57XLw)Fx z?qH;`Y^(H~LmA2&T)=`WA&!V-?qP8wxFCt_Cl5`A|EwAn?kB&Gx(oG4?+T5!o7Dq3 z-Xyt7BWBkm0B^+aNK}joLvn5;iMhu*U#|E}I+2kV-dFY>O!_4iX~kw}&}MNTv)cY1 z4&8$6{%+m5tJI>?(_% zh|w?pk#F{*2IqtLWdx ztS|?e$fZ}v+S7Oz&tYmkW^S{Qo`d|+U;Fs|cOBpQ1bk|}@b3%@i-NKv)#v%Yo6-Y3<3O9sB;?9wC!^wNOym0WgX__b>4JPCp>$M~neDHuXcho_CV zl~e(vpWrf&zRHlb8bD7nn(n8S9Yjo6E^E6;8h;pd>rq|GDzNHBHfDH$NB>TS1_c@H$OjZX1-ruGOO9%@pn4#HPEj@i}Ii zVaq(Sd@)w8wp`_t&l_yhgd>y~@S99O@qdWrE|l7_X%DMb0mW(=z;QKmHE4wnaJ4mz zth|I+3N1 zb{Q*hV*L@H&^XL^`SIxNEWH8HvpjxT{V6vgpt(~M6j~5e-0ppRE?502h;_|u*pEO! zGltTLs0&aC2~DN&!WV7aL2(~+3yx2DOf4HYwz>T$=M$VZa|#;>d?ps z+Tup5V0tubFa;5(wSR0}uI($(0Yq_f8*zx#zV6X$-Ab^`^}^!v^VQ0>W2nXb&c=5) zu=%gKCQ1PLw^nKUZOw=IPU9JEi4#a4&fX8Go{}F!OzI%jx*>-#cB-}w+l)%o8RSys zJeWa71gHh^lWbj^|EV^f_&4ZA-SBZj+Qu-`kyMcjC*< zSoP4;93(~V`uKz%f4}{Beu1kh6fb$za%b7LcHdK!}Q*f z%>J4O)LGqvBz3g0mpX35owbpg{x>7Sp(!$h_DS%1|Ksw~&kRz&Cj1qneWCF^-=Df8 zDIrnsHESf+KLR_1d?ZjBiymu+S%T+mK3Uh!gzO`sX)^rk$n&8>Bmm`beF-O9*8p&> zv5ZCjZPnMI^g>TBp*c5=gG6;>6b;@GC6J3rRH@1|-QM1RD3Xm^G`r%8XnD6X+>)k0 z)!9?x|K(J%?ihNapMO3Rr++>`#))e>X2y~xyAQj?l{4Bf!&ddEmfea}EjemcUC_U1=K{58BG0cSiPX=&m!b0|>xz#q8uG!^aV%gq76O1N@Yd88 zP(|`?`e&%64So1uf<0pbzl#WpaUr%rj2n5)NCa(yKJGdP$Ku{})((9b3{rS@06mCq z{`iPk^xwGPSB!^OU)!+iyXO5HZY2t@v}%)E zS>**W6X@RCMzekbDavang^%{r6<<&o)#FbUb6C&a*N(fK8ZZj@y_KLcIJsiPfAE_P zro)X6I8)b2&Jo^#Rk8D8DDd#4$b zMIUxC$h}o|N-Y~$`s>a=8&NT^<<9Xl~<8AW9Pe6Vrmb z+)Y=P1D0`ODOc$cOJc$MMw4M^nnU^c1k-stDR=oC4s##%o~bj9el@TFEJyQIL-W?4 z00P0pT}#W#6A={WwH!6pSzWX5crSp6*v&W)&)qbGhUMd%qO+CWU=(Lg04D-(4Og`V zd9L=(`GaKddjB*W5>8~zX{L3+0RMCZ%iCP(z!UNK&CGFaf=^1myoz03;xdyY6Mqf) zTCQMIu=fs5KdI}I%6fbh3S3CnPQOT>+LZH8W2K}gCsOX408OHSp7GQiL~V9c7BWBl zIR#qM|3allr0F!Rpov*zz<0IgeOpD+6+1%8Dn{bvku$#oljD-DDKaH#Dt=5r4|nBG zdfNqO*-X4+=e1ATS!p>Cz_OPzgnWI>9Qh4=Xms*5pZjS5))mxP(^t}tc_8cIFA+m2#lRx=itX&cRu$8T~W=7Z?B3+K}lOH(F8!t9Py*8Ae|j(p9Y6AuVApuvT!v-M?8^I%ybIapD z=c+`D#%>RH*_6~Bpe@W_0`toHBg zzwz%yq1JG6awe9mHr3M4!NB8Ri>T8Pf@qHQjeS)U5c7{&pDFJ9sA4@EX~k6&KkVxs zI78?2vA%HSO=tYAdrHjnSyLe6$r)9=^|1Z^f~cmF-$nCnh|yS&K)-?A@aW6KnJN)? z>JJaJR_EV2TQM0q2Z$A(PgZ>r7$2c%ZKdqi3k_O8CK6y+v#KIUiz~Hfeo=9lr09&W zd2?@83tULt5OTc)C$ev%b2=cjFg_@7u9|j|i)G**FC|}5tIq1RlnVu+TB z8%te}B>@G2xHNV9@5aI`uQY6?i@5_=_i?Z{rW2^sd(&g7zvTM-JwNu@G*3*^Lhy30 z5ewHnUK^;aXXlYbW~D?KzW|#I8apS0Gr0%Fn0CT4hAdUO@)nQl=M}YDX2xnP60_Ru zNn>`mvg~>$T(&!3ek3)nXT~tt^=2cMmLC-uu_7HjQ^OL8L*8s?c_r>{@)M3YZfO5CtQsR+C=M+TBNbHyZ^dBY+c1mr z33u5;Bs2`BqSw30aA#;a*Xf@hjl4-O8Em&24JP_zNN~fho6=cG`@7OJ5NW^|G*`~E zfiPu(({spSKf`dsb3R6L_KSPH&TcGAr_T$l&zw77rERPqZR+dv_VQ>P&c>VR*<9~4 zYfW&@#cJs)z!UWfy-hL-I46n05$gG7Qx;Hyo-C- zsbNLdna`Hl zYv)3kMs8R5Rzbbl+uAI4ZNTC2H&I?HqT<=31D_vkdE6)aAF0yOYI8BI`ET57wrPqz z>Kk<5LXjo6a?q65(^HFx0oL&XP6I#V+Xm~s`RwO^d$GPCHu&9TkRTn$?pB6XQL?4R znJ9p7I@+q^DI;Giuf}0Wbv?$bPEgnUpLzR?0sDd*N}CCnP`e1{erWw)GKGVw)7GuYG7M#6?%02s~$ zS5eK0@8P!rlFKVqN$kb3f0_9Ok+2*pSBZJCy$3cUkNAvwX7t-{fcpDchZSQA1q~JE}yQ{LZ3KBF04XbmI8+f03M>VrTgQJ};hfq8} ze4sHLt=i;Fs5gFm%Y$Eldq|SZr)=ZbF@TV*oKan%W`!ER$z01`6MBYB9KRFijr3$? zA^N_++24Ls?nV{m-Kj)=Ep%JXGS=`MPJUBKW$6DcO#45FkFUycGC`Yt6hsvww&|1c z<@wCM3buV~oC~zdV9Eh@CZelO!N;AH%9Db4uF@_Gzl(_2nI-1m3i*wJGCou2^{a3lFEwn%e z{@PaZ<&*`I+ENn$B3e!A@!FS~-&7(PhPTx5&BH30-p&(Yol>m#lXYf4+0B!WZX(#%p8kWE}&bVSb*}i)VWcw6d&7<7KrQ6qy8b%2m2=f^JxxDgX!o zrpJWTo9v|vm{4?)1;EGv40e&9Te#^0ZZhc@B@!_OeXHTBT!lhAU+?zE+L4j{ya67P zpuNbUS}m5YCZE69lnAeImCwGJ!xZs+5oHTkBQ3G-EeaFTbwOE1Hkx6vtf0gSZeA7% zJcEMVi%h3pT2QuTTW&u~{lL70UyRbnrl+qTeTR4tzuUzNp(! z9=f8ZVDoyw@~7F~Ezoyzpq(Y%&s!81-Kl29Mh zQM>X|E$nHKYB5)m9zrdBft%XsHFzv~(xy666^YVT?SG@)*EW7)V^DK*ozC>t(qi+Q z?_0dK@sr*HMw5FJM|)>?OX4x7v;1gZ$HWyaM{2z1oz`Ov$$&n(t6Q!^bDK7)0G#u< zFnLNu?DMlPgx5wOHRZ4PoWtIMPE^zj8dxRVWQgTExRXqUrn`I;7YZLhLl?~~ zTp)z*_DDhhoiBT8_F+ILQ(hYa-UM)DRrgzPHKq-$QQQE#ITZRgr)wC?w`H(K0y!*x zqLb|L`?}y}z_+<3(SM$h6LIb*>UJ8)$rhFo(+b!!KwiT7uX$kU#9#l0RX^r(sV6?m>wwb6REx{KdKK($fU4cJh?p3B0@ zaE@4J=KzSRw;K^xwma|55XxVtF`8E}weRBb;_;mfLRkP;ga$_CKc)=WLV5gNg{jEJ zF+{R$oKC8hr8?jV$12&GFv31t8QPCw*Qm&hI8eKF825ZDaEG(@F|LL~ zFP6QM$t5oz_B)S{1iUM7vDEYd;mDrv}w^ zw#K4B`e%wVwRi!x3j1|&>$#83yLi4^HI#I0qVSJ2S#NA;$1G?8oaA{Lqib1`^9C68 zXY7G4FiKo&O5Z#CC3U+Q3vHOerPD;8WV)zK-`nSjI%5E~qkLJ;*?AW&hz@%S>aEe9 zVDa0}gqUbcalXiuEApQBcK)E-fuXuwt4BVVZk(z zJHPa|pxK~C=}ozulaGMHGIwpN@jya(&``vKZ=R6y-~~VF{hZDfo)V&H71}~63~zoV zVtw>{c~Nipzin(KD3|g)^s1%mJQM zn}nS*hfIaz>HReRbBR1e9ZN&0&Pv{*unZYZCZk$u#^~r}7No%7UtTV9qc|QH0}O3D zKreyWsXX+-;~rL%s>Onj1mM`OCiYXXeDhbWLiwaNcW$Gk7i3Dpwrk(@nNvvIo>{+R z2|FUMS@6b5YErUBt30-ZY@*y}nJa{^v#KS+#=4yRX?R)l-X*_PQ&cMgu? zepsyP6%Duk9S9Sq&{N~QN!mkmkJI_4?>Dtk#dcByKs(EQ+Wo~TPa_B^ir=xyT;Nj7 zwTk*Cj_*HTL98!Z>`lk|{BsC}zpu=!y^~66ypbz_Y55--W|vVI80o&T=qOJ-6dXx= zTG>*{Wm5LGS~=77Xx`h=M+L*R+@np*UsPYjP%`w0`j0Z*>cu+!Hw z5P-s8v`N_IhL6~YLDVzYejV40Y{LxeCdZW>QbxLLIz-Q^K6AevkLJu^M8Cu1A0o*2 z&byoJ?Q#&26lFcG+mIsCXWnDdF1{r9swH*_8j`%JpmQl`xf@J2K5!Ag#6&B@VvWRO zce|kh=F@)Za0jPK7+w)S$scI`seF@ExBRSCz86~2)0(yms^A_;Fku5h6mY16>x>GwrA*MkZ?WYxzPm9ckE7=9`__(CLyyXH(>XF4N{vv8 zviiRKHEg$6gTrL=aNxHO!TD_3#*x_P{`7))4Kd@?IKL?>zE&gUd0W4a%eKtzKiGBo*#3LF33lqW**d}vSu5iS5|*+Z;- z$%7nEyS8!A*lQ{i5vPbbT?Yz{DXVNC8)~95-Z#HoI#WxctMGm_YmNughiqeS*Ig-B z_^5@fR`j^9bH>LUva%lCLP;=1t%i2L4jm-`l^3(?TUoQerr*n@rfbj*>wubxErsxm z@a)$Fo=4axXA}052>SjSOp*o?V&Y-x*{2sm;cFJ9?l=%@vmsY6%Si1wFB0buZo>+k zo_Uz_yhRvG`IH2Jl1nRNrG(OO+Gh^BOP@vpsUXFZ%RU@isW=XL3C3<)zauga#3~}Z z*Uyy|9yV#}+)w1|7ub4j0>fVBf%DxunnWj5c9#O;fG`oR&bJPulWt{@$IIoJRPxFg zF+PaBzH5a=)Amoc0UA6H&<0?9%t$9k0zEZDX(-26@%~+_R*VX^G%rM#Lnj??ujgG_ zwdMXy2QwzgBb9fRqYv?KmvAiB{<_oiX-2iK(SqL9Y(U?ySxf5_L}(Uu9HUF*&|uk! zG8w-C>n>vJ>%t7gkIkidqbiIW4!wPon5zpp4$($riTrUNL|~X2L};9I-gaF#Th{*7 zzc2iGEq`|tMcC}oNuHZ6d!AjI_qGaXsM0l=M3-|l44#7q9nne&lMDC0Mh`#b81KjZ4qK&1bYxyZD?8jCP1V4mhHUyy!X4eL3=E3XG|GWMb# zHzb!{pSkYoa_}?a!`704FQ+=jL0TK4a=Zt|d}_Q<4>pX8)TNd8X6O@#a;5A|lE=q= zJtt%$l=SC#-n4Z0^Vy^0OEj36qK%4vO_`WWeHV$UXUaRt!FM_f!vO%}TUtMAv^XBB zA_d|LN8vozdw$kGyBh4!;5d8I#<+-yVWp49%j%Qyo1ee|VTFzf5S`q!N9qFhNbeJN znY-E$aTG076;*%H`N;T>WXdBGU;;qzF;)K$rBn_|zA^sQpsD^J7Auq|8W7Bqf%_k7 zDmD}|)+}X8P5DPFC4uryHz?%ICI69Ht0kZm*VM1kX0-n}rAScTDi1J8EAb!e^dlA& zjr_4>to4uP+9e9@`2TkGe+Bq|EDKrmz5a3=Y=*@a*ZDfD=l!u&L3g{uI8w7#_xUes zi}J&kG|IxjCJrV_CZ>AN>++YE6UeLc)9o-RSGnJcHfS}pthksiEQ)wqa#h%VEmcV< z@CdA1Ut0VVC=9Ulov=XYbE&VnD8O{cf>Ds0sr#fLH~QCVrARt@vsWkE(_HHLuE2D- zjtjbU7vOPK>PFAoYR{VY@5VEd_B;3jtF12?O2Vm@a z?eX12x$!*V+LK)xJAxnfK%6^>mIv~%mgkq5n}+XxPd-Lm4C9b~_WN+!pG>H& z`1^N>>5Gl4e=PP85%Cyo_jA9iZ?thc1M=`N%<#@vvJ9FHHr<~4pP%{vCVM6Zgm=M= zg*dq7dzqujkl3S?+-QpO?7l%GyX-{I(&S@yNb zMo%Tp1_z8h%BMfW#2vn^(}aU2ekU+Is>gEn?YL3`9gI%BV2aA zJlqDLU*Wt>wbmFx!<#qYn^pppW^8G-+1PNIq5-8n-{GgtzhdUYT)_Pq+nrSs=pGd~ z4KOD8H~-LLvv>HFz7S7or|5loOMqC#tFQ2zZk;98-Q(uJo>*ZY`fazCHWD1C0U=Qi z*GS}s+aJ8%#CQMP&|m^#?o(Ti=g+g*XcHu2tf4y7kOup}{p38}B2oGyHYV64;Brpb zM^LZMF}!rp&EMjoC2N@8r1@ris8(07AZ<@N2Cy6K23JR*>5#^@5vt^6ljSJMMU<>ihRMmK`6$cvoNa{z8-O-mf9h6*EJtb zt+FvP6Iz}u#u20f%mEpH5_`4u_iUp9MEbkW_sda3GD1KH z+A1hLLD7G{-Fvgf%u?|xLK{}>xo8#x&f&pz-nI3#VStohI}K0P@Acf@Lf~d14guAP zvm$U1)FlcJCqir(%lu8_Gd}X+;Xa--g5t#t^yFa?o@}tQmwLWL`$b-ckk!!x7*X1d zsGt>2>eeF%t|#L7(~%u@b#+eW<1p}WIm*Gbe65Y`f?x@E0v979uc0y(f#PxN0WS-+ zZZZy3i_(#i+MN6VN>-48alvb~ujUytefGH5OK1YZ;7f*bs={azJc_lTPy!AV{x2>4J+f1A@; zGbb*t2VqJT%%7-^{0$Gj?9#B+^Mr_~Uv`vc-F-Beq44`mAMPd;5?!@we;6U5(O%>{gLJWmV-6U>9KL<}@n-Gu5J1bv)NfOAF~M8o(QX zRr)0g86&XjMW#pf%ibqg2(k!uFTzZnG{)QK;HbpuLdhg_QWQ%-P~o7&q!d&{OJ75F zks|>wR}UPP>q6gkedq^ZH;QeSx)4JA5H;W)_WBsBMWN-mjv{~5DFOKSez0;mq0c9- zeMi=pi54|90vsTq;9Kqy`$2u7O$&KsEE_8Gthiu`nMpnfeA=9!aL@^5pEUu zCPLlsGJ`)zoR0}cuN}yhM^ntwzvKKas{0;NDy-{}VQ&h35fZ8HD>68xm3++`7v$tQzqxt~ZW1V0)#?!L9^l7d^y={Q~c zp(ZOi)mYkG6ZUc>bQ}>N-F@B}j{M2Y^)?QTc|%W|dw8V#C{6o=Ddnw0*byn#D)BnSu^ z&EkH2Fga+>aDF)3j-L$f_U@(#UA15*&y8e)^`Uo=xxGzfTq6aDS#N`vmLE9&jN7|I z9+?o)hE5mRdzZ5`Ka`caRp>Umj%B+V__ssKD!+bU%<{N-pZs3nLy$Rx{AcVKLBn~- zOCq&&+nb+Ez4fOy&+P&B78ffu6{qCl`bmzaT9)tKT*;BD5=zPxEp3`swD)K*sm1)n@a*A4vGUZsyE}@!B4?z;BOAVvde+B?__C zFzGO+#C2#QVwO8$nGH|1<8I};8S_7)gX?edO7fVQ-~S!Rq7(cv%aj^Sm5z%H<*|AL zC@16g$pR)ImbcrZ(bDmx%h$Qy*s7cO$PWuOE{Fd1ZH~hj!gUfzVk+gL%K)C_4Xvd@ ztBNt6?HX_gut`J+yIiaNX@pErJ1w>6`;Ily2w)F3($SFoy$2sQG`0Z@WqYnHn227l zgR1t;yp`fntLc(^GGQT}Q;eXBR`<8#I;+=#Se;5M@9*vvKrB&;u-yRtups^0-L&g< zFUAOx5n1JQ?|~S{l+*?hgOWLme)4$2cjJ9{Fhaf6Y6hRbXj{J3y}V2p%UkgpibV8( zl9w0Q4n$J)J*jrh?KWx~N429pSlO@%fbu4Cdl6smpN_e~dPK&T2``(iXPNBI=JX2I zVQFX{<~38EM0{#{`Pookx=?IfiZ?>c|$osEp|5~t+FUKS0X zfDS~KG7HsL{4Z7Y?Sc32-_Op@F6?;D-<=NQGr!!`j(0pB6h$2!jiC{n zlL|yw2{+gOew$hH%(H>$s2fUvoro+Mnydg~1tt9{FabiLs*r$Uw8xWLbc;MvY##r} zb3!2!xzJY6rPT#@7<6BLJ`KC2VWW4%?9ruJT!I*k32ETBmmg`xe)p@2n)qpqm3pn^ zQn4Qx8ShUPs?El8jTMd;+8#6T4Sdd0G=8VE?Vc{%@vo>NHbDwrZy`0=%}uzU1)M2I zEnZgnDv|z~7Z!b2lU{|PVE7lzfR0`yGEY{~TCMS1KkN{nX1(*Z=}ridojcEE|6GA` zhjMX^5U#dnGMazE?&QLt!E11mM+d8U^cOoE6}6PqoYm{L>x*X3;Cay{)m<wr7YlbIBfbM3BQb9V|DmGj zi)4XBu?^GCz~6&T20oY$_!yad@88q%^Ru$ER~U)6;Sl8AoSeXQzBc&I zeY~N>9Ly;tdA}k(oys&$#EzJ!z^E|>C2{USZ?EzDct}xm+`I`4m6oxtRA5L@CrlQP zUd9XStLy5je+f~Nbaa&b{MpmUXc6-I@=93P+uX@g3KFxGGO)LFa5E_Xz9@3Uqi!XV}E6> zWK}_gihQT$;cts2c}lT=V+IJEQJuMyp+q)M&fh z=<OSmhKSHF3K7${d1U`Pr6@))f&y{$PS(Zz3dTy)3&Q`&_g z0guvHvK@HMFRN~DXxQNYnjlq~Hd=QZ|7NSMh{hF2SbHuyv(H;(g zL)3K`AT;p5BP`bF5rox?FJ>i^FcQ1KH}atXZZ~2^bpm^*On3J&p!X^lA64po@sD%a(`9R_zoFSe!#zr|Eq=HgfCHhT@kG!k(OIZfolP)pwl?Iugb z5?h#?MtJ6lnH{SS{kBnR%f;8b>3+RGXJ#IV-C%Zb=K#RKnC|>fp}XLL0wxR|qN^3O z4#n9~c7GyGum?yBwbJ^Wuf@00E56*8Rc0oq^@@k2cKo&o^?R2Jz`k^e>ik1k+P01g zhX4LbNxU1f>tO9~s;0{RmSM36-7L08GovXfRgB@@-?!ZyR3nsim8-Ub@>#PZtpZ!5TmdTCd(zGlN)UB%e4{Mspa+Zd0B*zL*k)U>|tT9EISk};H#9i zp2kg+I94j$0a8Aavf~BCJ4$sdxr{I`qL(4g$YI}~x&p1-*P5lLwLR{DJ+UG! zRjf@Y)FFRZw5s$GbQ(r{j^5WTUjLZwgpo-pq@$xTZLn*H?zKsyARrkHrXc)Hp61QF zNZLp~STW9Rt-!)}3Qm?vmhzXPszl^Jt14s-Qm>%pG!Qw;t;Djz$8nSgqTs3->z^z&3yoYy97>vHU2X@*&&- zk+*0h83+&+Mh(?g$bG9XN(F@HAzb6^Jl^tpSK-j+fryQX>={)qArcXAzlX7}v?}|w z#(wLI*W8_&|K)%)$L|TB!QNA~P>WjhhtO<%gaQy2o@|Z6KoR@1m(#{PeUI*-KN;L>={b3wqqUdx z0=LR>UdNhs$(Q)H`_#WXT28G>w02DPzp;E!-aRlC>E8~%6Uv2@e)ws2?^xCH6kyQ> zpqF%qcf=%=6|;g+@2ivYZOrv4hxi4PWxR;PMnMe|!|wpE_hd_WUO1!sS{TAUmSFQ( zFJU$|cIg%WH}!Fd*hL$v!pAZh7j&YXee(N zCaYi`WDl?~Csbz<;UK~#X2Ul(E)P8p($Jl{Z4%`0Pd(DF@{AE<;LR{1e#RGgKFLKR z_DSr@-299~XK0T8a;}_s03SgXaQ5<-oNGj533FV$xyTiRF*NeiW3Hzt0a?H@k~l)k z8ph`knKce>Zbo`(7e@(<-b9-WWaJPZ{+`J=Sst&Y~TJp3r6;R ztYcT%vojdVmaJtBS+a$q?37XVJ!DUo$YV*$R<F&1v?66jd{ZT zCuq1mjNsW`{PgRje z@$u{3NpcEvrdBax~uiyF;#q!n93VV2R_uI~_ZhJh`^Sw@h;V4`H zR647J&sXKDqdOP;>qNs-4#ihzIdNetbXT_4khA@rjrZe1HkF+5UNQyo> zH9Nb5sJ%1CGmSz?(|R`cR|^)9+MpMAw)xqNkX-A8cShVQtjC>4AH1$*ph8dg+dMct zae!hNhtrjbmF>M>+XES5Yf+FVe(UwsR*N!raLG!$8ppMc$X59B(#n%3SPU*1&L^jXCM?=Ey2 zTH2E}nVQvgy(@mDb<%4yO*q~X%@p4iq9W&2k~X<@ZeEmQBn|V=xwElM^1xz6mW#|H z@pxNJ>lT7T!NY%dz50cmPf;~OF*&ng)^D?J?b$OgG?T(No9R0HaIMgF{UT|JJejQU zi^7HEljyk`_tEZWq7P#|rkjJz-?!K`fDvexJA;dc{GLFRWsTG?-0%H& zFCI=T5Gj&5#*4ge#v_b^^3>gkPLYsc7O9JoqUM&J4UK}e>dU#pvUhG|q+nG==8M9U z?eZFQSNBa#G}?#jJX-8J`p9WG<@<-8i9nCy`gR5B^+;LOOYT>1uZRFLKMU(t&^x{D zUkJMt4{%4jThS=BS(!R!0i5M+Y+Y0IMAf^g`@`1Mp_ig`1z?=20e@leAHQPOD&mscgDQ&VTe~HKnzIMX|nn9vqeEb zQu1)h3EcDiL_0F^l7KkkDnEFxN{z9y`fN8R)HgH|?Z=Q!@wDw;U$Z8(og^-w`}(v9 zFEyb37N#?Ga&lLeW$q8NJbR{fe7MLHaQt--x`^xO64d7S{+&7vdl9_H^4^|e zn^g}*FUEoX(gaR6{Hdf>BVmq7*mqAcZ2oujE(Iq|tl!PvSKb2|*!!ab#b}v(AJ#U% zeMGH)3F+EfL;gkk^ZZ3IF%@6L(&v`D&#Sra&(ueTrK5)3CoQ;R0&IeG)9 zuZY-pQJ^YcD2xb`4W7I|p7t0OT%nVd^KIy*&*nPU5AeQkqBF5gRLI=4YDU^J1(v1A z>?umH)9$h>X?_cbE#*(PZXL9o=Npk}q+z2E27DoXdq{JTga^ZS639%me{Rb_+aPg& znf_9aD^D$xQ_9pU*ZnrbpJOY|1$R6MTUIj~L>I;joL*~+pL7NcE6+19zw>67oaBn`t zSzK#|%E+j2g1Zg|O4Rf5j3YW(VA>QB-qWP$=H+H7n^AMPb9nYEdf!kDY11``QVhdu zMh{^aznwhg<8Qc+N|Ri2Tb8=|`0^BRJD#q#jUX1QA0=pK6sMSV2CJs^)awd|nX!29 z1}eSfkaZhtR&sgV0TfW+46$t5Xciw(<)j58XrbOGN}T1-VQ`P_(IO2M&sp$lp-?<) zkRNgNuauj3Rp4b8MH|?O3Zs-4TZh%N11b^ z03LyQRTMd_^?*~}e&W|Qi?e0&(voF;V2w8srz4s1ka8uN%j~w9NsM#z#pKi?{&YBb z!H1WflbZ#hN>w-Gd4La88}PD9ss7g>Uy`x@<1?KUU`!}a9O$BK!_|+pLp=E#T z!;kX8xVZY%U5Z5C-Efh{1$e6&y3Rf=nMtmT zPr=(oPkh)3VHFRkU40<8*`vdA^!;ZOm5@4dtHRtiWI201Q*3P^wqWE$TD>xuuHY?~ z%*GS+6(@AMu#yWzLw+Nz;=^#d|)m|(kuo62ISvx$kBmDT-=%~!*@ zd(VAE1{Tm`VLCB*vd<$GAKo%LGoj*Jb^YU6r5L3E`Z&6XIF+}OG17WCD^PR8JGbxp zQzHCg4S|eXez+N^{5`v0%eh&@lp>VNC-$boTvw2S7+_R%J4;h?J=)}+xtUd&t?DyA z;B-AdDLZ}4<(Kz{aP9ue3uy+#62sdBe(KouN0GihDwLFzv3*iPU+MT56wcSS9qOX> zp$y>Ii(X@j*(?)C7q;#+ZbD!@z}PNrx*9CI{7DH%Vd0}^-g6&$bh<4^kOs<}8WVq` zk3CnUoe1S`>7r@BNcmmt2SS`uEE~q`TE_#w`bMP+3JMGVk_V6|?OoLUZEz6x34^(7 zp>;XPGD?vjNQ_N>16if8FQ=Q;s6ywXJO{D$ZByF@SKiG(Mrd$pGBhAB!QDUIzZW>` z)1=xIUKIJ$Od~|~!uL1}TYhM*x+k`}!`_Ih_S7e)QtZ;+GuTKP_8lpeS?ZgG3KYx$ zzw8Qr*08c=0ES_o4s_1Ost=-@c~8`f(%q6rxD{U8kCxUwSQ!S_Tismqwm)2(w6+3` zb0^}grvtbVOpU$!dJkjYi_C@R31HY#9*AXMH-<;>Fo*3Q=;HdNz1ir`QB}NK_!7YO zXuE6pa`ZfHhp#~GSCc4A$$%=5=}ZSi!LuoH!i;UQW8f#CnBbZA}=F+4si4$wGh#P;|5Zld~B_QPNa4AtQGEYvNpk3J0PwuiOw zmDx+5VAr$>ir;Wk)zwy*4+{qug_MNI80=*#X)r-S?|Ui2f>JQD-~b^e%G#b?Qy?V; zo2f#cL&k`kfhE$(@S4-ldw5F})cWpm&8DeHliM#rcRYjnJTV0&&Y_G5QoqI9*g5~H z0MV{~Yx04ZrHkp;vNPcPdc5x;6SNiROPsR0dRHGq zz_aaVZaJ%()W?G9BPFF#Co_b)<)Q*WlPjxt4-a_6GMP$Mjja?O0`}zKFz~+>_E-df zr96#4>@P$6!sd5W*(sMsT_Jyoi8`lY!Py_?al3sb0}ctOSykPv5D&a_=gyN2&pm)q zJOr4crfpLQ4j(gTEg1mK<~9d)4-(=QhHlTUdJ|pS4^wV2F*Ll8-sDGD&}@SQo;jCz zGNvH#fUXoWK@JM)rPZpO26#gWOR;wc2n&u5fFe1)2c30`xFijxrD{4j%n46K0yr-G zULMzyLhfieiw#C1OoI2@nTESNEZu^g3IN?!D79l2z&ckd>yVnE~1NftI9&-r;Z1i8}r@r?Ja1Se#ZS2sgHx~}2Z-5icVQ4=__ zK~uOylJ+s%G*1KwqZ)JDwQI>6Q6_NNN=!a&2|-ns2j3nm>$+ar+gebxu)rp45KPPu zd6Q;SJl$Y;pI*_s``R}&sfdN|6Zb}8xqhxX+e&feR zT2%es*Y}uJw1Gkg8&>p0(*> zDs>mf>wK!s$cY;Ifj{Zd+asSkne>qc2Q(o-e+8Bd5e4LoYf;cLZ_WM{Dr)?GZ`XCW zvfW$CzwAKvX#eo?0<~IET_ixq7{drMfnCwldV>sSzzjGKGzZKG|kw-a7?>zY1#TII+nHDj9nDqrogVR2Yn9QkR5d$f3rifizP|CHgN=@*DH{ zs{QeM)zPSY-?@hbq7yu;q9xseg33M(e4_@&39MT12o*AMkA%9P*0rl^4j<1QZeF)+ zUEz7SS6JgjHz_-~AF+byJQg% zd+e^vDDucrR?-xZ*T7Fsp})F08*YV&9~@|m!17U_4%p(GrwDYSK`uZ4=`Jad z!S@~k)AP?|y*3->T7B0_%$`lf@QL-Xp~6BxvRK$Zl{PjA z#)JrD^_Dabo^~BpYACMi+v_@pmk0%`xfCJ!lkgRarsl#kzFPI%v%*5>AG%ET6+(Y^ zUXbL17X(SKn4*VPDPFqX4)ni`h(2HC5UebG>~zb>b4%a^Bx`ek3|;$3s$NeLF7WZg zudLr3q|xe;4^8wrap|1Mw~WLFm8HZ8gf8$ylQlt_PFoDfyt%($Ul_A}?Xpg^kwE-O z4K2HAL!g_sq^Wxpqw9M?y zUb36oAn3%KRBo|ZEpwj23AF6z9~K_|bz0okYN^=+RvC&(>FlW_Y^opI|eF^eih(<-aOb{W;S@j?4YzE=)lDoV@UF^R+3_71bD#^ zDJ-87p3I455Knf8ZJRF1iGMC0nl#GaQ0RNjtzs@=GxbJ3mcV^v(1j4BC(YkA%h`y; z%N=Y{ogLXvv`2)K9oA! zQ_s)0C%Jq8EYQJebA-^113U}qBehb`4onpQW?qj!<$lo($p=WHD z66}^qtPheg$UWW)Yx5bBqd3@*MqIck@#yw!qs~_2qLjhFc&&C0xC8PUQ(x+pC%yQ2 z)Ntl)a2+3IYwH;Z#mEb}I~o^fo-@(uB*h!qhLS0ZdERa$$;WP@aknRyG;Nb`f5po7e&pVlhwsb@z~^6#8v zqY*fAOm5~K4&RUd1~UolYCLJi5qf#~!eRNPa{GIX1U4dnVgJ)}E-*cR_i15+nXSIU zsa-Z&l%NJ1gqupR9Sc#W!4rQGjJ1H`)4re}S5F<9T|_DnT!Vfrg0Boan-ezB)Q5j~ zqH}`*>yN`rl#?ebqUDX(@x(Xhj6V|&Fohs$a$GV`JthJ6)Q58ADLhPz5lNjFT@2Bq zN1@;m?F9!GHy6w5(mj#RJpZ%_P3w_r=o%lVssikDY>J}tbL2%%6xSO_U}u*gYV4`^ z#5ZbY<#a_NKeeg^zkr(Wx#1?c_#SfJ*eu-$nV5vMU&z$J?}TJ1wCrhR5;qItwGRKb z)Gi_xv&f?w=Q0SoV@k(BMyjEtw!nS|n3NQ+@*U$tMat(A8xgNhP0sn~A;~SFmlD z;~m4tajfK+diML)Q3Bcki%DKeNB96^sG3^F+NXk(09*xGrpGG?KxhjVRP6IG=zBSypXApJJFI8Mmm zVh3a5nA$_~q37$H$|GdjSXC@8@F*_vsMl85u(Ogq{O&BSaY&Sxy;prw(r`64)G(11z5iy1MuWe~T<$JEG($+KS+U z5r%}ni{^d}a%FK5y*Di=&rhqQ?gEmkUjY(D0%pQ+*y8-aBKMJeAKw**W-|^fp+n+J zOUTemyE7-$?=bf1SB)sS+S0uW(_{lQTXN=jjj zNfkarVBDVto&Q9=j z$AAa(6PWc$63fB2QuZ3sFG5Orv_O~09RAAkk3<7dq92X18tLHkq^b13pYpF({xz_F s-wLTr{nvy2>x@Zu@P8dwaA&YU;o-774%c}>q!^&5Wq9Sarv2mp0(yZP!~g&Q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fabe9d96563785c7d6b008bb3d8da25e816c343c GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^{6Or)!3HEd1bTh|DVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?08bak5Rc<;uP@|nU=UzFz%6x@#ly{E6Z5RU$2Hhw*i>Gs`(~~C zr~2_>(e4Ka`gpa)&de}Ks*u{@U5E@m-v9X3<$3NT3r3p*`<7|@n1Ecw;OXk;vd$@? F2>^8yH@N@+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..a5fa74def4b40d7eb6826da05bd5e12b836cb999 GIT binary patch literal 2836 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b91e9d7f285e8110ba3ba4e72cc6f0416eb3a30a GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^VnCe4!3HEl*p=S^DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MMa)2jv*QM-d<4Ta$*#5x!8O#VbcvCx78OjjCM19-`|n` zlcQ;yJWqK-!X?h+v^9}Es?F+hJ07=b>sdT*QRcgm+^%b8|A7C`|A*gYPjm3$2miRv cpZdzQt0C%<%j~>EK-(ESUHx3vIVCg!0CP)0sQ>@~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/app/src/main/res/drawable-xxhdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..9c4685d6e046ce6c450c19426dce627a88718bfc GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?3oVGw3ym^DWND5#L^ z5#-Cjkf+YTP`sXjk!=$LL!~YQgWnqlM%L3n1JW26goK+9UQq_B4e)ev49U3n_PU`U zg8>io#t-TVJM=pEGT)onF!&ZOd;8}O149hcq!N%?hK6(oZAK7-f#HS|n9?%@Qw{w* cAUc7wfPvd9>y+w~O{pNhr>mdKI;Vst074Kf@&Et; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/button.xml b/app/src/main/res/drawable/button.xml new file mode 100644 index 0000000..462b79f --- /dev/null +++ b/app/src/main/res/drawable/button.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_normal.xml b/app/src/main/res/drawable/button_normal.xml new file mode 100644 index 0000000..cf07485 --- /dev/null +++ b/app/src/main/res/drawable/button_normal.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_pressed.xml b/app/src/main/res/drawable/button_pressed.xml new file mode 100644 index 0000000..83b003c --- /dev/null +++ b/app/src/main/res/drawable/button_pressed.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_choose_message.xml b/app/src/main/res/layout/activity_choose_message.xml new file mode 100644 index 0000000..f9773e6 --- /dev/null +++ b/app/src/main/res/layout/activity_choose_message.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..d8e6dcd --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,86 @@ + + + + + + + + +