diff --git a/.travis.yml b/.travis.yml index e46959f8..ae8d40dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: android -jdk: oraclejdk7 +jdk: oraclejdk8 sudo: false cache: directories: diff --git a/mobile/build.gradle b/mobile/build.gradle index 74abfabe..e1c6175f 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -12,8 +12,8 @@ apply plugin: 'io.fabric' apply plugin: 'com.google.gms.google-services' android { - compileSdkVersion 23 - buildToolsVersion '23.0.2' + compileSdkVersion 24 + buildToolsVersion '24.0.2' applicationVariants.all { variant -> @@ -28,7 +28,7 @@ android { defaultConfig { applicationId 'com.alexstyl.specialdates' minSdkVersion 16 - targetSdkVersion 22 + targetSdkVersion 24 versionCode 57 versionName '3.8' @@ -67,12 +67,14 @@ repositories { dependencies { + compile fileTree(dir: 'libs', exclude: 'android-support-v4.jar', include: ['*.jar']) compile project(':numberpicker') - compile 'com.android.support:support-annotations:23.3.0' - compile 'com.android.support:design:23.3.0' - compile 'com.android.support:appcompat-v7:23.3.0' - compile 'com.android.support:recyclerview-v7:23.3.0' + compile 'com.android.support:support-annotations:24.2.0' + compile 'com.android.support:design:24.2.0' + compile 'com.android.support:appcompat-v7:24.2.0' + compile 'com.android.support:recyclerview-v7:24.2.0' + compile 'com.android.support:transition:24.2.0' compile 'net.danlew:android.joda:2.8.0' compile('de.psdev.licensesdialog:licensesdialog:1.5.0') { exclude module: 'support-v4' diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index 86974324..ab5fdb06 100644 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -26,6 +26,7 @@ @@ -67,6 +68,7 @@ Created by alexstyl on 05/02/15.

- */ -public class PayPal { - - public static final String URL_DONATIONS = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=M7V8YHDL2NVUC"; -} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/about/AboutActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/about/AboutActivity.java index 2d79bdd4..1f0bb2af 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/about/AboutActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/about/AboutActivity.java @@ -11,6 +11,7 @@ import com.alexstyl.specialdates.Navigator; import com.alexstyl.specialdates.R; +import com.alexstyl.specialdates.analytics.Firebase; import com.alexstyl.specialdates.theming.AttributeExtractor; import com.alexstyl.specialdates.ui.CheatsSheat; import com.alexstyl.specialdates.ui.activity.MainActivity; @@ -41,7 +42,7 @@ protected void onCreate(Bundle savedInstanceState) { SimpleChromeCustomTabs.initialize(this); - navigator = new Navigator(this); + navigator = new Navigator(this, Firebase.get(this)); MementoToolbar toolbar = Views.findById(this, R.id.memento_toolbar); setSupportActionBar(toolbar); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/addevent/AddBirthdayActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/addevent/AddBirthdayActivity.java index cc5df3b4..907ccb6c 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/addevent/AddBirthdayActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/addevent/AddBirthdayActivity.java @@ -9,10 +9,9 @@ import com.alexstyl.specialdates.addevent.ui.ContactHeroView; import com.alexstyl.specialdates.addevent.ui.ContactsAutoCompleteView; import com.alexstyl.specialdates.analytics.Action; -import com.alexstyl.specialdates.analytics.Analytics; import com.alexstyl.specialdates.analytics.ActionWithParameters; +import com.alexstyl.specialdates.analytics.Analytics; import com.alexstyl.specialdates.analytics.Firebase; -import com.alexstyl.specialdates.analytics.Screen; import com.alexstyl.specialdates.contact.Birthday; import com.alexstyl.specialdates.contact.Contact; import com.alexstyl.specialdates.theming.MementoTheme; @@ -36,8 +35,7 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); analytics = Firebase.get(this); - analytics.trackScreen(Screen.ADD_BIRTHDAY); - MementoTheme theme = Themer.get().getCurrentTheme(); + MementoTheme theme = Themer.get(this).getCurrentTheme(); setContentView(R.layout.activity_add_birthday, theme); contactHeroView = Views.findById(this, R.id.addbirthday_hero); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/addevent/BirthdayQuery.java b/mobile/src/main/java/com/alexstyl/specialdates/addevent/BirthdayQuery.java index dabfff15..4ec4f5a0 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/addevent/BirthdayQuery.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/addevent/BirthdayQuery.java @@ -15,7 +15,6 @@ import com.alexstyl.specialdates.date.DateParseException; import com.alexstyl.specialdates.date.DayDate; import com.alexstyl.specialdates.util.DateParser; -import com.alexstyl.specialdates.util.Utils; import com.novoda.notils.exception.DeveloperError; public class BirthdayQuery { @@ -127,8 +126,7 @@ public static Cursor query(ContentResolver cr) { } private static final Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI; - private static final String COL_DISPLAY_NAME = Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY - : ContactsContract.Contacts.DISPLAY_NAME; + private static final String COL_DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY; public static final String WHERE = "(" + ContactsContract.Data.MIMETYPE + " = ? AND " + diff --git a/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsQuery.java b/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsQuery.java index fcee9c80..74136715 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsQuery.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/contact/ContactsQuery.java @@ -7,20 +7,16 @@ import android.os.Build; import android.provider.ContactsContract; -import com.alexstyl.specialdates.util.Utils; - @TargetApi(Build.VERSION_CODES.HONEYCOMB) class ContactsQuery { public final static Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI; - public static String COL_DISPLAY_NAME = Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY //3 - : ContactsContract.Contacts.DISPLAY_NAME; + public static String COL_DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY; public static String COL_LOOKUP = ContactsContract.Contacts.LOOKUP_KEY; @SuppressLint("InlinedApi") - public final static String SORT_ORDER = Utils.hasHoneycomb() ? - ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME; + public final static String SORT_ORDER = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY; @SuppressLint("InlinedApi") public static final String[] PROJECTION = { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsFragment.java b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsFragment.java index f2ebabf1..16806fb0 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsFragment.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/datedetails/DateDetailsFragment.java @@ -155,7 +155,7 @@ public void onActivityCreated(Bundle savedInstanceState) { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - navigator = new Navigator(getActivity()); + navigator = new Navigator(getActivity(), analytics); analytics = Firebase.get(getActivity()); } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/BirthdayDatabaseRefresher.java b/mobile/src/main/java/com/alexstyl/specialdates/events/BirthdayDatabaseRefresher.java index 1d1f0ceb..54ca8dea 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/BirthdayDatabaseRefresher.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/BirthdayDatabaseRefresher.java @@ -19,7 +19,6 @@ import com.alexstyl.specialdates.date.DayDate; import com.alexstyl.specialdates.events.database.EventSQLiteOpenHelper; import com.alexstyl.specialdates.util.DateParser; -import com.alexstyl.specialdates.util.Utils; import java.util.ArrayList; import java.util.Collections; @@ -120,8 +119,7 @@ public static Cursor query(ContentResolver cr) { } private static final Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI; - private static final String COL_DISPLAY_NAME = Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY - : ContactsContract.Contacts.DISPLAY_NAME; + private static final String COL_DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY; public static final String WHERE = "(" + ContactsContract.Data.MIMETYPE + " = ? AND " + diff --git a/mobile/src/main/java/com/alexstyl/specialdates/events/namedays/NamedayDatabaseRefresher.java b/mobile/src/main/java/com/alexstyl/specialdates/events/namedays/NamedayDatabaseRefresher.java index 1936da13..c47679b0 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/events/namedays/NamedayDatabaseRefresher.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/events/namedays/NamedayDatabaseRefresher.java @@ -22,7 +22,6 @@ import com.alexstyl.specialdates.events.database.EventSQLiteOpenHelper; import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendar; import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendarProvider; -import com.alexstyl.specialdates.util.Utils; import java.util.ArrayList; import java.util.Collections; @@ -230,14 +229,12 @@ private static class DeviceContactsQuery { }; @SuppressLint("InlinedApi") - public final static String SORT_ORDER = - Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY - : ContactsContract.Contacts.DISPLAY_NAME; + public final static String SORT_ORDER = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY; @SuppressLint("InlinedApi") public static final String[] PROJECTION = { ContactsContract.Data.CONTACT_ID, - Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME, + ContactsContract.Contacts.DISPLAY_NAME_PRIMARY }; public static final int ID = 0; diff --git a/mobile/src/main/java/com/alexstyl/specialdates/images/ImageDownloader.java b/mobile/src/main/java/com/alexstyl/specialdates/images/ImageDownloader.java index 3b60d3d5..176c9ea7 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/images/ImageDownloader.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/images/ImageDownloader.java @@ -7,7 +7,6 @@ import android.os.Build; import android.provider.ContactsContract; -import com.alexstyl.specialdates.util.Utils; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import java.io.FileNotFoundException; @@ -33,11 +32,7 @@ protected InputStream getStreamFromContent(String imageUri, Object extra) throws Uri uri = Uri.parse(imageUri); if (imageUri.startsWith("content://com.android.contacts/")) { - if (Utils.hasICS()) { - return ContactsContract.Contacts.openContactPhotoInputStream(res, uri, true); - } else { - return ContactsContract.Contacts.openContactPhotoInputStream(res, uri); - } + return ContactsContract.Contacts.openContactPhotoInputStream(res, uri, true); } return res.openInputStream(uri); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/BackKeyEditText.java b/mobile/src/main/java/com/alexstyl/specialdates/search/BackKeyEditText.java new file mode 100644 index 00000000..968b80a9 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/BackKeyEditText.java @@ -0,0 +1,26 @@ +package com.alexstyl.specialdates.search; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.widget.EditText; + +public class BackKeyEditText extends EditText { + public BackKeyEditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + private OnBackKeyPressedListener listener; + + public void setOnBackKeyPressedListener(OnBackKeyPressedListener listener) { + this.listener = listener; + } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && listener.onBackButtonPressed()) { + return true; + } + return super.onKeyPreIme(keyCode, event); + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/DelayedTextWatcher.java b/mobile/src/main/java/com/alexstyl/specialdates/search/DelayedTextWatcher.java index e6545ae4..1abbeb0f 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/search/DelayedTextWatcher.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/DelayedTextWatcher.java @@ -2,7 +2,6 @@ import android.os.Handler; import android.text.Editable; -import android.text.TextUtils; import android.text.TextWatcher; public class DelayedTextWatcher implements TextWatcher { @@ -23,13 +22,13 @@ public DelayedTextWatcher(TextUpdatedCallback textWatchTextUpdatedCallback, Hand this.handler = handler; } - private Runnable timeEndRunnable = new Runnable() { + private final Runnable timeEndRunnable = new Runnable() { @Override public void run() { - if (TextUtils.isEmpty(text)) { - textWatchTextUpdatedCallback.onEmptyTextEntered(); - } else { + if (text.length() > 0) { textWatchTextUpdatedCallback.onTextConfirmed(text); + } else { + textWatchTextUpdatedCallback.onEmptyTextConfirmed(); } } }; @@ -55,7 +54,7 @@ public void afterTextChanged(Editable s) { public interface TextUpdatedCallback { void onTextChanged(String text); - void onEmptyTextEntered(); + void onEmptyTextConfirmed(); void onTextConfirmed(String text); } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/DeviceSearchFragment.java b/mobile/src/main/java/com/alexstyl/specialdates/search/DeviceSearchFragment.java deleted file mode 100644 index ecbd54df..00000000 --- a/mobile/src/main/java/com/alexstyl/specialdates/search/DeviceSearchFragment.java +++ /dev/null @@ -1,319 +0,0 @@ -package com.alexstyl.specialdates.search; - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.text.InputType; -import android.text.TextUtils; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.TextView; - -import com.alexstyl.specialdates.R; -import com.alexstyl.specialdates.contact.Contact; -import com.alexstyl.specialdates.datedetails.DateDetailsActivity; -import com.alexstyl.specialdates.date.DayDate; -import com.alexstyl.specialdates.events.namedays.NamedayPreferences; -import com.alexstyl.specialdates.events.namedays.NameCelebrations; -import com.alexstyl.specialdates.ui.base.MementoFragment; -import com.alexstyl.specialdates.ui.widget.SpacesItemDecoration; - -/** - * A fragment in which the user can search for namedays and their contact's birthdays. - *
The fragment has a different logic for when the user has enabled namedays for any language. - * If the user has enabled to display Namedays, the search EditText will give no suggestions. Instead a custom - * suggestion bar on top of the keyboard is going to be given to the user with names. - *

Created by alexstyl on 20/04/15.

- */ -public class DeviceSearchFragment extends MementoFragment implements NameSuggestionsAdapter.OnNameSelectedListener { - - private static final String KEY_QUERY = "alexstyl:key_query"; - - private static final int ID_CONTACTS = 31; - private static final int ID_NAMEDAYS = 32; - - private static final int INITAL_COUNT = 5; - - private int searchCounter = INITAL_COUNT; - - private EditText searchField; - - private ImageButton clearButton; - private RecyclerView resultView; - - private RecyclerView namesSuggestionsView; - private SearchResultAdapter adapter; - - private NameSuggestionsAdapter namesAdapter; - - private boolean displayNamedays; - - private String searchQuery; - - @Override - public void onStart() { - super.onStart(); - searchField.requestFocus(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(KEY_QUERY, searchQuery); - } - - private LoaderManager.LoaderCallbacks contactSearchCallbacks - = new LoaderManager.LoaderCallbacks() { - - @Override - public Loader onCreateLoader(int id, Bundle args) { - adapter.notifyIsLoadingMore(); - return new SearchLoader(getActivity(), searchQuery, searchCounter); - } - - @Override - public void onLoadFinished(Loader loader, SearchResults searchResults) { - if (loader.getId() == ID_CONTACTS) { - adapter.updateSearchResults(searchResults); - } - } - - @Override - public void onLoaderReset(Loader loader) { - if (loader.getId() == ID_CONTACTS) { - adapter.notifyIsLoadingMore(); - } - } - }; - - private LoaderManager.LoaderCallbacks namedayLoaderCallbacks = new LoaderManager.LoaderCallbacks() { - - @Override - public Loader onCreateLoader(int id, Bundle args) { - return NamedaysLoader.newInstance(getActivity(), searchQuery); - } - - @Override - public void onLoadFinished(Loader loader, NameCelebrations results) { - adapter.setNamedays(results); - } - - @Override - public void onLoaderReset(Loader loader) { - adapter.setNamedays(NameCelebrations.EMPTY); - } - }; - - private void startSearching() { - getLoaderManager().restartLoader(ID_CONTACTS, null, contactSearchCallbacks); - getLoaderManager().restartLoader(ID_NAMEDAYS, null, namedayLoaderCallbacks); - } - - private void clearResults() { - adapter.clearResults(); - if (displayNamedays) { - namesAdapter.clearNames(); - } - } - - private void hideClearButton() { - clearButton.setVisibility(View.GONE); - } - - private void showClearButton() { - clearButton.setVisibility(View.VISIBLE); - } - - private void resetSearchCounter() { - searchCounter = INITAL_COUNT; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - displayNamedays = shouldIncludeNamedays(); - if (savedInstanceState != null) { - searchQuery = savedInstanceState.getString(KEY_QUERY); - } - } - - private boolean shouldIncludeNamedays() { - NamedayPreferences namedayPreferences = NamedayPreferences.newInstance(getActivity()); - return namedayPreferences.isEnabled(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_search, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - searchField = (EditText) view.findViewById(R.id.text_search_query); - setupSearchField(); - ImageButton closeButton = (ImageButton) view.findViewById(R.id.btn_close); - clearButton = (ImageButton) view.findViewById(R.id.btn_clear); - resultView = (RecyclerView) view.findViewById(android.R.id.list); - resultView.setHasFixedSize(false); - namesSuggestionsView = (RecyclerView) view.findViewById(R.id.nameday_suggestions); - - closeButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - getActivity().finish(); - } - } - ); - clearButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - searchField.setText(null); - searchField.requestFocus(); - InputMethodManager imm = (InputMethodManager) getActivity() - .getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(searchField, InputMethodManager.SHOW_IMPLICIT); - - } - } - ); - - adapter = SearchResultAdapter.newInstance(getActivity(), displayNamedays); - adapter.setSearchResultClickListener(listener); - - resultView.setHasFixedSize(true); - RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); - int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.card_spacing_between); - resultView.addItemDecoration(new SpacesItemDecoration(spacingInPixels, 3)); - resultView.setLayoutManager(mLayoutManager); - resultView.setAdapter(adapter); - - if (displayNamedays) { - // we are loading namedays as well - GridLayoutManager namedayManager = new GridLayoutManager(getActivity(), 1, RecyclerView.HORIZONTAL, false); - namesAdapter = NameSuggestionsAdapter.newInstance(getActivity()); - namesAdapter.setOnNameSelectedListener(this); - namesSuggestionsView.setHasFixedSize(true); - namesSuggestionsView.setLayoutManager(namedayManager); - namesSuggestionsView.setAdapter(namesAdapter); - - searchField.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); - - searchField.setOnFocusChangeListener( - new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - namesSuggestionsView.setVisibility(View.VISIBLE); - } else { - namesSuggestionsView.setVisibility(View.GONE); - } - } - } - ); - } else { - namesSuggestionsView.setVisibility(View.GONE); - } - } - - private final DelayedTextWatcher.TextUpdatedCallback textUpdatedTextUpdatedCallback = new DelayedTextWatcher.TextUpdatedCallback() { - @Override - public void onTextChanged(String text) { - searchQuery = text; - updateNameSuggestions(text); - resetSearchCounter(); - } - - @Override - public void onEmptyTextEntered() { - clearResults(); - hideClearButton(); - } - - @Override - public void onTextConfirmed(String text) { - startSearching(); - showClearButton(); - } - }; - - private void updateNameSuggestions(String text) { - if (displayNamedays) { - namesAdapter.getFilter().filter(text); - } - } - - private void setupSearchField() { - searchField.addTextChangedListener(DelayedTextWatcher.newInstance(textUpdatedTextUpdatedCallback)); - searchField.setOnEditorActionListener( - new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_SEARCH) { - InputMethodManager imm = (InputMethodManager) getActivity() - .getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(searchField.getWindowToken(), 0); - resultView.requestFocus(); - return true; - } - return false; - } - } - ); - } - - @Override - public void onNameSelected(View view, final String name) { - onNameSet(name); - } - - private void onNameSet(String name) { - // setting the text to the EditText will trigger the search for the name - searchField.setText(name); - namesAdapter.clearNames(); - - InputMethodManager imm = (InputMethodManager) getActivity() - .getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(searchField.getWindowToken(), 0); - searchField.clearFocus(); - - } - - @Override - public void onResume() { - super.onResume(); - if (TextUtils.isEmpty(searchQuery)) { - hideClearButton(); - } else { - showClearButton(); - } - } - - private SearchResultAdapter.SearchResultClickListener listener = new SearchResultAdapter.SearchResultClickListener() { - - @Override - public void onContactClicked(View v, Contact contact) { - contact.displayQuickInfo(getActivity(), v); - } - - @Override - public void onNamedayClicked(View v, int month, int day) { - DayDate dayDate = DayDate.today(); - DateDetailsActivity.startActivity(getActivity(), month, day, dayDate.getYear()); - } - - }; - -} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/OnBackKeyPressedListener.java b/mobile/src/main/java/com/alexstyl/specialdates/search/OnBackKeyPressedListener.java new file mode 100644 index 00000000..8bf8b18c --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/OnBackKeyPressedListener.java @@ -0,0 +1,8 @@ +package com.alexstyl.specialdates.search; + +public interface OnBackKeyPressedListener { + /** + * @return Return true if the event has been handled + */ + boolean onBackButtonPressed(); +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchActivity.java index cdea9c5a..238feabe 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchActivity.java @@ -1,16 +1,349 @@ package com.alexstyl.specialdates.search; import android.os.Bundle; +import android.support.transition.Fade; +import android.support.transition.Transition; +import android.support.transition.TransitionManager; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.InputType; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; import com.alexstyl.specialdates.R; -import com.alexstyl.specialdates.ui.base.ThemedActivity; +import com.alexstyl.specialdates.analytics.Firebase; +import com.alexstyl.specialdates.analytics.Screen; +import com.alexstyl.specialdates.contact.Contact; +import com.alexstyl.specialdates.date.DayDate; +import com.alexstyl.specialdates.datedetails.DateDetailsActivity; +import com.alexstyl.specialdates.events.namedays.NameCelebrations; +import com.alexstyl.specialdates.events.namedays.NamedayLocale; +import com.alexstyl.specialdates.events.namedays.NamedayPreferences; +import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendar; +import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendarProvider; +import com.alexstyl.specialdates.images.ImageLoader; +import com.alexstyl.specialdates.theming.Themer; +import com.alexstyl.specialdates.transition.FadeInTransition; +import com.alexstyl.specialdates.transition.FadeOutTransition; +import com.alexstyl.specialdates.transition.SimpleTransitionListener; +import com.alexstyl.specialdates.ui.ViewFader; +import com.alexstyl.specialdates.ui.base.MementoActivity; +import com.alexstyl.specialdates.ui.widget.SpacesItemDecoration; +import com.novoda.notils.caster.Views; +import com.novoda.notils.meta.AndroidUtils; -public class SearchActivity extends ThemedActivity { +import static android.view.View.GONE; + +/** + * A fragment in which the user can search for namedays and their contact's birthdays. + *
The fragment has a different logic for when the user has enabled namedays for any language. + * If the user has enabled to display Namedays, the search EditText will give no suggestions. Instead a custom + * suggestion bar on top of the keyboard is going to be given to the user with names. + *

Created by alexstyl on 20/04/15.

+ */ +public class SearchActivity extends MementoActivity { + + private static final String KEY_QUERY = "alexstyl:key_query"; + private static final int ID_CONTACTS = 31; + private static final int ID_NAMEDAYS = 32; + private static final int INITAL_COUNT = 5; + + private int searchCounter = INITAL_COUNT; + private SearchBar searchbar; + private RecyclerView resultView; + private RecyclerView namesSuggestionsView; + private SearchResultAdapter adapter; + private NameSuggestionsAdapter namesAdapter; + private String searchQuery; + + private ViewFader fader = new ViewFader(); + private ViewGroup content; + private NamedayPreferences namedayPreferences; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Themer themer = Themer.get(this); + themer.initialiseActivity(this); setContentView(R.layout.activity_search); + Firebase.get(this).trackScreen(Screen.SEARCH); + searchbar = Views.findById(this, R.id.search_searchbar); + setSupportActionBar(searchbar); + content = Views.findById(this, R.id.search_content); + resultView = Views.findById(this, android.R.id.list); + resultView.setHasFixedSize(false); + namesSuggestionsView = Views.findById(this, R.id.nameday_suggestions); + + if (savedInstanceState != null) { + searchQuery = savedInstanceState.getString(KEY_QUERY); + } + + setupSearchField(); + + ImageLoader imageLoader = ImageLoader.createSquareThumbnailLoader(getResources()); + int year = DayDate.today().getYear(); + NamedayLocale locale = NamedayPreferences.newInstance(this).getSelectedLanguage(); + NamedayCalendar namedayCalendar = NamedayCalendarProvider.newInstance(this).loadNamedayCalendarForLocale(locale, year); + + adapter = new SearchResultAdapter(imageLoader, namedayCalendar); + adapter.setSearchResultClickListener(listener); + + resultView.setHasFixedSize(true); + RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context()); + int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.card_spacing_between); + resultView.addItemDecoration(new SpacesItemDecoration(spacingInPixels, 3)); + resultView.setLayoutManager(mLayoutManager); + resultView.setAdapter(adapter); + + searchbar.setOnBackKeyPressedListener(onBackKeyPressedListener); + + namedayPreferences = NamedayPreferences.newInstance(this); + setupSearchbarHint(namedayPreferences); + + if (namedayPreferences.isEnabled()) { + // we are loading namedays as well + GridLayoutManager namedayManager = new GridLayoutManager(context(), 1, RecyclerView.HORIZONTAL, false); + namesAdapter = NameSuggestionsAdapter.newInstance(context()); + namesAdapter.setOnNameSelectedListener(onNameSelectedListener); + namesSuggestionsView.setHasFixedSize(true); + namesSuggestionsView.setLayoutManager(namedayManager); + namesSuggestionsView.setAdapter(namesAdapter); + + searchbar.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + searchbar.setOnFocusChangeListener(new ToggleVisibilityOnFocus(namesSuggestionsView)); + } else { + namesSuggestionsView.setVisibility(GONE); + } + + if (savedInstanceState == null) { + fader.hideContentOf(searchbar); + ViewTreeObserver viewTreeObserver = searchbar.getViewTreeObserver(); + viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + searchbar.getViewTreeObserver().removeOnGlobalLayoutListener(this); + animateShowSearch(); + } + + private void animateShowSearch() { + TransitionManager.beginDelayedTransition(searchbar, FadeInTransition.createTransition()); + fader.showContent(searchbar); + } + }); + } + + } + + private void setupSearchbarHint(NamedayPreferences preferences) { + SearchHintCreator searchHintCreator = new SearchHintCreator(getResources(), preferences); + searchbar.setHint(searchHintCreator.createHint()); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_search, menu); + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + MenuItem clearMenuItem = menu.findItem(R.id.action_clear); + clearMenuItem.setVisible(searchbar.hasText()); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + case R.id.action_clear: + onClearPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void finish() { + if (supportsTransitions()) { + AndroidUtils.requestHideKeyboard(this, searchbar); + exitTransitionWithAction(new Runnable() { + @Override + public void run() { + SearchActivity.super.finish(); + overridePendingTransition(0, 0); + } + }); + } else { + super.finish(); + } + } + + private void exitTransitionWithAction(final Runnable endingAction) { + Transition transition = FadeOutTransition.withAction(new SimpleTransitionListener() { + @Override + public void onTransitionEnd(Transition transition) { + endingAction.run(); + } + }); + + TransitionManager.beginDelayedTransition(searchbar, transition); + fader.hideContentOf(searchbar); + + TransitionManager.beginDelayedTransition(content, new Fade(Fade.OUT)); } + private void onClearPressed() { + searchbar.clearText(); + AndroidUtils.toggleKeyboard(this); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(KEY_QUERY, searchQuery); + } + + private void startSearching() { + getSupportLoaderManager().restartLoader(ID_CONTACTS, null, contactSearchCallbacks); + getSupportLoaderManager().restartLoader(ID_NAMEDAYS, null, namedayLoaderCallbacks); + } + + private void clearResults() { + adapter.clearResults(); + if (namedayPreferences.isEnabled()) { + namesAdapter.clearNames(); + } + } + + private void resetSearchCounter() { + searchCounter = INITAL_COUNT; + } + + private void updateNameSuggestions(String text) { + if (namedayPreferences.isEnabled()) { + namesAdapter.getFilter().filter(text); + } + } + + private void setupSearchField() { + searchbar.addTextWatcher(DelayedTextWatcher.newInstance(textUpdatedTextUpdatedCallback)); + } + + private void onNameSet(String name) { + // setting the text to the EditText will trigger the search for the name + AndroidUtils.requestHideKeyboard(this, searchbar); + searchbar.setText(name); + searchbar.clearFocus(); + if (namedayPreferences.isEnabled()) { + namesAdapter.clearNames(); + } + } + + private final NameSuggestionsAdapter.OnNameSelectedListener onNameSelectedListener = new NameSuggestionsAdapter.OnNameSelectedListener() { + @Override + public void onNameSelected(View view, String name) { + onNameSet(name); + } + }; + + private final SearchResultAdapter.SearchResultClickListener listener = new SearchResultAdapter.SearchResultClickListener() { + + @Override + public void onContactClicked(View v, Contact contact) { + contact.displayQuickInfo(context(), v); + } + + @Override + public void onNamedayClicked(View v, int month, int day) { + DayDate dayDate = DayDate.today(); + DateDetailsActivity.startActivity(context(), month, day, dayDate.getYear()); + } + + }; + + private final LoaderManager.LoaderCallbacks namedayLoaderCallbacks = new LoaderManager.LoaderCallbacks() { + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return NamedaysLoader.newInstance(context(), searchQuery); + } + + @Override + public void onLoadFinished(Loader loader, NameCelebrations results) { + adapter.setNamedays(results); + } + + @Override + public void onLoaderReset(Loader loader) { + adapter.setNamedays(NameCelebrations.EMPTY); + } + }; + + private final DelayedTextWatcher.TextUpdatedCallback textUpdatedTextUpdatedCallback = new DelayedTextWatcher.TextUpdatedCallback() { + @Override + public void onTextChanged(String text) { + searchQuery = text; + updateNameSuggestions(text); + resetSearchCounter(); + invalidateOptionsMenu(); + } + + @Override + public void onEmptyTextConfirmed() { + clearResults(); + invalidateOptionsMenu(); + } + + @Override + public void onTextConfirmed(String text) { + startSearching(); + } + }; + + private final LoaderManager.LoaderCallbacks contactSearchCallbacks = new LoaderManager.LoaderCallbacks() { + + @Override + public Loader onCreateLoader(int id, Bundle args) { + adapter.notifyIsLoadingMore(); + return new SearchLoader(context(), searchQuery, searchCounter); + } + + @Override + public void onLoadFinished(Loader loader, SearchResults searchResults) { + if (loader.getId() == ID_CONTACTS) { + adapter.updateSearchResults(searchResults); + } + } + + @Override + public void onLoaderReset(Loader loader) { + if (loader.getId() == ID_CONTACTS) { + adapter.notifyIsLoadingMore(); + } + } + }; + + private final OnBackKeyPressedListener onBackKeyPressedListener = new OnBackKeyPressedListener() { + @Override + public boolean onBackButtonPressed() { + if (searchbar.hasText()) { + // do nothing + return false; + } else { + finish(); + return true; + } + } + }; + } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchBar.java b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchBar.java new file mode 100644 index 00000000..79c0e3aa --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchBar.java @@ -0,0 +1,81 @@ +package com.alexstyl.specialdates.search; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.TextView; + +import com.alexstyl.specialdates.R; +import com.alexstyl.specialdates.theming.AttributeExtractor; +import com.alexstyl.specialdates.theming.ViewTinter; +import com.novoda.notils.caster.Views; + +public class SearchBar extends Toolbar { + + private BackKeyEditText editText; + + public SearchBar(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + inflate(getContext(), R.layout.merge_searchbar, this); + editText = Views.findById(this, R.id.toolbar_search_edittext); + setBackgroundColor(Color.WHITE); + addTintedUpNavigation(); + + editText.setOnEditorActionListener(onEditorActionListener); + } + + private void addTintedUpNavigation() { + ViewTinter viewTinter = new ViewTinter(new AttributeExtractor()); + Drawable backDrawable = getResources().getDrawable(R.drawable.ic_action_arrow_light_back).mutate(); + Drawable tintedUpDrawable = viewTinter.createAccentTintedDrawable(backDrawable, getContext()); + setNavigationIcon(tintedUpDrawable); + } + + public void addTextWatcher(TextWatcher textWatcher) { + editText.addTextChangedListener(textWatcher); + } + + public void setInputType(int typeTextFlag) { + editText.setInputType(typeTextFlag); + } + + private final TextView.OnEditorActionListener onEditorActionListener = new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + editText.requestFocus(); + return true; + } + return false; + } + }; + + public void setOnBackKeyPressedListener(OnBackKeyPressedListener listener) { + editText.setOnBackKeyPressedListener(listener); + } + + public void setText(String text) { + editText.setText(text); + } + + public void clearText() { + editText.setText(null); + } + + public boolean hasText() { + return editText.length() > 0; + } + + public void setHint(String hint) { + editText.setHint(hint); + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchHintCreator.java b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchHintCreator.java new file mode 100644 index 00000000..c2ae9702 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchHintCreator.java @@ -0,0 +1,26 @@ +package com.alexstyl.specialdates.search; + +import android.content.res.Resources; + +import com.alexstyl.specialdates.R; +import com.alexstyl.specialdates.events.namedays.NamedayPreferences; + +public class SearchHintCreator { + + private final Resources resources; + private final NamedayPreferences namedayPreferences; + + public SearchHintCreator(Resources resources, NamedayPreferences namedayPreferences) { + this.resources = resources; + this.namedayPreferences = namedayPreferences; + } + + public String createHint() { + boolean enabled = namedayPreferences.isEnabled(); + if (enabled) { + return resources.getString(R.string.search_hint_contacts_and_namedays); + } else { + return resources.getString(R.string.search_hint_contacts); + } + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultAdapter.java b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultAdapter.java index 53a17d7f..6cff3770 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultAdapter.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultAdapter.java @@ -1,51 +1,32 @@ package com.alexstyl.specialdates.search; -import android.content.Context; -import android.content.res.Resources; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import com.alexstyl.specialdates.contact.Contact; -import com.alexstyl.specialdates.date.DayDate; +import com.alexstyl.specialdates.events.namedays.NameCelebrations; import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendar; -import com.alexstyl.specialdates.events.namedays.calendar.NamedayCalendarProvider; -import com.alexstyl.specialdates.events.namedays.NamedayLocale; -import com.alexstyl.specialdates.events.namedays.NamedayPreferences; import com.alexstyl.specialdates.images.ImageLoader; -import com.alexstyl.specialdates.events.namedays.NameCelebrations; import com.novoda.notils.exception.DeveloperError; import java.util.ArrayList; import java.util.List; -public class SearchResultAdapter extends RecyclerView.Adapter { +public final class SearchResultAdapter extends RecyclerView.Adapter { private final List contacts = new ArrayList<>(); private NamedayCard namedayCard = new NamedayCard(); private boolean isLoadingMore; - private final boolean namedayEnabled; private boolean canLoadMore = false; private final ImageLoader imageLoader; private final NamedayCalendar namedayCalendar; private String searchQuery; - public static SearchResultAdapter newInstance(Context context, boolean loadNamedays) { - Resources resources = context.getResources(); - ImageLoader imageLoader = ImageLoader.createSquareThumbnailLoader(resources); - - int year = DayDate.today().getYear(); - NamedayLocale locale = NamedayPreferences.newInstance(context).getSelectedLanguage(); - NamedayCalendar namedayCalendar = NamedayCalendarProvider.newInstance(context) - .loadNamedayCalendarForLocale(locale, year); - return new SearchResultAdapter(loadNamedays, imageLoader, namedayCalendar); - } - - private SearchResultAdapter(boolean loadNamedays, ImageLoader imageLoader, NamedayCalendar namedayCalendar) { - this.namedayEnabled = loadNamedays; + SearchResultAdapter(ImageLoader imageLoader, NamedayCalendar namedayCalendar) { this.imageLoader = imageLoader; this.namedayCalendar = namedayCalendar; } @@ -141,7 +122,7 @@ private boolean containsNoResults() { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEWTYPE_CONTACTVIEW) { - return SearchResultContactViewHolder.createFor(parent, namedayCalendar, imageLoader, namedayEnabled); + return SearchResultContactViewHolder.createFor(parent, namedayCalendar, imageLoader); } if (viewType == VIEWTYPE_NAMEDAYS_VIEW) { return SearchResultNamedayViewHolder.createFor(parent); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultContactViewHolder.java b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultContactViewHolder.java index aca93e8a..5d272da4 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultContactViewHolder.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/SearchResultContactViewHolder.java @@ -25,22 +25,19 @@ class SearchResultContactViewHolder extends RecyclerView.ViewHolder { private final TextView nameday; private final ImageLoader imageLoader; - private boolean namedayEnabled; public static SearchResultContactViewHolder createFor(ViewGroup parent, NamedayCalendar namedayCalendar, - ImageLoader imageLoader, - boolean namedayEnabled) { + ImageLoader imageLoader) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); View view = layoutInflater.inflate(R.layout.row_search_result_contact, parent, false); - return new SearchResultContactViewHolder(view, namedayCalendar, imageLoader, namedayEnabled); + return new SearchResultContactViewHolder(view, namedayCalendar, imageLoader); } - SearchResultContactViewHolder(View convertView, NamedayCalendar namedayCalendar, ImageLoader imageLoader, boolean namedayEnabled) { + SearchResultContactViewHolder(View convertView, NamedayCalendar namedayCalendar, ImageLoader imageLoader) { super(convertView); this.namedayCalendar = namedayCalendar; this.imageLoader = imageLoader; - this.namedayEnabled = namedayEnabled; this.displayName = (TextView) convertView.findViewById(R.id.contact_name); this.birthday = (TextView) convertView.findViewById(R.id.birthday_label); this.nameday = (TextView) convertView.findViewById(R.id.nameday_label); @@ -59,15 +56,12 @@ void bind(final Contact contact, final SearchResultAdapter.SearchResultClickList bindNamedays(contact); itemView.setOnClickListener( - new View.OnClickListener() - - { + new View.OnClickListener() { @Override public void onClick(View v) { mListener.onContactClicked(v, contact); } } - ); } @@ -122,7 +116,7 @@ private static String getEventString(Context context, int stringRes, DayDate dat } private boolean noEventsToDisplay(NameCelebrations namedays) { - return !namedayEnabled || namedays.containsNoDate(); + return namedays.containsNoDate(); } private Context getContext() { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/search/ToggleVisibilityOnFocus.java b/mobile/src/main/java/com/alexstyl/specialdates/search/ToggleVisibilityOnFocus.java new file mode 100644 index 00000000..be59a052 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/search/ToggleVisibilityOnFocus.java @@ -0,0 +1,23 @@ +package com.alexstyl.specialdates.search; + +import android.view.View; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +public class ToggleVisibilityOnFocus implements View.OnFocusChangeListener { + private final View view; + + public ToggleVisibilityOnFocus(View view) { + this.view = view; + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + view.setVisibility(VISIBLE); + } else { + view.setVisibility(GONE); + } + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceActivity.java index e673df7f..3f97282d 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceActivity.java @@ -25,7 +25,7 @@ public class MainPreferenceActivity extends MementoPreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Themer.get().initialiseActivity(this); + Themer.get(this).initialiseActivity(this); setContentView(R.layout.activity_settings); MementoToolbar toolbar = Views.findById(this, R.id.memento_toolbar); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceFragment.java b/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceFragment.java index 97c27a30..16001d42 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceFragment.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/settings/MainPreferenceFragment.java @@ -24,7 +24,8 @@ final public class MainPreferenceFragment extends MementoPreferenceFragment { private ListPreference namedayLanguageListPreferences; private NamedayPreferences namedaysPreferences; - private ThemingPreferences themingPreferences = new ThemingPreferences(); + private ThemingPreferences themingPreferences; + private Preference appThemePreference; private MainPreferenceActivity activity; @@ -42,6 +43,7 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preference_main); analytics = Firebase.get(getActivity()); + themingPreferences = ThemingPreferences.newInstance(getActivity()); Preference bankholidaysLanguage = findPreference(R.string.key_bankholidays_language); bankholidaysLanguage.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override diff --git a/mobile/src/main/java/com/alexstyl/specialdates/support/RateDialog.java b/mobile/src/main/java/com/alexstyl/specialdates/support/RateDialog.java index 74752226..cfe9c725 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/support/RateDialog.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/support/RateDialog.java @@ -10,6 +10,7 @@ import com.alexstyl.specialdates.Navigator; import com.alexstyl.specialdates.R; +import com.alexstyl.specialdates.analytics.Firebase; import com.alexstyl.specialdates.ui.base.MementoActivity; import com.novoda.notils.caster.Views; @@ -17,17 +18,18 @@ public class RateDialog extends MementoActivity { private final String smiley = " " + Emoticon.SMILEY.asText(); private AskForSupport askForSupport; + private Navigator navigator; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rate_dialog); askForSupport = new AskForSupport(context()); - + navigator = new Navigator(this, Firebase.get(this)); Views.findById(this, R.id.support_rate_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - new Navigator(v.getContext()).toPlayStore(); + navigator.toPlayStore(); Toast.makeText(context(), R.string.support_thanks_for_rating, Toast.LENGTH_LONG).show(); askForSupport.onRateEnd(); finish(); diff --git a/mobile/src/main/java/com/alexstyl/specialdates/support/SupportDonateDialog.java b/mobile/src/main/java/com/alexstyl/specialdates/support/SupportDonateDialog.java index 7426cdb6..ef3c211d 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/support/SupportDonateDialog.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/support/SupportDonateDialog.java @@ -216,8 +216,4 @@ public void onDestroy() { } } - public static void displayDialog(Context context) { - Intent intent = new Intent(context, SupportDonateDialog.class); - context.startActivity(intent); - } } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/support/SupportTranslateDialog.java b/mobile/src/main/java/com/alexstyl/specialdates/support/SupportTranslateDialog.java index eac9b76a..ebb00911 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/support/SupportTranslateDialog.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/support/SupportTranslateDialog.java @@ -1,8 +1,6 @@ package com.alexstyl.specialdates.support; -import android.annotation.TargetApi; import android.content.Context; -import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.Toast; @@ -10,7 +8,6 @@ import com.alexstyl.specialdates.R; import com.alexstyl.specialdates.theming.Themer; import com.alexstyl.specialdates.ui.base.ThemedActivity; -import com.alexstyl.specialdates.util.Utils; import com.novoda.notils.caster.Views; public class SupportTranslateDialog extends ThemedActivity { @@ -19,7 +16,7 @@ public class SupportTranslateDialog extends ThemedActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.dialog_translate, Themer.get().getCurrentTheme()); + setContentView(R.layout.dialog_translate, Themer.get(this).getCurrentTheme()); Views.findById(this, android.R.id.content).setBackgroundColor(getResources().getColor(android.R.color.transparent)); Views.findById(this, R.id.button_ok).setOnClickListener(new View.OnClickListener() { @@ -38,18 +35,10 @@ public void onClick(View v) { } - @TargetApi(Build.VERSION_CODES.HONEYCOMB) public boolean copyLinkToClipboard() { - if (Utils.hasHoneycomb()) { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) - getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData - .newPlainText(getResources().getString(R.string.app_name), getString(R.string.link_translate_short)); - clipboard.setPrimaryClip(clip); - } else { - android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setText(getString(R.string.link_translate_short)); - } + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText(getResources().getString(R.string.app_name), getString(R.string.link_translate_short)); + clipboard.setPrimaryClip(clip); return true; } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/theming/Themer.java b/mobile/src/main/java/com/alexstyl/specialdates/theming/Themer.java index 1c135be0..7531406e 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/theming/Themer.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/theming/Themer.java @@ -14,9 +14,10 @@ public class Themer { private static Themer INSTANCE; - public static Themer get() { + public static Themer get(Context context) { if (INSTANCE == null) { - INSTANCE = new Themer(new ThemingPreferences(), new AttributeExtractor()); + ThemingPreferences preferences = ThemingPreferences.newInstance(context); + INSTANCE = new Themer(preferences, new AttributeExtractor()); } return INSTANCE; } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/theming/ThemingPreferences.java b/mobile/src/main/java/com/alexstyl/specialdates/theming/ThemingPreferences.java index fc55ace3..47f1ce9d 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/theming/ThemingPreferences.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/theming/ThemingPreferences.java @@ -1,16 +1,21 @@ package com.alexstyl.specialdates.theming; +import android.content.Context; + import com.alexstyl.specialdates.EasyPreferences; -import com.alexstyl.specialdates.MementoApplication; import com.alexstyl.specialdates.R; -public class ThemingPreferences { +public final class ThemingPreferences { private static final String DEFAULT_THEME = MementoTheme.CHERRY_RED.getThemeName(); private final EasyPreferences preferences; - public ThemingPreferences() { - this.preferences = EasyPreferences.createForDefaultPreferences(MementoApplication.getAppContext()); + public static ThemingPreferences newInstance(Context context) { + return new ThemingPreferences(EasyPreferences.createForDefaultPreferences(context)); + } + + private ThemingPreferences(EasyPreferences defaultPreferences) { + this.preferences = defaultPreferences; } public MementoTheme getSelectedTheme() { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/theming/ViewTinter.java b/mobile/src/main/java/com/alexstyl/specialdates/theming/ViewTinter.java new file mode 100644 index 00000000..5bab4e53 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/theming/ViewTinter.java @@ -0,0 +1,19 @@ +package com.alexstyl.specialdates.theming; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; + +public class ViewTinter { + private final AttributeExtractor extractor; + + public ViewTinter(AttributeExtractor extractor) { + this.extractor = extractor; + } + + public Drawable createAccentTintedDrawable(Drawable mutate, Context context) { + int accentColor = extractor.extractAccentColorFrom(context); + mutate.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN); + return mutate; + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/transition/FadeInTransition.java b/mobile/src/main/java/com/alexstyl/specialdates/transition/FadeInTransition.java new file mode 100644 index 00000000..eb363f12 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/transition/FadeInTransition.java @@ -0,0 +1,19 @@ +package com.alexstyl.specialdates.transition; + +import android.support.transition.AutoTransition; +import android.support.transition.Transition; + +public class FadeInTransition extends AutoTransition { + + private static final int FADE_IN_DURATION = 200; + + private FadeInTransition() { + // force callers to call the factory method to instantiate this class + } + + public static Transition createTransition() { + AutoTransition transition = new AutoTransition(); + transition.setDuration(FADE_IN_DURATION); + return transition; + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/transition/FadeOutTransition.java b/mobile/src/main/java/com/alexstyl/specialdates/transition/FadeOutTransition.java new file mode 100644 index 00000000..04632563 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/transition/FadeOutTransition.java @@ -0,0 +1,25 @@ +package com.alexstyl.specialdates.transition; + +import android.support.transition.AutoTransition; +import android.support.transition.Transition; + +public class FadeOutTransition extends AutoTransition { + + private FadeOutTransition() { + // force callers to call the factory method to instantiate this class + } + + private static final int FADE_OUT_DURATION = 250; + + /** + * Creates a AutoTransition that calls the {@linkplain Transition.TransitionListener#onTransitionEnd(Transition)} + * of the passing Listener when complete + */ + public static Transition withAction(TransitionListener finishingAction) { + AutoTransition transition = new AutoTransition(); + transition.setDuration(FADE_OUT_DURATION); + transition.addListener(finishingAction); + return transition; + } + +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/transition/SimpleTransitionListener.java b/mobile/src/main/java/com/alexstyl/specialdates/transition/SimpleTransitionListener.java new file mode 100644 index 00000000..570412cf --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/transition/SimpleTransitionListener.java @@ -0,0 +1,32 @@ +package com.alexstyl.specialdates.transition; + +import android.support.transition.Transition; + +import static android.support.transition.Transition.TransitionListener; + +public class SimpleTransitionListener implements TransitionListener { + @Override + public void onTransitionStart(Transition transition) { + // do nothing + } + + @Override + public void onTransitionPause(Transition transition) { + // do nothing + } + + @Override + public void onTransitionResume(Transition transition) { + // do nothing + } + + @Override + public void onTransitionEnd(Transition transition) { + // do nothing + } + + @Override + public void onTransitionCancel(Transition transition) { + // do nothing + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/ThemeMonitor.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/ThemeMonitor.java new file mode 100644 index 00000000..0876953d --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/ui/ThemeMonitor.java @@ -0,0 +1,25 @@ +package com.alexstyl.specialdates.ui; + +import com.alexstyl.specialdates.theming.MementoTheme; +import com.alexstyl.specialdates.theming.ThemingPreferences; + +public final class ThemeMonitor { + + private final MementoTheme theme; + private final ThemingPreferences preferences; + + public static ThemeMonitor startMonitoring(ThemingPreferences preferences) { + MementoTheme currentTheme = preferences.getSelectedTheme(); + return new ThemeMonitor(currentTheme, preferences); + } + + private ThemeMonitor(MementoTheme theme, ThemingPreferences preferences) { + this.theme = theme; + this.preferences = preferences; + } + + public boolean hasThemeChanged() { + MementoTheme newTheme = preferences.getSelectedTheme(); + return newTheme != theme; + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/ThemeReapplier.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/ThemeReapplier.java deleted file mode 100644 index 4d1106ae..00000000 --- a/mobile/src/main/java/com/alexstyl/specialdates/ui/ThemeReapplier.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.alexstyl.specialdates.ui; - -import android.content.Context; - -import com.alexstyl.specialdates.theming.MementoTheme; -import com.alexstyl.specialdates.theming.ThemingPreferences; - -public class ThemeReapplier { - - private final Context context; - - private final MementoTheme theme; - private final ThemingPreferences themingPreferences; - - public ThemeReapplier(Context context) { - this.context = context.getApplicationContext(); - this.themingPreferences = new ThemingPreferences(); - this.theme = themingPreferences.getSelectedTheme(); - } - - public boolean hasThemeChanged() { - MementoTheme newTheme = themingPreferences.getSelectedTheme(); - return newTheme != theme; - } -} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/ViewFader.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/ViewFader.java new file mode 100644 index 00000000..1f7a78c8 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/ui/ViewFader.java @@ -0,0 +1,22 @@ +package com.alexstyl.specialdates.ui; + +import android.view.ViewGroup; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +public final class ViewFader { + + public void hideContentOf(ViewGroup viewGroup) { + for (int i = 0; i < viewGroup.getChildCount(); i++) { + viewGroup.getChildAt(i).setVisibility(GONE); + } + } + + public void showContent(ViewGroup viewGroup) { + for (int i = 0; i < viewGroup.getChildCount(); i++) { + viewGroup.getChildAt(i).setVisibility(VISIBLE); + } + } + +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/activity/MainActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/activity/MainActivity.java index 3d65b75e..ee77b367 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/ui/activity/MainActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/ui/activity/MainActivity.java @@ -1,28 +1,32 @@ package com.alexstyl.specialdates.ui.activity; -import android.content.Intent; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; -import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; +import com.alexstyl.specialdates.Navigator; import com.alexstyl.specialdates.R; -import com.alexstyl.specialdates.about.AboutActivity; -import com.alexstyl.specialdates.addevent.AddBirthdayActivity; -import com.alexstyl.specialdates.analytics.Analytics; import com.alexstyl.specialdates.analytics.Firebase; import com.alexstyl.specialdates.analytics.Screen; -import com.alexstyl.specialdates.settings.MainPreferenceActivity; +import com.alexstyl.specialdates.events.namedays.NamedayPreferences; +import com.alexstyl.specialdates.search.SearchHintCreator; import com.alexstyl.specialdates.support.AskForSupport; import com.alexstyl.specialdates.support.SupportDonateDialog; -import com.alexstyl.specialdates.ui.ThemeReapplier; +import com.alexstyl.specialdates.theming.ThemingPreferences; +import com.alexstyl.specialdates.ui.ThemeMonitor; +import com.alexstyl.specialdates.ui.ViewFader; import com.alexstyl.specialdates.ui.base.ThemedActivity; -import com.alexstyl.specialdates.upcoming.UpcomingEventsFragment; +import com.alexstyl.specialdates.upcoming.ExposedSearchToolbar; +import com.alexstyl.specialdates.upcoming.SearchTransitioner; import com.alexstyl.specialdates.util.Notifier; import com.alexstyl.specialdates.widgetprovider.TodayWidgetProvider; import com.novoda.notils.caster.Views; +import com.novoda.notils.meta.AndroidUtils; + +import static android.view.View.OnClickListener; /* * The activity was first launched with MainActivity being in package.ui.activity @@ -31,49 +35,50 @@ public class MainActivity extends ThemedActivity { private Notifier notifier; - private UpcomingEventsFragment upcomingEventsFragment; private AskForSupport askForSupport; - private ThemeReapplier reapplier; - private Analytics analytics; + private ThemeMonitor themeMonitor; + + private Navigator navigator; + + private SearchTransitioner searchTransitioner; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - reapplier = new ThemeReapplier(this); - analytics = Firebase.get(this); + themeMonitor = ThemeMonitor.startMonitoring(ThemingPreferences.newInstance(this)); + Firebase analytics = Firebase.get(this); analytics.trackScreen(Screen.HOME); - Toolbar toolbar = Views.findById(this, R.id.memento_toolbar); + navigator = new Navigator(this, analytics); + + ExposedSearchToolbar toolbar = Views.findById(this, R.id.memento_toolbar); + toolbar.setOnClickListener(onToolbarClickListener); setSupportActionBar(toolbar); + ViewGroup activityContent = Views.findById(this, R.id.main_content); + searchTransitioner = new SearchTransitioner(this, navigator, activityContent, toolbar, new ViewFader()); + notifier = Notifier.newInstance(this); - FloatingActionButton floatingActionButton = Views.findById(this, R.id.fab_add); - floatingActionButton.setOnClickListener(startAddBirthdayOnClick); + FloatingActionButton addBirthdayFAB = Views.findById(this, R.id.main_birthday_add_fab); + addBirthdayFAB.setOnClickListener(startAddBirthdayOnClick); askForSupport = new AskForSupport(this); - upcomingEventsFragment = (UpcomingEventsFragment) getSupportFragmentManager().findFragmentById(R.id.upcoming); + + SearchHintCreator hintCreator = new SearchHintCreator(getResources(), NamedayPreferences.newInstance(this)); + setTitle(hintCreator.createHint()); } @Override protected void onResume() { super.onResume(); - if (reapplier.hasThemeChanged()) { + if (themeMonitor.hasThemeChanged()) { reapplyTheme(); } else if (askForSupport.shouldAskForRating()) { askForSupport.askForRatingFromUser(this); } - } - - @Override - protected void onPostResume() { - super.onPostResume(); - } - - private void startAddBirthdayActivity() { - Intent intent = new Intent(this, AddBirthdayActivity.class); - startActivity(intent); + searchTransitioner.onActivityResumed(); } @Override @@ -89,37 +94,22 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: - openSettings(); + navigator.toSettings(); break; case R.id.action_about: - openAboutScreen(); + navigator.toAbout(); break; case R.id.action_donate: - openDonateDialog(); + navigator.toDonateDialog(); break; } return super.onOptionsItemSelected(item); } - private void openDonateDialog() { - analytics.trackScreen(Screen.DONATE); - SupportDonateDialog.displayDialog(this); - } - - private void openAboutScreen() { - analytics.trackScreen(Screen.ABOUT); - startActivity(new Intent(this, AboutActivity.class)); - - } - - private void openSettings() { - analytics.trackScreen(Screen.SETTINGS); - startActivity(new Intent(this, MainPreferenceActivity.class)); - } - @Override public boolean onSearchRequested() { - return upcomingEventsFragment.onSearchRequested(); + searchTransitioner.transitionToSearch(); + return true; } @Override @@ -136,10 +126,19 @@ protected void onDestroy() { } } - private final View.OnClickListener startAddBirthdayOnClick = new View.OnClickListener() { + private final OnClickListener onToolbarClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + AndroidUtils.toggleKeyboard(v.getContext()); + onSearchRequested(); + } + + }; + + private final OnClickListener startAddBirthdayOnClick = new OnClickListener() { @Override public void onClick(View v) { - startAddBirthdayActivity(); + navigator.toAddBirthday(); } }; } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/base/MementoActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/base/MementoActivity.java index ec2c5c07..13872a4d 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/ui/base/MementoActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/ui/base/MementoActivity.java @@ -7,6 +7,7 @@ import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; +import com.alexstyl.specialdates.util.Utils; import com.novoda.notils.exception.DeveloperError; public class MementoActivity extends AppCompatActivity { @@ -61,4 +62,8 @@ protected Context context() { return this; } + protected boolean supportsTransitions() { + return Utils.hasKitKat(); + } + } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/base/ThemedActivity.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/base/ThemedActivity.java index db0fe1c0..411f3313 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/ui/base/ThemedActivity.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/ui/base/ThemedActivity.java @@ -13,7 +13,7 @@ public class ThemedActivity extends MementoActivity { @Override public void setContentView(@LayoutRes int layoutResID) { - Themer.get().initialiseActivity(this); + Themer.get(this).initialiseActivity(this); super.setContentView(layoutResID); } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/ui/widget/MementoToolbar.java b/mobile/src/main/java/com/alexstyl/specialdates/ui/widget/MementoToolbar.java index 2f187911..3a7697fb 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/ui/widget/MementoToolbar.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/ui/widget/MementoToolbar.java @@ -24,7 +24,7 @@ public MementoToolbar(Context context, @Nullable AttributeSet attrs) { if (isInEditMode()) { return; } - themer = Themer.get(); + themer = Themer.get(context); int toolbarColor = fetchAccentColor(context); float toolbarElevation = getToolbarElevation(); @@ -50,7 +50,7 @@ public float getToolbarElevation() { public void displayAsUp() { if (themer.isActivityUsingDarkIcons(getContext())) { - setNavigationIcon(R.drawable.ic_action_arrow_dark_back); + setNavigationIcon(R.drawable.ic_action_left_semitransparent); } else { setNavigationIcon(R.drawable.ic_action_arrow_light_back); } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ExposedSearchToolbar.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ExposedSearchToolbar.java new file mode 100644 index 00000000..2f119a19 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ExposedSearchToolbar.java @@ -0,0 +1,18 @@ +package com.alexstyl.specialdates.upcoming; + +import android.content.Context; +import android.support.v7.widget.Toolbar; +import android.util.AttributeSet; + +import com.alexstyl.specialdates.R; + +public class ExposedSearchToolbar extends Toolbar { + + public ExposedSearchToolbar(Context context, AttributeSet attrs) { + super(context, attrs); + + setBackgroundResource(R.drawable.card_noshadow); + setNavigationIcon(R.drawable.ic_action_search); + } + +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/MonthTitleSetter.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/MonthTitleSetter.java deleted file mode 100644 index 8ec4c9f9..00000000 --- a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/MonthTitleSetter.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.alexstyl.specialdates.upcoming; - -import android.app.Activity; - -import java.util.Locale; - -class MonthTitleSetter { - - private final Activity activity; - private final MonthLabels monthLabels; - - - public static MonthTitleSetter createSetterFor(Activity activity) { - MonthLabels monthLabels = MonthLabels.forLocale(Locale.getDefault()); - - return new MonthTitleSetter(activity, monthLabels); - } - - MonthTitleSetter(Activity activity, MonthLabels monthLabels) { - this.activity = activity; - this.monthLabels = monthLabels; - } - - - void updateWithMonth(int monthToDisplay) { - String monthLabel = monthLabels.getMonthOfYear(monthToDisplay); - activity.setTitle(monthLabel); - } - -} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/SearchTransitioner.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/SearchTransitioner.java new file mode 100644 index 00000000..068465f5 --- /dev/null +++ b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/SearchTransitioner.java @@ -0,0 +1,102 @@ +package com.alexstyl.specialdates.upcoming; + +import android.app.Activity; +import android.support.transition.Fade; +import android.support.transition.Transition; +import android.support.transition.TransitionManager; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.alexstyl.specialdates.Navigator; +import com.alexstyl.specialdates.R; +import com.alexstyl.specialdates.transition.FadeInTransition; +import com.alexstyl.specialdates.transition.FadeOutTransition; +import com.alexstyl.specialdates.transition.SimpleTransitionListener; +import com.alexstyl.specialdates.ui.ViewFader; +import com.alexstyl.specialdates.util.Utils; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +public final class SearchTransitioner { + + private final Activity activity; + private final Navigator navigator; + private final ViewGroup activityContent; + private final ExposedSearchToolbar toolbar; + private final ViewFader viewFader; + + private final int toolbarMargin; + private boolean transitioning; + + public SearchTransitioner(Activity activity, + Navigator navigator, + ViewGroup activityContent, + ExposedSearchToolbar toolbar, + ViewFader viewFader) { + this.activity = activity; + this.navigator = navigator; + this.activityContent = activityContent; + this.toolbar = toolbar; + this.viewFader = viewFader; + this.toolbarMargin = activity.getResources().getDimensionPixelSize(R.dimen.padding_tight); + } + + public void transitionToSearch() { + if (transitioning) { + return; + } + if (supportsTransitions()) { + + Transition transition = FadeOutTransition.withAction(navigateToSearchWhenDone()); + TransitionManager.beginDelayedTransition(toolbar, transition); + expandToolbar(); + viewFader.hideContentOf(toolbar); + + TransitionManager.beginDelayedTransition(activityContent, new Fade(Fade.OUT)); + activityContent.setVisibility(GONE); + } else { + navigator.toSearch(); + } + } + + private void expandToolbar() { + FrameLayout.LayoutParams frameLP = (FrameLayout.LayoutParams) toolbar.getLayoutParams(); + frameLP.setMargins(0, 0, 0, 0); + toolbar.setLayoutParams(frameLP); + } + + private Transition.TransitionListener navigateToSearchWhenDone() { + return new SimpleTransitionListener() { + + @Override + public void onTransitionStart(Transition transition) { + transitioning = true; + } + + @Override + public void onTransitionEnd(Transition transition) { + transitioning = false; + navigator.toSearch(); + activity.overridePendingTransition(0, 0); + } + }; + } + + private static boolean supportsTransitions() { + return Utils.hasKitKat(); + } + + public void onActivityResumed() { + if (supportsTransitions()) { + TransitionManager.beginDelayedTransition(toolbar, FadeInTransition.createTransition()); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) toolbar.getLayoutParams(); + layoutParams.setMargins(toolbarMargin, toolbarMargin, toolbarMargin, toolbarMargin); + viewFader.showContent(toolbar); + toolbar.setLayoutParams(layoutParams); + + TransitionManager.beginDelayedTransition(activityContent, new Fade(Fade.IN)); + activityContent.setVisibility(VISIBLE); + } + } +} diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsFragment.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsFragment.java index 9ddbd96d..42a7b093 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsFragment.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/UpcomingEventsFragment.java @@ -13,8 +13,8 @@ import com.alexstyl.specialdates.R; import com.alexstyl.specialdates.analytics.Action; -import com.alexstyl.specialdates.analytics.Analytics; import com.alexstyl.specialdates.analytics.ActionWithParameters; +import com.alexstyl.specialdates.analytics.Analytics; import com.alexstyl.specialdates.analytics.Firebase; import com.alexstyl.specialdates.analytics.Screen; import com.alexstyl.specialdates.date.CelebrationDate; @@ -22,8 +22,8 @@ import com.alexstyl.specialdates.date.DayDate; import com.alexstyl.specialdates.datedetails.DateDetailsActivity; import com.alexstyl.specialdates.search.SearchActivity; -import com.alexstyl.specialdates.theming.Themer; import com.alexstyl.specialdates.ui.base.MementoFragment; +import com.alexstyl.specialdates.upcoming.ui.OnUpcomingEventClickedListener; import com.alexstyl.specialdates.upcoming.ui.UpcomingEventsListView; import com.alexstyl.specialdates.views.FabPaddingSetter; import com.novoda.notils.caster.Views; @@ -38,22 +38,18 @@ public class UpcomingEventsFragment extends MementoFragment { private ProgressBar progressBar; private TextView emptyView; private SettingsMonitor monitor; - private MonthTitleSetter titleSetter; private UpcomingEventsProvider upcomingEventsProvider; private boolean mustScrollToPosition = true; private GoToTodayEnabler goToTodayEnabler; - private Themer themer; private Analytics firebase; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); - themer = Themer.get(); firebase = Firebase.get(getActivity()); monitor = SettingsMonitor.newInstance(getActivity()); monitor.initialise(); - titleSetter = MonthTitleSetter.createSetterFor(getActivity()); goToTodayEnabler = new GoToTodayEnabler(getMementoActivity()); upcomingEventsProvider = UpcomingEventsProvider.newInstance(getActivity(), onEventsLoadedListener); } @@ -61,28 +57,16 @@ public void onCreate(Bundle savedInstanceState) { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); - if (isUsingDarkIcons()) { - inflater.inflate(R.menu.menu_upcoming_dark, menu); - } else { - inflater.inflate(R.menu.menu_upcoming_light, menu); - } + inflater.inflate(R.menu.menu_upcoming_dark, menu); goToTodayEnabler.reattachTo(menu); } - private boolean isUsingDarkIcons() { - return themer.isActivityUsingDarkIcons(getActivity()); - } - @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_today: onGoToTodayRequested(); return true; - case R.id.action_search: { - onSearchRequested(); - return true; - } default: break; } @@ -106,6 +90,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onViewCreated(View view, Bundle savedInstanceState) { new FabPaddingSetter().setBottomPaddingTo(upcomingEventsListView); + upcomingEventsListView.setHasFixedSize(true); } @Override @@ -155,8 +140,7 @@ private void showLoading() { emptyView.setVisibility(View.GONE); } - private final UpcomingEventsListView.Listener listClickListener = new UpcomingEventsListView.Listener() { - + private final OnUpcomingEventClickedListener listClickListener = new OnUpcomingEventClickedListener() { @Override public void onContactEventPressed(View view, ContactEvent contact) { firebase.trackAction(action); @@ -169,11 +153,6 @@ public void onCardPressed(DayDate date) { Intent intent = DateDetailsActivity.getStartIntent(getActivity(), date.getDayOfMonth(), date.getMonth(), date.getYear()); startActivity(intent); } - - @Override - public void onDifferentMonthScrolled(int month) { - titleSetter.updateWithMonth(month); - } }; public boolean onSearchRequested() { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsAdapter.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsAdapter.java index 2d17fb2d..98dab06e 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsAdapter.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsAdapter.java @@ -118,7 +118,7 @@ public int getMonthAt(int position) { return integer == null ? -1 : integer; } - public void setUpcomingEvents(List upcomingEvents, UpcomingEventsListView.Listener listener) { + public void setUpcomingEvents(List upcomingEvents, OnUpcomingEventClickedListener listener) { this.listener = listener; if (this.celebrationDates == upcomingEvents) { return; diff --git a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsListView.java b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsListView.java index 604847b3..7dc5b3ac 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsListView.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/upcoming/ui/UpcomingEventsListView.java @@ -11,7 +11,6 @@ import com.alexstyl.specialdates.images.ImageLoader; import com.alexstyl.specialdates.images.PauseImageLoadingScrollListener; import com.alexstyl.specialdates.ui.widget.ScrollingLinearLayoutManager; -import com.alexstyl.specialdates.upcoming.MonthSectionScrollListener; import java.util.List; @@ -20,12 +19,9 @@ public class UpcomingEventsListView extends RecyclerView { private UpcomingEventsAdapter adapter; private ScrollingLinearLayoutManager layoutManager; - private Listener listener; - public UpcomingEventsListView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); - setHasFixedSize(true); layoutManager = new ScrollingLinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false, 600); setLayoutManager(layoutManager); @@ -39,19 +35,10 @@ public UpcomingEventsListView(Context context, @Nullable AttributeSet attrs) { setAdapter(adapter); addOnScrollListener(PauseImageLoadingScrollListener.newInstance(imageLoader)); - - final MonthSectionScrollListener monthSectionScrollListener = new MonthSectionScrollListener(adapter, layoutManager) { - @Override - protected void onDifferentMonthScrolled(int month) { - listener.onDifferentMonthScrolled(month); - } - }; - addOnScrollListener(monthSectionScrollListener); } - public void updateWith(List dates, Listener listener) { - this.listener = listener; - this.adapter.setUpcomingEvents(dates, listener); + public void updateWith(List dates, OnUpcomingEventClickedListener listener) { + adapter.setUpcomingEvents(dates, listener); } public void scrollToToday(final boolean smoothScroll) { @@ -120,7 +107,4 @@ public boolean isDisplayingEvents() { return adapter.getItemCount() > 0; } - public interface Listener extends OnUpcomingEventClickedListener { - void onDifferentMonthScrolled(int month); - } } diff --git a/mobile/src/main/java/com/alexstyl/specialdates/util/Notifier.java b/mobile/src/main/java/com/alexstyl/specialdates/util/Notifier.java index 782193d9..bb277cf7 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/util/Notifier.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/util/Notifier.java @@ -197,7 +197,7 @@ private boolean supportsPublicNotifications() { } private boolean shouldDisplayContactImage(int contactCount) { - return Utils.hasHoneycomb() && contactCount == 1; + return contactCount == 1; } public void forNamedays(List names, Date date) { diff --git a/mobile/src/main/java/com/alexstyl/specialdates/util/Utils.java b/mobile/src/main/java/com/alexstyl/specialdates/util/Utils.java index 45d68b8b..02be5b06 100644 --- a/mobile/src/main/java/com/alexstyl/specialdates/util/Utils.java +++ b/mobile/src/main/java/com/alexstyl/specialdates/util/Utils.java @@ -16,15 +16,10 @@ package com.alexstyl.specialdates.util; -import android.annotation.SuppressLint; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.Uri; import android.os.Build; import android.os.Vibrator; @@ -34,17 +29,14 @@ import android.view.View; import android.widget.Toast; -import com.alexstyl.specialdates.BuildConfig; import com.alexstyl.specialdates.ErrorTracker; import com.alexstyl.specialdates.MementoApplication; -import com.alexstyl.specialdates.PayPal; import com.alexstyl.specialdates.R; import com.alexstyl.specialdates.contact.actions.IntentAction; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.List; import org.json.JSONException; import org.json.JSONObject; @@ -58,22 +50,6 @@ public class Utils { private Utils() { } - /** - * Uses static final constants to detect if the device's platform version is - * Honeycomb or later. - */ - public static boolean hasHoneycomb() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; - } - - /** - * Uses static final constants to detect if the device's platform version is - * ICS or later. - */ - public static boolean hasICS() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; - } - public static boolean hasJellyBean() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; } @@ -97,10 +73,6 @@ public static boolean hasKitKat() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; } - public static boolean isRunningKitKat() { - return Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT; - } - /** * Uses static final constants to detect if the device's platform version is * Lollipop or later. @@ -164,52 +136,11 @@ public static String getAndroidVersion() { return android.os.Build.VERSION.RELEASE; } - /** - * Returns whether the device has - * - * @param context The context to use - * @return - */ - @SuppressLint("NewApi") public static boolean hasVibrator(Context context) { Vibrator vibr = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - if (!hasHoneycomb()) { - return vibr != null; - } return vibr.hasVibrator(); } - /** - * Checks if the device is currently connected to the webz! - * - * @param context The context to use - * @return Whether the device is online or not... duh - */ - public static boolean isOnline(Context context) { - ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo ni = cm.getActiveNetworkInfo(); - if (ni == null) { - // There are no active networks. - return false; - } - return ni.isConnectedOrConnecting(); - } - - /** - * Returns the height of the navigation bars height - * - * @param context - * @return - */ - final public static int getNavigationBarHeight(Context context) { - Resources resources = context.getResources(); - int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); - if (resourceId > 0) { - return resources.getDimensionPixelSize(resourceId); - } - return 0; - } - /** * Starts a {@link IntentAction}. A Toast is displayed if the action throws an ActivityNotFoundException * @@ -251,27 +182,11 @@ public String getName() { ); } - /** - * Checks if the running device has any installed applications that can handle the given intent - * - * @param context - * @param intent - * @return - */ - public static boolean isCallable(Context context, Intent intent) { - List list = context.getPackageManager().queryIntentActivities( - intent, - PackageManager.MATCH_DEFAULT_ONLY - ); - return list.size() > 0; - } - /** * Returns a JSON value from the raw folder, of the given resID * * @param context The context to use * @param resID The resource ID of the JSON file - * @return * @throws android.content.res.Resources.NotFoundException if the resource is not a JSON */ public static JSONObject getJSON(@NonNull Context context, @RawRes int resID) { @@ -296,36 +211,4 @@ public static JSONObject getJSON(@NonNull Context context, @RawRes int resID) { } } - /** - * Compares whether one is equal with at least one of the others - * - * @param one - * @param others - * @return - */ - public static boolean equalsTo(Object one, Object... others) { - for (Object other : others) { - if (one.equals(other)) { - return true; - } - } - return false; - } - - public static boolean openPayPalDonation(Context context) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(PayPal.URL_DONATIONS)); - context.startActivity(intent); - return true; - } catch (ActivityNotFoundException e) { - if (BuildConfig.DEBUG) { - // do nothing if we there is no browser installed - Toast.makeText(context, "Exception thrown!", Toast.LENGTH_SHORT).show(); - e.printStackTrace(); - } - } - return false; - } - } diff --git a/mobile/src/main/res/drawable-hdpi/ic_action_arrow_dark_back.png b/mobile/src/main/res/drawable-hdpi/ic_action_left_semitransparent.png similarity index 100% rename from mobile/src/main/res/drawable-hdpi/ic_action_arrow_dark_back.png rename to mobile/src/main/res/drawable-hdpi/ic_action_left_semitransparent.png diff --git a/mobile/src/main/res/drawable-hdpi/ic_action_navigation_arrow_back.png b/mobile/src/main/res/drawable-hdpi/ic_action_navigation_arrow_back.png new file mode 100755 index 00000000..a9df1796 Binary files /dev/null and b/mobile/src/main/res/drawable-hdpi/ic_action_navigation_arrow_back.png differ diff --git a/mobile/src/main/res/drawable-hdpi/ic_action_search.png b/mobile/src/main/res/drawable-hdpi/ic_action_search.png old mode 100644 new mode 100755 index 857135d2..9810302b Binary files a/mobile/src/main/res/drawable-hdpi/ic_action_search.png and b/mobile/src/main/res/drawable-hdpi/ic_action_search.png differ diff --git a/mobile/src/main/res/drawable-hdpi/ic_action_today.png b/mobile/src/main/res/drawable-hdpi/ic_action_today.png old mode 100644 new mode 100755 index fe825d98..eaf359f4 Binary files a/mobile/src/main/res/drawable-hdpi/ic_action_today.png and b/mobile/src/main/res/drawable-hdpi/ic_action_today.png differ diff --git a/mobile/src/main/res/drawable-hdpi/ic_exit_to_app_white_24dp.png b/mobile/src/main/res/drawable-hdpi/ic_exit_to_app_white_24dp.png deleted file mode 100644 index 52565d09..00000000 Binary files a/mobile/src/main/res/drawable-hdpi/ic_exit_to_app_white_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-hdpi/ic_search_black_24dp.png b/mobile/src/main/res/drawable-hdpi/ic_search_black_24dp.png deleted file mode 100644 index c593e7ad..00000000 Binary files a/mobile/src/main/res/drawable-hdpi/ic_search_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-hdpi/ic_today_black_24dp.png b/mobile/src/main/res/drawable-hdpi/ic_today_black_24dp.png deleted file mode 100644 index 03680a76..00000000 Binary files a/mobile/src/main/res/drawable-hdpi/ic_today_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-mdpi/ic_action_arrow_dark_back.png b/mobile/src/main/res/drawable-mdpi/ic_action_left_semitransparent.png similarity index 100% rename from mobile/src/main/res/drawable-mdpi/ic_action_arrow_dark_back.png rename to mobile/src/main/res/drawable-mdpi/ic_action_left_semitransparent.png diff --git a/mobile/src/main/res/drawable-mdpi/ic_action_navigation_arrow_back.png b/mobile/src/main/res/drawable-mdpi/ic_action_navigation_arrow_back.png new file mode 100755 index 00000000..6ae1c1d0 Binary files /dev/null and b/mobile/src/main/res/drawable-mdpi/ic_action_navigation_arrow_back.png differ diff --git a/mobile/src/main/res/drawable-mdpi/ic_action_search.png b/mobile/src/main/res/drawable-mdpi/ic_action_search.png old mode 100644 new mode 100755 index 8d57e2ba..f70bef02 Binary files a/mobile/src/main/res/drawable-mdpi/ic_action_search.png and b/mobile/src/main/res/drawable-mdpi/ic_action_search.png differ diff --git a/mobile/src/main/res/drawable-mdpi/ic_action_today.png b/mobile/src/main/res/drawable-mdpi/ic_action_today.png old mode 100644 new mode 100755 index 82a86d8d..c7c57fd2 Binary files a/mobile/src/main/res/drawable-mdpi/ic_action_today.png and b/mobile/src/main/res/drawable-mdpi/ic_action_today.png differ diff --git a/mobile/src/main/res/drawable-mdpi/ic_exit_to_app_white_24dp.png b/mobile/src/main/res/drawable-mdpi/ic_exit_to_app_white_24dp.png deleted file mode 100644 index 461be00a..00000000 Binary files a/mobile/src/main/res/drawable-mdpi/ic_exit_to_app_white_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-mdpi/ic_search_black_24dp.png b/mobile/src/main/res/drawable-mdpi/ic_search_black_24dp.png deleted file mode 100644 index 6b163432..00000000 Binary files a/mobile/src/main/res/drawable-mdpi/ic_search_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-mdpi/ic_today_black_24dp.png b/mobile/src/main/res/drawable-mdpi/ic_today_black_24dp.png deleted file mode 100644 index 227bfca9..00000000 Binary files a/mobile/src/main/res/drawable-mdpi/ic_today_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xhdpi/ic_action_arrow_dark_back.png b/mobile/src/main/res/drawable-xhdpi/ic_action_left_semitransparent.png similarity index 100% rename from mobile/src/main/res/drawable-xhdpi/ic_action_arrow_dark_back.png rename to mobile/src/main/res/drawable-xhdpi/ic_action_left_semitransparent.png diff --git a/mobile/src/main/res/drawable-xhdpi/ic_action_navigation_arrow_back.png b/mobile/src/main/res/drawable-xhdpi/ic_action_navigation_arrow_back.png new file mode 100755 index 00000000..39dde07a Binary files /dev/null and b/mobile/src/main/res/drawable-xhdpi/ic_action_navigation_arrow_back.png differ diff --git a/mobile/src/main/res/drawable-xhdpi/ic_action_search.png b/mobile/src/main/res/drawable-xhdpi/ic_action_search.png old mode 100644 new mode 100755 index d9fb6338..ccdfb3fd Binary files a/mobile/src/main/res/drawable-xhdpi/ic_action_search.png and b/mobile/src/main/res/drawable-xhdpi/ic_action_search.png differ diff --git a/mobile/src/main/res/drawable-xhdpi/ic_action_today.png b/mobile/src/main/res/drawable-xhdpi/ic_action_today.png old mode 100644 new mode 100755 index 4fe7595f..80b49c4b Binary files a/mobile/src/main/res/drawable-xhdpi/ic_action_today.png and b/mobile/src/main/res/drawable-xhdpi/ic_action_today.png differ diff --git a/mobile/src/main/res/drawable-xhdpi/ic_exit_to_app_white_24dp.png b/mobile/src/main/res/drawable-xhdpi/ic_exit_to_app_white_24dp.png deleted file mode 100644 index 07847bd2..00000000 Binary files a/mobile/src/main/res/drawable-xhdpi/ic_exit_to_app_white_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xhdpi/ic_search_black_24dp.png b/mobile/src/main/res/drawable-xhdpi/ic_search_black_24dp.png deleted file mode 100644 index 63819026..00000000 Binary files a/mobile/src/main/res/drawable-xhdpi/ic_search_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xhdpi/ic_today_black_24dp.png b/mobile/src/main/res/drawable-xhdpi/ic_today_black_24dp.png deleted file mode 100644 index 2d6a849c..00000000 Binary files a/mobile/src/main/res/drawable-xhdpi/ic_today_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_action_arrow_dark_back.png b/mobile/src/main/res/drawable-xxhdpi/ic_action_left_semitransparent.png similarity index 100% rename from mobile/src/main/res/drawable-xxhdpi/ic_action_arrow_dark_back.png rename to mobile/src/main/res/drawable-xxhdpi/ic_action_left_semitransparent.png diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_action_navigation_arrow_back.png b/mobile/src/main/res/drawable-xxhdpi/ic_action_navigation_arrow_back.png new file mode 100755 index 00000000..e5287823 Binary files /dev/null and b/mobile/src/main/res/drawable-xxhdpi/ic_action_navigation_arrow_back.png differ diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_action_search.png b/mobile/src/main/res/drawable-xxhdpi/ic_action_search.png old mode 100644 new mode 100755 index b1048235..4a85a4cd Binary files a/mobile/src/main/res/drawable-xxhdpi/ic_action_search.png and b/mobile/src/main/res/drawable-xxhdpi/ic_action_search.png differ diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_action_today.png b/mobile/src/main/res/drawable-xxhdpi/ic_action_today.png old mode 100644 new mode 100755 index ad33347b..d5b29841 Binary files a/mobile/src/main/res/drawable-xxhdpi/ic_action_today.png and b/mobile/src/main/res/drawable-xxhdpi/ic_action_today.png differ diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_exit_to_app_white_24dp.png b/mobile/src/main/res/drawable-xxhdpi/ic_exit_to_app_white_24dp.png deleted file mode 100644 index c04fe6e0..00000000 Binary files a/mobile/src/main/res/drawable-xxhdpi/ic_exit_to_app_white_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_search_black_24dp.png b/mobile/src/main/res/drawable-xxhdpi/ic_search_black_24dp.png deleted file mode 100644 index 3ae490ef..00000000 Binary files a/mobile/src/main/res/drawable-xxhdpi/ic_search_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xxhdpi/ic_today_black_24dp.png b/mobile/src/main/res/drawable-xxhdpi/ic_today_black_24dp.png deleted file mode 100644 index 229f0445..00000000 Binary files a/mobile/src/main/res/drawable-xxhdpi/ic_today_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xxxhdpi/ic_action_navigation_arrow_back.png b/mobile/src/main/res/drawable-xxxhdpi/ic_action_navigation_arrow_back.png new file mode 100755 index 00000000..71d044e5 Binary files /dev/null and b/mobile/src/main/res/drawable-xxxhdpi/ic_action_navigation_arrow_back.png differ diff --git a/mobile/src/main/res/drawable-xxxhdpi/ic_action_search.png b/mobile/src/main/res/drawable-xxxhdpi/ic_action_search.png new file mode 100755 index 00000000..2653c039 Binary files /dev/null and b/mobile/src/main/res/drawable-xxxhdpi/ic_action_search.png differ diff --git a/mobile/src/main/res/drawable-xxxhdpi/ic_action_today.png b/mobile/src/main/res/drawable-xxxhdpi/ic_action_today.png new file mode 100755 index 00000000..e9d5192c Binary files /dev/null and b/mobile/src/main/res/drawable-xxxhdpi/ic_action_today.png differ diff --git a/mobile/src/main/res/drawable-xxxhdpi/ic_exit_to_app_white_24dp.png b/mobile/src/main/res/drawable-xxxhdpi/ic_exit_to_app_white_24dp.png deleted file mode 100644 index 27a9d7b0..00000000 Binary files a/mobile/src/main/res/drawable-xxxhdpi/ic_exit_to_app_white_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xxxhdpi/ic_search_black_24dp.png b/mobile/src/main/res/drawable-xxxhdpi/ic_search_black_24dp.png deleted file mode 100644 index 21be5729..00000000 Binary files a/mobile/src/main/res/drawable-xxxhdpi/ic_search_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable-xxxhdpi/ic_today_black_24dp.png b/mobile/src/main/res/drawable-xxxhdpi/ic_today_black_24dp.png deleted file mode 100644 index 38704111..00000000 Binary files a/mobile/src/main/res/drawable-xxxhdpi/ic_today_black_24dp.png and /dev/null differ diff --git a/mobile/src/main/res/drawable/card_noshadow.xml b/mobile/src/main/res/drawable/card_noshadow.xml new file mode 100644 index 00000000..48d13eb2 --- /dev/null +++ b/mobile/src/main/res/drawable/card_noshadow.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/mobile/src/main/res/layout/activity_main.xml b/mobile/src/main/res/layout/activity_main.xml index 7b64d35c..db83d92b 100644 --- a/mobile/src/main/res/layout/activity_main.xml +++ b/mobile/src/main/res/layout/activity_main.xml @@ -2,19 +2,30 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center_horizontal"> + android:layout_height="match_parent"> - + android:layout_height="@dimen/toolbar_semi_expanded_height" + android:background="?attr/colorPrimary" + android:elevation="@dimen/toolbar_elevation"> + + + + - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + diff --git a/mobile/src/main/res/layout/fragment_contact_details.xml b/mobile/src/main/res/layout/fragment_contact_details.xml deleted file mode 100644 index 8df1ce95..00000000 --- a/mobile/src/main/res/layout/fragment_contact_details.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/src/main/res/layout/fragment_search.xml b/mobile/src/main/res/layout/fragment_search.xml deleted file mode 100644 index 0a562370..00000000 --- a/mobile/src/main/res/layout/fragment_search.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/mobile/src/main/res/layout/merge_searchbar.xml b/mobile/src/main/res/layout/merge_searchbar.xml new file mode 100644 index 00000000..0fb1dc59 --- /dev/null +++ b/mobile/src/main/res/layout/merge_searchbar.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/mobile/src/main/res/layout/searchbar.xml b/mobile/src/main/res/layout/searchbar.xml deleted file mode 100644 index 372ce657..00000000 --- a/mobile/src/main/res/layout/searchbar.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/src/main/res/layout/toolbar_search.xml b/mobile/src/main/res/layout/toolbar_search.xml new file mode 100644 index 00000000..5aac703e --- /dev/null +++ b/mobile/src/main/res/layout/toolbar_search.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/mobile/src/main/res/menu/menu_search.xml b/mobile/src/main/res/menu/menu_search.xml new file mode 100644 index 00000000..02e644b3 --- /dev/null +++ b/mobile/src/main/res/menu/menu_search.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/mobile/src/main/res/menu/menu_upcoming_dark.xml b/mobile/src/main/res/menu/menu_upcoming_dark.xml index de8c7968..01d4cedd 100644 --- a/mobile/src/main/res/menu/menu_upcoming_dark.xml +++ b/mobile/src/main/res/menu/menu_upcoming_dark.xml @@ -4,16 +4,9 @@ - - diff --git a/mobile/src/main/res/transition/changebounds.xml b/mobile/src/main/res/transition/changebounds.xml new file mode 100644 index 00000000..eeaa7e8b --- /dev/null +++ b/mobile/src/main/res/transition/changebounds.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/mobile/src/main/res/transition/explode.xml b/mobile/src/main/res/transition/explode.xml new file mode 100644 index 00000000..3b00a31c --- /dev/null +++ b/mobile/src/main/res/transition/explode.xml @@ -0,0 +1,6 @@ + + + + diff --git a/mobile/src/main/res/transition/fade_and_changebounds.xml b/mobile/src/main/res/transition/fade_and_changebounds.xml new file mode 100644 index 00000000..8a427181 --- /dev/null +++ b/mobile/src/main/res/transition/fade_and_changebounds.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/mobile/src/main/res/values-v21/search-resources.xml b/mobile/src/main/res/values-v21/search-resources.xml new file mode 100644 index 00000000..feb2cd46 --- /dev/null +++ b/mobile/src/main/res/values-v21/search-resources.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/mobile/src/main/res/values/search-resources.xml b/mobile/src/main/res/values/search-resources.xml new file mode 100644 index 00000000..f1ea3d11 --- /dev/null +++ b/mobile/src/main/res/values/search-resources.xml @@ -0,0 +1,9 @@ + + + @string/Search_for_contacts + @string/Search_for_contacts_or_namedays + @string/Clear + #808080 + + + diff --git a/mobile/src/main/res/values/string.xml b/mobile/src/main/res/values/string.xml new file mode 100644 index 00000000..5333ef9b --- /dev/null +++ b/mobile/src/main/res/values/string.xml @@ -0,0 +1,4 @@ + + + Clear + diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 50e5203d..c5abb223 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -1,64 +1,65 @@ - - Memento Namedays - Today - Tomorrow - Birthday - Birthdays - Name Days - Name Day - "It's %s's birthday!" - "It's %s's nameday!" - No name days for this day - No contact has their birthday this day - Settings - Disable - Enable - %1$s - %1$s and %2$s - %1$s and %2$d others - About - Daily Reminder Service - Display Name Days - Name Days will be displayed for all of your contacts - Name Days will not be displayed - Contact the developer - Found a bug? Have a suggestion? Let me know! - Choose - number - Nameday on %s - Birthday on %s - Turns %1$d on %2$s - Call - Send SMS - Send e-mail - No application found in order to perform this action - Send e-mail via - Daily Reminder - "Remind me for every day's events" - Ringtone - Vibrate - Every day at %s - Set time - Set - Discard - Contact added - Contact could not be added - Contact updated - Contact could not be updated - @string/upcoming - Silent - Contacts celebrating this day - There are no contacts celebrating this day - Upcoming - Turns %1$d - Today\'s Namedays - Check out %1$s - a sweet looking birthdays and namedays reminder app for Android! Get it at %2$s - Share via - Licences - Developed and designed by Alex Styl + + Memento Namedays + Today + Tomorrow + Birthday + Birthdays + Name Days + Name Day + "It's %s's birthday!" + "It's %s's nameday!" + No name days for this day + No contact has their birthday this day + Settings + Disable + Enable + %1$s + %1$s and %2$s + %1$s and %2$d others + About + Daily Reminder Service + Display Name Days + Name Days will be displayed for all of your contacts + Name Days will not be displayed + Contact the developer + Found a bug? Have a suggestion? Let me know! + Choose + number + Nameday on %s + Birthday on %s + Turns %1$d on %2$s + Call + Send SMS + Send e-mail + No application found in order to perform this action + Send e-mail via + Daily Reminder + "Remind me for every day's events" + Ringtone + Vibrate + Every day at %s + Set time + Set + Discard + Contact added + Contact could not be added + Contact updated + Contact could not be updated + @string/upcoming + Silent + Contacts celebrating this day + There are no contacts celebrating this day + Upcoming + Turns %1$d + Today\'s Namedays + Check out %1$s - a sweet looking birthdays and namedays reminder app for Android! Get it at %2$s + Share via + Licences + Developed and designed by Alex Styl "Special thanks to Andreas Sfakianakis for his work on the Greeklish library @@ -66,94 +67,96 @@ Aggela Stylianidou for the French translation Gian Maria Calzolari for the Italian translation Andrejs Kotovs for the Latvian translation" - and *%s* for using and supporting the app! :) - Something is wrong with the app? Got a suggestion? Send an email at %s - You - On - Off - Thank you for supporting the app - Donate - Loading… - Search - Contacts - Nameday on - Show more - Create - - (No name) - Include year? - Save - Add - No birthday set - No nameday for the name %s - Edit - Add birthday - Search - and - Greek - Czech - Slovak - Russian - Latvian - Hungarian - Nameday Calendar - Silent - "Memento - Namedays" - Share - Support the app - Open Facebook Page - How would you rate the app? - "It\'s pretty much horrible" - "I don't like it" - "It's okay" - "It's good" - "I LOVE it!" - Rate - Message - %1$s turns %2$d - No results found - %d contacts celebrate today - Today\'s Namedays - "Today's nameday" - "Today's namedays" - %s via… - Like Page - Rate the app - Like Facebook Page - Namedays for %1$s - Get %1$s at %2$s - You can hide names you don\'t want to appear in the app, by long pressing on them. - OK, got it - Namedays will be displayed for stored contacts only - Namedays will be displays for the namedays of all year - Namedays for Contacts only - I hope you enjoy using the app, and it is useful for you. Here are some ways you can support the app: - Translate the app - Translating the app - Visit the following url from your computer browser - - Copy Link - Link copied to clipboard - Select the amount you would like to donate - Open Wall - View contact - No birthday set - "No contacts with special events found.\nTap the '+' to add some" - "No contacts with special events found" - Add birthday - Birthday date - Contact name - Themes - Romanian - Configure Widget - Done - Transparency - Dark theme? - Contact Names - Bank holiday - Bank holidays - Google+ community - Display Bankholidays - Bankholidays Country - Bankholidays are currently supported only for Greek + and *%s* for using and supporting the app! :) + Something is wrong with the app? Got a suggestion? Send an email at %s + You + On + Off + Thank you for supporting the app + Donate + Loading… + Search + Contacts + Nameday on + Show more + Create + + (No name) + Include year? + Save + Add + No birthday set + No nameday for the name %s + Edit + Add birthday + Search + and + Greek + Czech + Slovak + Russian + Latvian + Hungarian + Nameday Calendar + Silent + "Memento - Namedays" + Share + Support the app + Open Facebook Page + How would you rate the app? + "It\'s pretty much horrible" + "I don't like it" + "It's okay" + "It's good" + "I LOVE it!" + Rate + Message + %1$s turns %2$d + No results found + %d contacts celebrate today + Today\'s Namedays + "Today's nameday" + "Today's namedays" + %s via… + Like Page + Rate the app + Like Facebook Page + Namedays for %1$s + Get %1$s at %2$s + You can hide names you don\'t want to appear in the app, by long pressing on them. + OK, got it + Namedays will be displayed for stored contacts only + Namedays will be displays for the namedays of all year + Namedays for Contacts only + I hope you enjoy using the app, and it is useful for you. Here are some ways you can support the app: + Translate the app + Translating the app + Visit the following url from your computer browser + + Copy Link + Link copied to clipboard + Select the amount you would like to donate + Open Wall + View contact + No birthday set + "No contacts with special events found.\nTap the '+' to add some" + "No contacts with special events found" + Add birthday + Birthday date + Contact name + Themes + Romanian + Configure Widget + Done + Transparency + Dark theme? + Contact Names + Bank holiday + Bank holidays + Google+ community + Display Bankholidays + Bankholidays Country + Bankholidays are currently supported only for Greek + Search for contacts + Search for contacts or namedays diff --git a/mobile/src/main/res/values/toolbar-resources.xml b/mobile/src/main/res/values/toolbar-resources.xml index b12f1776..250e5b71 100644 --- a/mobile/src/main/res/values/toolbar-resources.xml +++ b/mobile/src/main/res/values/toolbar-resources.xml @@ -2,4 +2,7 @@ 4dp 56dp + 64dp + + diff --git a/mobile/src/main/res/values/upcoming-resources.xml b/mobile/src/main/res/values/upcoming-resources.xml index 694a11d4..fdb6a65e 100644 --- a/mobile/src/main/res/values/upcoming-resources.xml +++ b/mobile/src/main/res/values/upcoming-resources.xml @@ -16,6 +16,15 @@ +