From f0257429eb02a7acc7c7b776bb6b2107c62fa60c Mon Sep 17 00:00:00 2001 From: korelstar Date: Sun, 15 Oct 2017 10:16:50 +0200 Subject: [PATCH 1/2] categories in navigation drawer --- app/src/main/AndroidManifest.xml | 13 +- .../android/AlwaysAutoCompleteTextView.java | 48 ++ .../android/activity/CreateNoteActivity.java | 12 +- .../android/activity/EditNoteActivity.java | 3 +- .../activity/NotesListViewActivity.java | 473 +++++++++++------- .../activity/SelectSingleNoteActivity.java | 27 +- .../fragment/CategoryDialogFragment.java | 132 ++++- .../owncloud/notes/model/Category.java | 18 + .../niedermann/owncloud/notes/model/Item.java | 3 - .../owncloud/notes/model/ItemAdapter.java | 75 ++- .../notes/model/NavigationAdapter.java | 146 ++++++ .../owncloud/notes/model/SectionItem.java | 6 +- .../notes/persistence/LoadNotesListTask.java | 141 ++++++ .../persistence/NoteSQLiteOpenHelper.java | 137 +++-- .../owncloud/notes/util/NoteUtil.java | 25 +- .../owncloud/notes/util/NotesClient.java | 11 +- .../owncloud/notes/util/NotesClientUtil.java | 5 +- .../drawable-hdpi/ic_clock_grey600_24dp.png | Bin 0 -> 1511 bytes .../drawable-hdpi/ic_folder_grey600_18dp.png | Bin 0 -> 530 bytes .../drawable-hdpi/ic_folder_grey600_24dp.png | Bin 0 -> 533 bytes .../ic_folder_outline_grey600_24dp.png | Bin 0 -> 552 bytes .../ic_folder_plus_grey600_18dp.png | Bin 0 -> 678 bytes .../ic_folder_plus_grey600_24dp.png | Bin 0 -> 627 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 1428 bytes .../drawable-hdpi/ic_tune_grey600_24dp.png | Bin 0 -> 578 bytes .../drawable-mdpi/ic_clock_grey600_24dp.png | Bin 0 -> 1044 bytes .../drawable-mdpi/ic_folder_grey600_18dp.png | Bin 0 -> 463 bytes .../drawable-mdpi/ic_folder_grey600_24dp.png | Bin 0 -> 448 bytes .../ic_folder_outline_grey600_24dp.png | Bin 0 -> 468 bytes .../ic_folder_plus_grey600_18dp.png | Bin 0 -> 533 bytes .../ic_folder_plus_grey600_24dp.png | Bin 0 -> 488 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 972 bytes .../drawable-mdpi/ic_tune_grey600_24dp.png | Bin 0 -> 412 bytes .../drawable-xhdpi/ic_clock_grey600_24dp.png | Bin 0 -> 1869 bytes .../drawable-xhdpi/ic_folder_grey600_18dp.png | Bin 0 -> 533 bytes .../drawable-xhdpi/ic_folder_grey600_24dp.png | Bin 0 -> 596 bytes .../ic_folder_outline_grey600_24dp.png | Bin 0 -> 621 bytes .../ic_folder_plus_grey600_18dp.png | Bin 0 -> 627 bytes .../ic_folder_plus_grey600_24dp.png | Bin 0 -> 639 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 1692 bytes .../drawable-xhdpi/ic_tune_grey600_24dp.png | Bin 0 -> 463 bytes .../drawable-xxhdpi/ic_clock_grey600_24dp.png | Bin 0 -> 2628 bytes .../ic_folder_grey600_18dp.png | Bin 0 -> 684 bytes .../ic_folder_grey600_24dp.png | Bin 0 -> 811 bytes .../ic_folder_outline_grey600_24dp.png | Bin 0 -> 829 bytes .../ic_folder_plus_grey600_18dp.png | Bin 0 -> 794 bytes .../ic_folder_plus_grey600_24dp.png | Bin 0 -> 851 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 2387 bytes .../drawable-xxhdpi/ic_tune_grey600_24dp.png | Bin 0 -> 532 bytes .../ic_clock_grey600_24dp.png | Bin 0 -> 3473 bytes .../ic_folder_grey600_18dp.png | Bin 0 -> 811 bytes .../ic_folder_grey600_24dp.png | Bin 0 -> 942 bytes .../ic_folder_outline_grey600_24dp.png | Bin 0 -> 966 bytes .../ic_folder_plus_grey600_18dp.png | Bin 0 -> 851 bytes .../ic_folder_plus_grey600_24dp.png | Bin 0 -> 986 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 3203 bytes .../drawable-xxxhdpi/ic_tune_grey600_24dp.png | Bin 0 -> 586 bytes .../res/layout/activity_notes_list_view.xml | 40 +- .../res/layout/dialog_change_category.xml | 23 +- app/src/main/res/layout/drawer_layout.xml | 94 ++++ app/src/main/res/layout/item_navigation.xml | 44 ++ app/src/main/res/menu/menu_list_view.xml | 17 +- app/src/main/res/values/strings.xml | 7 +- app/src/main/res/values/styles.xml | 16 +- 64 files changed, 1172 insertions(+), 344 deletions(-) create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/android/AlwaysAutoCompleteTextView.java create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/model/Category.java create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java create mode 100644 app/src/main/res/drawable-hdpi/ic_clock_grey600_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_grey600_18dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_grey600_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_18dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_tune_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_clock_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_grey600_18dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_18dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_tune_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_clock_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_grey600_18dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_18dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_tune_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_clock_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_grey600_18dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_18dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_tune_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_clock_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_18dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_18dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_tune_grey600_24dp.png create mode 100644 app/src/main/res/layout/drawer_layout.xml create mode 100644 app/src/main/res/layout/item_navigation.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 45143ee47..45663fe75 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,8 @@ android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" android:supportsRtl="true" - android:theme="@style/OwnCloud"> + android:theme="@style/AppTheme"> + @@ -21,9 +22,12 @@ + + android:label="@string/app_name" + android:theme="@style/AppTheme.NoActionBar" + > @@ -78,8 +82,9 @@ /> - + android:name=".android.activity.SelectSingleNoteActivity" + android:theme="@style/AppTheme.NoActionBar" + > diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/AlwaysAutoCompleteTextView.java b/app/src/main/java/it/niedermann/owncloud/notes/android/AlwaysAutoCompleteTextView.java new file mode 100644 index 000000000..c756d168c --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/AlwaysAutoCompleteTextView.java @@ -0,0 +1,48 @@ +package it.niedermann.owncloud.notes.android; + +import android.content.Context; +import android.support.v7.widget.AppCompatAutoCompleteTextView; +import android.util.AttributeSet; + +/** + * Extension of the {@link AppCompatAutoCompleteTextView}, but this one is always open, i.e. you can see the list of suggestions even the TextView is empty. + */ +public class AlwaysAutoCompleteTextView extends AppCompatAutoCompleteTextView { + + private int myThreshold; + + public AlwaysAutoCompleteTextView(Context context) { + super(context); + } + + public AlwaysAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public AlwaysAutoCompleteTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void setThreshold(int threshold) { + if (threshold < 0) { + threshold = 0; + } + myThreshold = threshold; + } + + @Override + public boolean enoughToFilter() { + return getText().length() >= myThreshold; + } + + @Override + public int getThreshold() { + return myThreshold; + } + + public void showFullDropDown() { + performFiltering(getText(), 0); + showDropDown(); + } +} \ No newline at end of file diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java index fb19e0979..ac27fcd3b 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/CreateNoteActivity.java @@ -12,15 +12,19 @@ import com.yydcdut.rxmarkdown.syntax.edit.EditFactory; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.model.Category; import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper; import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper; import it.niedermann.owncloud.notes.util.MarkDownUtil; import rx.Subscriber; public class CreateNoteActivity extends AppCompatActivity { + + public static final String PARAM_CATEGORY = "category"; private final static int server_settings = 2; private RxMDEditText editTextField = null; + private Category categoryPreselection; @Override protected void onCreate(Bundle savedInstanceState) { @@ -39,6 +43,10 @@ protected void onCreate(Bundle savedInstanceState) { String action = intent.getAction(); String type = intent.getType(); + if(intent.hasExtra(PARAM_CATEGORY)) { + categoryPreselection = (Category) intent.getSerializableExtra(PARAM_CATEGORY); + } + if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { editTextField.setText(intent.getStringExtra(Intent.EXTRA_TEXT)); @@ -104,7 +112,9 @@ private void saveAndClose(boolean implicit) { if(!implicit || !content.isEmpty()) { NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(this); Intent data = new Intent(this, NotesListViewActivity.class); - data.putExtra(NotesListViewActivity.CREATED_NOTE, db.getNote(db.addNoteAndSync(content))); + String category = categoryPreselection==null ? null : categoryPreselection.category; + boolean favorite = categoryPreselection!=null && categoryPreselection.favorite!=null ? categoryPreselection.favorite : false; + data.putExtra(NotesListViewActivity.CREATED_NOTE, db.getNote(db.addNoteAndSync(content, category, favorite))); setResult(RESULT_OK, data); } finish(); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java index edbd43bb5..c61d794c2 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/EditNoteActivity.java @@ -236,8 +236,7 @@ private void showCategorySelector() { @Override public void onCategoryChosen(String category) { DBNote note = fragment.getNote(); - note.setCategory(category); - db.updateNoteAndSync(note, note.getContent(), null); + db.setCategory(note, category, null); } /** diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java index 6d4747917..65588b2a7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java @@ -5,19 +5,24 @@ import android.app.SearchManager; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.graphics.Canvas; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.view.MenuItemCompat; +import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.app.NotificationCompat; import android.support.v7.view.ActionMode; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; +import android.support.v7.widget.Toolbar; import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback; import android.util.Log; @@ -27,32 +32,45 @@ import android.widget.Toast; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; +import java.util.Map; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.model.Category; import it.niedermann.owncloud.notes.model.DBNote; import it.niedermann.owncloud.notes.model.Item; import it.niedermann.owncloud.notes.model.ItemAdapter; -import it.niedermann.owncloud.notes.model.SectionItem; +import it.niedermann.owncloud.notes.model.NavigationAdapter; +import it.niedermann.owncloud.notes.persistence.LoadNotesListTask; import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper; import it.niedermann.owncloud.notes.persistence.NoteServerSyncHelper; import it.niedermann.owncloud.notes.util.ICallback; +import it.niedermann.owncloud.notes.util.NoteUtil; import it.niedermann.owncloud.notes.util.NotesClientUtil; -public class NotesListViewActivity extends AppCompatActivity implements - ItemAdapter.NoteClickListener, View.OnClickListener { +public class NotesListViewActivity extends AppCompatActivity implements ItemAdapter.NoteClickListener { public final static String CREATED_NOTE = "it.niedermann.owncloud.notes.created_notes"; public final static String CREDENTIALS_CHANGED = "it.niedermann.owncloud.notes.CREDENTIALS_CHANGED"; + private static final String ADAPTER_KEY_RECENT = "recent"; + private static final String ADAPTER_KEY_STARRED = "starred"; + private static final String SAVED_STATE_NAVIGATION_SELECTION = "navigationSelection"; + private static final String SAVED_STATE_NAVIGATION_ADAPTER_SLECTION = "navigationAdapterSelection"; + private static final String SAVED_STATE_NAVIGATION_OPEN = "navigationOpen"; + private final static int create_note_cmd = 0; private final static int show_single_note_cmd = 1; private final static int server_settings = 2; private final static int about = 3; - private RecyclerView listView = null; + private DrawerLayout drawerLayout; + private ActionBarDrawerToggle drawerToggle; private ItemAdapter adapter = null; + private NavigationAdapter adapterCategories; + private NavigationAdapter.NavigationItem itemRecent, itemStarred, itemUncategorized; + private Category navigationSelection = new Category(null, null); + private String navigationOpen = ""; private ActionMode mActionMode; private SwipeRefreshLayout swipeRefreshLayout = null; private NoteSQLiteOpenHelper db = null; @@ -64,7 +82,7 @@ public void onFinish() { if (mActionMode != null) { mActionMode.finish(); } - refreshList(); + refreshLists(); swipeRefreshLayout.setRefreshing(false); } @@ -77,77 +95,37 @@ public void onScheduled() { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // First Run Wizard - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); if (!NoteServerSyncHelper.isConfigured(this)) { Intent settingsIntent = new Intent(this, SettingsActivity.class); startActivityForResult(settingsIntent, server_settings); } + String categoryAdapterSelectedItem=ADAPTER_KEY_RECENT; + if(savedInstanceState!=null) { + navigationSelection = (Category) savedInstanceState.getSerializable(SAVED_STATE_NAVIGATION_SELECTION); + navigationOpen = savedInstanceState.getString(SAVED_STATE_NAVIGATION_OPEN); + categoryAdapterSelectedItem = savedInstanceState.getString(SAVED_STATE_NAVIGATION_ADAPTER_SLECTION); + } - setContentView(R.layout.activity_notes_list_view); + setContentView(R.layout.drawer_layout); - // Display Data db = NoteSQLiteOpenHelper.getInstance(this); - initList(); - refreshList(); - // Pull to Refresh - swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefreshlayout); - swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if(db.getNoteServerSyncHelper().isSyncPossible()) { - synchronize(); - } else { - swipeRefreshLayout.setRefreshing(false); - Toast.makeText(getApplicationContext(), getString(R.string.error_sync, getString(NotesClientUtil.LoginStatus.NO_NETWORK.str)), Toast.LENGTH_LONG).show(); - } - } - }); - - // Floating Action Button - findViewById(R.id.fab_create).setOnClickListener(this); + setupActionBar(); + setupNotesList(); + setupNavigationList(categoryAdapterSelectedItem); + setupNavigationMenu(); // Show persistant notification for creating a new note checkNotificationSetting(); } - protected void checkNotificationSetting(){ - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - Boolean showNotification = preferences.getBoolean(getString(R.string.pref_key_show_notification), false); - if(showNotification==true){ - // add notification - NotificationCompat.Builder builder = new NotificationCompat.Builder(this); - PendingIntent newNoteIntent = PendingIntent.getActivity(this, 0, - new Intent(this, CreateNoteActivity.class) - .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP), - 0); - builder.setSmallIcon(R.drawable.ic_action_new) - .setContentTitle(getString(R.string.action_create)) - .setContentText("") - .setOngoing(true) - .setContentIntent(newNoteIntent) - .setVisibility(NotificationCompat.VISIBILITY_SECRET); - NotificationManager notificationManager = (NotificationManager) getSystemService( - NOTIFICATION_SERVICE); - - notificationManager.notify(10, builder.build()); - } - else{ - // remove notification - NotificationManager nMgr = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE); - nMgr.cancel(10); - } - } - @Override protected void onResume() { // Show persistant notification for creating a new note checkNotificationSetting(); // refresh and sync every time the activity gets visible - refreshList(); + refreshLists(); db.getNoteServerSyncHelper().addCallbackPull(syncCallBack); if (db.getNoteServerSyncHelper().isSyncPossible()) { synchronize(); @@ -155,125 +133,247 @@ protected void onResume() { super.onResume(); } - /** - * Click listener for Floating Action Button - *

- * Creates a new Instance of CreateNoteActivity. - * - * @param v View - */ @Override - public void onClick(View v) { - Intent createIntent = new Intent(this, CreateNoteActivity.class); - startActivityForResult(createIntent, create_note_cmd); + protected void onPostCreate(@Nullable Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + drawerToggle.syncState(); } - /** - * Allows other classes to refresh the List of Notes. Starts an AsyncTask which loads the data in the background. - */ - public void refreshList() { - new RefreshListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + drawerToggle.syncState(); } - private class RefreshListTask extends AsyncTask> { + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable(SAVED_STATE_NAVIGATION_SELECTION, navigationSelection); + outState.putString(SAVED_STATE_NAVIGATION_ADAPTER_SLECTION, adapterCategories.getSelectedItem()); + outState.putString(SAVED_STATE_NAVIGATION_OPEN, navigationOpen); + } - private CharSequence query = null; + private void setupActionBar() { + Toolbar toolbar = findViewById(R.id.notesListActivityActionBar); + setSupportActionBar(toolbar); + drawerLayout = findViewById(R.id.drawerLayout); + drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.action_drawer_open, R.string.action_drawer_close); + drawerToggle.setDrawerIndicatorEnabled(true); + drawerLayout.addDrawerListener(drawerToggle); + } - @Override - protected void onPreExecute() { - if(searchView != null && !searchView.isIconified() && searchView.getQuery().length() != 0) { - query = searchView.getQuery(); + private void setupNotesList() { + initList(); + // Pull to Refresh + swipeRefreshLayout = findViewById(R.id.swiperefreshlayout); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + if(db.getNoteServerSyncHelper().isSyncPossible()) { + synchronize(); + } else { + swipeRefreshLayout.setRefreshing(false); + Toast.makeText(getApplicationContext(), getString(R.string.error_sync, getString(NotesClientUtil.LoginStatus.NO_NETWORK.str)), Toast.LENGTH_LONG).show(); + } } - } + }); + + // Floating Action Button + findViewById(R.id.fab_create).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent createIntent = new Intent(getApplicationContext(), CreateNoteActivity.class); + createIntent.putExtra(CreateNoteActivity.PARAM_CATEGORY, navigationSelection); + startActivityForResult(createIntent, create_note_cmd); + } + }); + } + + private void setupNavigationList(String selectedItem) { + itemRecent = new NavigationAdapter.NavigationItem(ADAPTER_KEY_RECENT, getString(R.string.action_recent), null, R.drawable.ic_clock_grey600_24dp); + itemStarred = new NavigationAdapter.NavigationItem(ADAPTER_KEY_STARRED, getString(R.string.action_starred), null, R.drawable.ic_star_grey600_24dp); + adapterCategories = new NavigationAdapter(new NavigationAdapter.ClickListener() { + @Override + public void onItemClick(NavigationAdapter.NavigationItem item) { + adapterCategories.setSelectedItem(item.id); + // update current selection + if(itemRecent == item) { + navigationSelection = new Category(null, null); + } else if(itemStarred == item) { + navigationSelection = new Category(null, true); + } else if(itemUncategorized == item) { + navigationSelection = new Category("", null); + } else { + navigationSelection = new Category(item.label, null); + } + // auto-close sub-folder in Navigation if selection is outside of that folder + if(navigationOpen != null) { + int slashIndex = navigationSelection.category==null ? -1 : navigationSelection.category.indexOf('/'); + String rootCategory = slashIndex<0 ? navigationSelection.category : navigationSelection.category.substring(0, slashIndex); + if (!navigationOpen.equals(rootCategory)) { + navigationOpen = null; + } + } + // update views + drawerLayout.closeDrawers(); + refreshLists(); + } + + @Override + public void onIconClick(NavigationAdapter.NavigationItem item) { + if(item.icon == NavigationAdapter.ICON_MULTIPLE && !item.label.equals(navigationOpen)) { + navigationOpen = item.label; + refreshLists(); + } else if(item.icon== NavigationAdapter.ICON_MULTIPLE || item.icon==NavigationAdapter.ICON_MULTIPLE_OPEN && item.label.equals(navigationOpen)) { + navigationOpen = null; + refreshLists(); + } else { + onItemClick(item); + } + } + }); + adapterCategories.setSelectedItem(selectedItem); + RecyclerView listNavigationCategories = findViewById(R.id.navigationList); + listNavigationCategories.setAdapter(adapterCategories); + } + private class LoadCategoryListTask extends AsyncTask> { @Override - protected List doInBackground(Void... voids) { - List noteList; - if (query==null) { - noteList = db.getNotes(); + protected List doInBackground(Void... voids) { + List categories = db.getCategories(); + if(!categories.isEmpty() && categories.get(0).label.isEmpty()) { + itemUncategorized = categories.get(0); + itemUncategorized.label = getString(R.string.action_uncategorized); + itemUncategorized.icon = NavigationAdapter.ICON_NOFOLDER; } else { - noteList = db.searchNotes(query); + itemUncategorized = null; } - final List itemList = new ArrayList<>(); - // #12 Create Sections depending on Time - // TODO Move to ItemAdapter? - boolean todaySet, yesterdaySet, weekSet, monthSet, earlierSet; - todaySet = yesterdaySet = weekSet = monthSet = earlierSet = false; - Calendar recent = Calendar.getInstance(); - Calendar today = Calendar.getInstance(); - today.set(Calendar.HOUR_OF_DAY, 0); - today.set(Calendar.MINUTE, 0); - today.set(Calendar.SECOND, 0); - today.set(Calendar.MILLISECOND, 0); - Calendar yesterday = Calendar.getInstance(); - yesterday.set(Calendar.DAY_OF_YEAR, yesterday.get(Calendar.DAY_OF_YEAR) - 1); - yesterday.set(Calendar.HOUR_OF_DAY, 0); - yesterday.set(Calendar.MINUTE, 0); - yesterday.set(Calendar.SECOND, 0); - yesterday.set(Calendar.MILLISECOND, 0); - Calendar week = Calendar.getInstance(); - week.set(Calendar.DAY_OF_WEEK, week.getFirstDayOfWeek()); - week.set(Calendar.HOUR_OF_DAY, 0); - week.set(Calendar.MINUTE, 0); - week.set(Calendar.SECOND, 0); - week.set(Calendar.MILLISECOND, 0); - Calendar month = Calendar.getInstance(); - month.set(Calendar.DAY_OF_MONTH, 0); - month.set(Calendar.HOUR_OF_DAY, 0); - month.set(Calendar.MINUTE, 0); - month.set(Calendar.SECOND, 0); - month.set(Calendar.MILLISECOND, 0); - for (int i = 0; i < noteList.size(); i++) { - DBNote currentNote = noteList.get(i); - if (currentNote.isFavorite()) { - // don't show as new section - } else if (!todaySet && currentNote.getModified().getTimeInMillis() >= today.getTimeInMillis()) { - // after 00:00 today - if (i > 0) { - itemList.add(new SectionItem(getResources().getString(R.string.listview_updated_today))); - } - todaySet = true; - } else if (!yesterdaySet && currentNote.getModified().getTimeInMillis() < today.getTimeInMillis() && currentNote.getModified().getTimeInMillis() >= yesterday.getTimeInMillis()) { - // between today 00:00 and yesterday 00:00 - if (i > 0) { - itemList.add(new SectionItem(getResources().getString(R.string.listview_updated_yesterday))); - } - yesterdaySet = true; - } else if (!weekSet && currentNote.getModified().getTimeInMillis() < yesterday.getTimeInMillis() && currentNote.getModified().getTimeInMillis() >= week.getTimeInMillis()) { - // between yesterday 00:00 and start of the week 00:00 - if (i > 0) { - itemList.add(new SectionItem(getResources().getString(R.string.listview_updated_this_week))); - } - weekSet = true; - } else if (!monthSet && currentNote.getModified().getTimeInMillis() < week.getTimeInMillis() && currentNote.getModified().getTimeInMillis() >= month.getTimeInMillis()) { - // between start of the week 00:00 and start of the month 00:00 - if (i > 0) { - itemList.add(new SectionItem(getResources().getString(R.string.listview_updated_this_month))); + Map favorites = db.getFavoritesCount(); + int numFavorites = favorites.containsKey("1") ? favorites.get("1") : 0; + int numNonFavorites = favorites.containsKey("0") ? favorites.get("0") : 0; + itemStarred.count = numFavorites; + itemRecent.count = numFavorites + numNonFavorites; + + ArrayList items = new ArrayList<>(); + items.add(itemRecent); + items.add(itemStarred); + NavigationAdapter.NavigationItem lastPrimaryCategory = null, lastSecondaryCategory = null; + for (NavigationAdapter.NavigationItem item : categories) { + int slashIndex = item.label.indexOf('/'); + String currentPrimaryCategory = slashIndex<0 ? item.label : item.label.substring(0, slashIndex); + String currentSecondaryCategory = null; + boolean isCategoryOpen = currentPrimaryCategory.equals(navigationOpen); + + if(isCategoryOpen && !currentPrimaryCategory.equals(item.label)) { + String currentCategorySuffix = item.label.substring(navigationOpen.length()+1); + int subSlashIndex = currentCategorySuffix.indexOf('/'); + currentSecondaryCategory = subSlashIndex<0 ? currentCategorySuffix : currentCategorySuffix.substring(0, subSlashIndex); + } + + boolean belongsToLastPrimaryCategory = lastPrimaryCategory!=null && currentPrimaryCategory.equals(lastPrimaryCategory.label); + boolean belongsToLastSecondaryCategory = belongsToLastPrimaryCategory && lastSecondaryCategory!=null && lastSecondaryCategory.label.equals(currentPrimaryCategory+"/"+currentSecondaryCategory); + + if(isCategoryOpen && !belongsToLastPrimaryCategory && currentSecondaryCategory!=null) { + lastPrimaryCategory = new NavigationAdapter.NavigationItem("category:"+currentPrimaryCategory, currentPrimaryCategory, 0, NavigationAdapter.ICON_MULTIPLE_OPEN); + items.add(lastPrimaryCategory); + belongsToLastPrimaryCategory = true; + } + + if(belongsToLastPrimaryCategory && belongsToLastSecondaryCategory) { + lastSecondaryCategory.count += item.count; + lastSecondaryCategory.icon = NavigationAdapter.ICON_SUB_MULTIPLE; + } else if(belongsToLastPrimaryCategory) { + if(isCategoryOpen) { + item.label = currentPrimaryCategory + "/" + currentSecondaryCategory; + item.icon = NavigationAdapter.ICON_SUB_FOLDER; + items.add(item); + lastSecondaryCategory = item; + } else { + lastPrimaryCategory.count += item.count; + lastPrimaryCategory.icon = NavigationAdapter.ICON_MULTIPLE; + lastSecondaryCategory = null; } - monthSet = true; - } else if (!earlierSet && currentNote.getModified().getTimeInMillis() < month.getTimeInMillis()) { - // before start of the month 00:00 - if (i > 0) { - itemList.add(new SectionItem(getResources().getString(R.string.listview_updated_earlier))); + } else { + if(isCategoryOpen) { + item.icon = NavigationAdapter.ICON_MULTIPLE_OPEN; + } else { + item.label = currentPrimaryCategory; } - earlierSet = true; + items.add(item); + lastPrimaryCategory = item; + lastSecondaryCategory = null; } - itemList.add(currentNote); } - - return itemList; + return items; } @Override - protected void onPostExecute(List items) { - adapter.setItemList(items); + protected void onPostExecute(List items) { + adapterCategories.setItems(items); + } + } + + private void setupNavigationMenu() { + final NavigationAdapter.NavigationItem itemSettings = new NavigationAdapter.NavigationItem("settings", getString(R.string.action_settings), null, R.drawable.ic_tune_grey600_24dp); + final NavigationAdapter.NavigationItem itemAbout = new NavigationAdapter.NavigationItem("about", getString(R.string.action_about), null, R.drawable.ic_information_outline_grey600_24dp); + + ArrayList itemsMenu = new ArrayList<>(); + itemsMenu.add(itemSettings); + itemsMenu.add(itemAbout); + + NavigationAdapter adapterMenu = new NavigationAdapter(new NavigationAdapter.ClickListener() { + @Override + public void onItemClick(NavigationAdapter.NavigationItem item) { + if(item == itemSettings) { + Intent settingsIntent = new Intent(getApplicationContext(), PreferencesActivity.class); + startActivityForResult(settingsIntent, server_settings); + } else if(item == itemAbout) { + Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class); + startActivityForResult(aboutIntent, about); + } + } + + @Override + public void onIconClick(NavigationAdapter.NavigationItem item) { + onItemClick(item); + } + }); + adapterMenu.setItems(itemsMenu); + RecyclerView listNavigationMenu = findViewById(R.id.navigationMenu); + listNavigationMenu.setAdapter(adapterMenu); + } + + protected void checkNotificationSetting() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + boolean showNotification = preferences.getBoolean(getString(R.string.pref_key_show_notification), false); + if (showNotification) { + // add notification + NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + PendingIntent newNoteIntent = PendingIntent.getActivity(this, 0, + new Intent(this, CreateNoteActivity.class) + .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP), + 0); + builder.setSmallIcon(R.drawable.ic_action_new) + .setContentTitle(getString(R.string.action_create)) + .setContentText("") + .setOngoing(true) + .setContentIntent(newNoteIntent) + .setVisibility(NotificationCompat.VISIBILITY_SECRET); + NotificationManager notificationManager = (NotificationManager) getSystemService( + NOTIFICATION_SERVICE); + + notificationManager.notify(10, builder.build()); + } else { + // remove notification + NotificationManager nMgr = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE); + nMgr.cancel(10); } } public void initList() { adapter = new ItemAdapter(this); - listView = (RecyclerView) findViewById(R.id.recycler_view); + RecyclerView listView = findViewById(R.id.recycler_view); listView.setAdapter(adapter); listView.setLayoutManager(new LinearLayoutManager(this)); ItemTouchHelper touchHelper = new ItemTouchHelper(new SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { @@ -307,14 +407,14 @@ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { final DBNote dbNote = (DBNote) adapter.getItem(viewHolder.getAdapterPosition()); db.deleteNoteAndSync((dbNote).getId()); adapter.remove(dbNote); - refreshList(); + refreshLists(); Log.v("Note", "Item deleted through swipe ----------------------------------------------"); Snackbar.make(swipeRefreshLayout, R.string.action_note_deleted, Snackbar.LENGTH_LONG) .setAction(R.string.action_undo, new View.OnClickListener() { @Override public void onClick(View v) { db.addNoteAndSync(dbNote); - refreshList(); + refreshLists(); Snackbar.make(swipeRefreshLayout, R.string.action_note_restored, Snackbar.LENGTH_SHORT) .show(); } @@ -340,6 +440,35 @@ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHol touchHelper.attachToRecyclerView(listView); } + private void refreshLists() { + String subtitle = ""; + if(navigationSelection.category!=null) { + if(navigationSelection.category.isEmpty()) { + subtitle = getString(R.string.action_uncategorized); + } else { + subtitle = NoteUtil.extendCategory(navigationSelection.category); + } + } else if(navigationSelection.favorite!=null && navigationSelection.favorite) { + subtitle = getString(R.string.action_starred); + } else { + subtitle = getString(R.string.action_recent); + } + getSupportActionBar().setSubtitle(subtitle); + CharSequence query = null; + if(searchView != null && !searchView.isIconified() && searchView.getQuery().length() != 0) { + query = searchView.getQuery(); + } + LoadNotesListTask.NotesLoadedListener callback = new LoadNotesListTask.NotesLoadedListener() { + @Override + public void onNotesLoaded(List notes, boolean showCategory) { + adapter.setShowCategory(showCategory); + adapter.setItemList(notes); + } + }; + new LoadNotesListTask(getApplicationContext(), callback, navigationSelection, query).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new LoadCategoryListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + public ItemAdapter getItemAdapter() { return adapter; } @@ -368,7 +497,7 @@ public boolean onQueryTextSubmit(String query) { @Override public boolean onQueryTextChange(String newText) { - refreshList(); + refreshLists(); return true; } }); @@ -383,29 +512,6 @@ protected void onNewIntent(Intent intent) { super.onNewIntent(intent); } - /** - * Handels click events on the Buttons in the Action Bar. - * - * @param item MenuItem - the clicked menu item - * @return boolean - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - switch (id) { - case R.id.action_settings: - Intent settingsIntent = new Intent(this, PreferencesActivity.class); - startActivityForResult(settingsIntent, server_settings); - return true; - case R.id.action_about: - Intent aboutIntent = new Intent(this, AboutActivity.class); - startActivityForResult(aboutIntent, about); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - /** * Handles the Results of started Sub Activities (Created Note, Edited Note) * @@ -423,7 +529,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { DBNote createdNote = (DBNote) data.getExtras().getSerializable(CREATED_NOTE); adapter.add(createdNote); - //setListView(db.getNotes()); + // TODO scroll to top } } else if (requestCode == show_single_note_cmd) { if (resultCode == RESULT_OK || resultCode == RESULT_FIRST_USER) { @@ -436,7 +542,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { DBNote editedNote = (DBNote) data.getExtras().getSerializable(EditNoteActivity.PARAM_NOTE); adapter.replace(editedNote, notePosition); - refreshList(); + refreshLists(); } } } @@ -496,7 +602,7 @@ public void onNoteFavoriteClick(int position, View view) { NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(view.getContext()); db.toggleFavorite(note, syncCallBack); adapter.notifyItemChanged(position); - refreshList(); + refreshLists(); } @Override @@ -533,8 +639,7 @@ private class MultiSelectedActionModeCallback implements ActionMode.Callback { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // inflate contextual menu - mode.getMenuInflater().inflate(R.menu.menu_list_context_multiple, - menu); + mode.getMenuInflater().inflate(R.menu.menu_list_context_multiple, menu); return true; } @@ -562,7 +667,7 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) { mode.finish(); // Action picked, so close the CAB //after delete selection has to be cleared searchView.setIconified(true); - refreshList(); + refreshLists(); return true; default: return false; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java index 26fe4268d..baac35bac 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/SelectSingleNoteActivity.java @@ -4,15 +4,9 @@ import android.appwidget.AppWidgetManager; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.drawable.ColorDrawable; -import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.v4.content.ContextCompat; import android.support.v4.widget.SwipeRefreshLayout; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; import android.view.Menu; import android.view.View; @@ -27,31 +21,16 @@ public class SelectSingleNoteActivity extends NotesListViewActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ColorDrawable color; android.support.v7.app.ActionBar ab = getSupportActionBar(); SwipeRefreshLayout swipeRefreshLayout = getSwipeRefreshLayout(); setResult(Activity.RESULT_CANCELED); - findViewById(R.id.fab_create).setVisibility(View.INVISIBLE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - color = new ColorDrawable(getColor(R.color.bg_highlighted)); - } else { - color = new ColorDrawable(ContextCompat.getColor(getApplicationContext(), - R.color.bg_highlighted)); + findViewById(R.id.fab_create).setVisibility(View.GONE); + if(ab != null) { + ab.setTitle(R.string.activity_select_single_note); } - - ab.setBackgroundDrawable(color); - ab.setTitle(R.string.activity_select_single_note); - Spannable title = new SpannableString(ab.getTitle()); - title.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.primary)), - 0, - title.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - ab.setTitle(title); swipeRefreshLayout.setEnabled(false); swipeRefreshLayout.setRefreshing(false); - initList(); } @Override diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java index d21dce6a5..d884ba0e7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/fragment/CategoryDialogFragment.java @@ -4,12 +4,23 @@ import android.app.Dialog; import android.app.DialogFragment; import android.app.Fragment; +import android.content.Context; import android.content.DialogInterface; +import android.os.AsyncTask; import android.os.Bundle; +import android.support.annotation.NonNull; import android.view.View; -import android.widget.EditText; +import android.view.WindowManager; +import android.widget.ArrayAdapter; +import android.widget.Filter; + +import java.util.ArrayList; +import java.util.List; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.android.AlwaysAutoCompleteTextView; +import it.niedermann.owncloud.notes.model.NavigationAdapter; +import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper; /** * This {@link DialogFragment} allows for the selection of a category. @@ -31,19 +42,22 @@ public interface CategoryDialogListener { public static final String PARAM_CATEGORY = "category"; - private EditText textCategory; + private AlwaysAutoCompleteTextView textCategory; + private FolderArrayAdapter adapter; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { View dialogView = getActivity().getLayoutInflater().inflate(R.layout.dialog_change_category, null); - textCategory = (EditText) dialogView.findViewById(R.id.editCategory); + textCategory = dialogView.findViewById(R.id.editCategory); if(savedInstanceState==null) { textCategory.setText(getArguments().getString(PARAM_CATEGORY)); } + adapter = new FolderArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item); + textCategory.setAdapter(adapter); + new LoadCategoriesTask().execute(); return new AlertDialog.Builder(getActivity(), R.style.ocAlertDialog) .setTitle(R.string.change_category_title) .setView(dialogView) - .setMessage(R.string.change_category_message) .setCancelable(true) .setPositiveButton(R.string.action_edit_save, new DialogInterface.OnClickListener() { @Override @@ -66,4 +80,114 @@ public void onClick(DialogInterface dialog, int which) { }) .create(); } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + } + + + private class LoadCategoriesTask extends AsyncTask> { + @Override + protected List doInBackground(Void... voids) { + NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(getActivity()); + List items = db.getCategories(); + List categories = new ArrayList<>(); + for(NavigationAdapter.NavigationItem item : items) { + if(!item.label.isEmpty()) { + categories.add(item.label); + } + } + return categories; + } + + @Override + protected void onPostExecute(List categories) { + adapter.setData(categories); + if(textCategory.getText().length()==0) { + textCategory.showFullDropDown(); + } else { + textCategory.dismissDropDown(); + } + } + } + + + private static class FolderArrayAdapter extends ArrayAdapter { + + private List originalData; + private Filter filter; + + private FolderArrayAdapter(@NonNull Context context, int resource) { + super(context, resource); + } + + public void setData(List data) { + originalData = data; + clear(); + addAll(data); + } + + @NonNull + @Override + public Filter getFilter() { + if(filter==null) { + filter = new FolderFilter(); + } + return filter; + } + + /* This implementation is based on ArrayAdapter.ArrayFilter */ + private class FolderFilter extends Filter { + @Override + protected FilterResults performFiltering(CharSequence prefix) { + final FilterResults results = new FilterResults(); + + if (prefix == null || prefix.length() == 0) { + final ArrayList list = new ArrayList<>(originalData); + results.values = list; + results.count = list.size(); + } else { + final String prefixString = prefix.toString().toLowerCase(); + final int count = originalData.size(); + final ArrayList newValues = new ArrayList<>(); + + for (int i = 0; i < count; i++) { + final String value = originalData.get(i); + final String valueText = value.toString().toLowerCase(); + + // First match against the whole, non-splitted value + if (valueText.startsWith(prefixString)) { + newValues.add(value); + } else { + final String[] words = valueText.split("/"); + for (String word : words) { + if (word.startsWith(prefixString)) { + newValues.add(value); + break; + } + } + } + } + + results.values = newValues; + results.count = newValues.size(); + } + + return results; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + clear(); + addAll((List) results.values); + if (results.count > 0) { + notifyDataSetChanged(); + } else { + notifyDataSetInvalidated(); + } + } + } + } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/Category.java b/app/src/main/java/it/niedermann/owncloud/notes/model/Category.java new file mode 100644 index 000000000..336ce23f9 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/Category.java @@ -0,0 +1,18 @@ +package it.niedermann.owncloud.notes.model; + +import android.support.annotation.Nullable; + +import java.io.Serializable; + +public class Category implements Serializable { + + @Nullable + public final String category; + @Nullable + public final Boolean favorite; + + public Category(@Nullable String category, @Nullable Boolean favorite) { + this.category = category; + this.favorite = favorite; + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/Item.java b/app/src/main/java/it/niedermann/owncloud/notes/model/Item.java index 2e46f58cc..d3191e4d3 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/model/Item.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/Item.java @@ -1,8 +1,5 @@ package it.niedermann.owncloud.notes.model; -/** - * Created by stefan on 23.10.15. - */ public interface Item { boolean isSection(); } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java index 44238e641..a505351d2 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/ItemAdapter.java @@ -1,5 +1,6 @@ package it.niedermann.owncloud.notes.model; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -11,6 +12,7 @@ import java.util.List; import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.util.NoteUtil; public class ItemAdapter extends RecyclerView.Adapter { @@ -18,9 +20,10 @@ public class ItemAdapter extends RecyclerView.Adapter { private static final int note_type = 1; private final NoteClickListener noteClickListener; private List itemList = null; + private boolean showCategory = true; private List selected = null; - public ItemAdapter(NoteClickListener noteClickListener) { + public ItemAdapter(@NonNull NoteClickListener noteClickListener) { this.itemList = new ArrayList<>(); this.selected = new ArrayList<>(); this.noteClickListener = noteClickListener; @@ -28,9 +31,9 @@ public ItemAdapter(NoteClickListener noteClickListener) { /** * Updates the item list and notifies respective view to update. - * @param itemList + * @param itemList List of items to be set */ - public void setItemList(List itemList) { + public void setItemList(@NonNull List itemList) { this.itemList = itemList; notifyDataSetChanged(); } @@ -39,7 +42,7 @@ public void setItemList(List itemList) { * Adds the given note to the top of the list. * @param note Note that should be added. */ - public void add(DBNote note) { + public void add(@NonNull DBNote note) { itemList.add(0, note); notifyItemInserted(0); notifyItemChanged(0); @@ -50,7 +53,7 @@ public void add(DBNote note) { * @param note Note with the changes. * @param position position in the list of the node */ - public void replace(DBNote note, int position) { + public void replace(@NonNull DBNote note, int position) { itemList.set(position, note); notifyItemChanged(position); } @@ -79,30 +82,29 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType // Replace the contents of a view (invoked by the layout manager) @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element Item item = itemList.get(position); if (item.isSection()) { SectionItem section = (SectionItem) item; ((SectionViewHolder) holder).sectionTitle.setText(section.geTitle()); - ((SectionViewHolder) holder).setPosition(position); } else { final DBNote note = (DBNote) item; final NoteViewHolder nvHolder = ((NoteViewHolder) holder); + nvHolder.noteSwipeable.setAlpha(DBStatus.LOCAL_DELETED.equals(note.getStatus()) ? 0.5f : 1.0f); nvHolder.noteTitle.setText(note.getTitle()); - nvHolder.noteCategory.setVisibility(note.getCategory().isEmpty() ? View.GONE : View.VISIBLE); - nvHolder.noteCategory.setText(note.getCategory()); + nvHolder.noteCategory.setVisibility(showCategory && !note.getCategory().isEmpty() ? View.VISIBLE : View.GONE); + nvHolder.noteCategory.setText(NoteUtil.extendCategory(note.getCategory())); nvHolder.noteExcerpt.setText(note.getExcerpt()); nvHolder.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? View.GONE : View.VISIBLE); nvHolder.noteFavorite.setImageResource(note.isFavorite() ? R.drawable.ic_star_grey600_24dp : R.drawable.ic_star_outline_grey600_24dp); nvHolder.noteFavorite.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - noteClickListener.onNoteFavoriteClick(position, view); + noteClickListener.onNoteFavoriteClick(holder.getAdapterPosition(), view); } }); - nvHolder.setPosition(position); } } @@ -114,6 +116,7 @@ public void clearSelection() { selected.clear(); } + @NonNull public List getSelected() { return selected; } @@ -134,11 +137,15 @@ public Item getItem(int notePosition) { return itemList.get(notePosition); } - public void remove(Item item) { + public void remove(@NonNull Item item) { itemList.remove(item); notifyDataSetChanged(); } + public void setShowCategory(boolean showCategory) { + this.showCategory = showCategory; + } + @Override public int getItemCount() { return itemList.size(); @@ -157,40 +164,35 @@ public interface NoteClickListener { public class NoteViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener { public View noteSwipeable; - public ImageView noteDeleteLeft, noteDeleteRight; - public TextView noteTitle; - public TextView noteCategory; - public TextView noteExcerpt; - public ImageView noteStatus; - public ImageView noteFavorite; - public int position = -1; + ImageView noteDeleteLeft, noteDeleteRight; + TextView noteTitle; + TextView noteCategory; + TextView noteExcerpt; + ImageView noteStatus; + ImageView noteFavorite; private NoteViewHolder(View v) { super(v); this.noteSwipeable = v.findViewById(R.id.noteSwipeable); - this.noteDeleteLeft = (ImageView) v.findViewById(R.id.noteDeleteLeft); - this.noteDeleteRight = (ImageView) v.findViewById(R.id.noteDeleteRight); - this.noteTitle = (TextView) v.findViewById(R.id.noteTitle); - this.noteCategory = (TextView) v.findViewById(R.id.noteCategory); - this.noteExcerpt = (TextView) v.findViewById(R.id.noteExcerpt); - this.noteStatus = (ImageView) v.findViewById(R.id.noteStatus); - this.noteFavorite = (ImageView) v.findViewById(R.id.noteFavorite); + this.noteDeleteLeft = v.findViewById(R.id.noteDeleteLeft); + this.noteDeleteRight = v.findViewById(R.id.noteDeleteRight); + this.noteTitle = v.findViewById(R.id.noteTitle); + this.noteCategory = v.findViewById(R.id.noteCategory); + this.noteExcerpt = v.findViewById(R.id.noteExcerpt); + this.noteStatus = v.findViewById(R.id.noteStatus); + this.noteFavorite = v.findViewById(R.id.noteFavorite); v.setOnClickListener(this); v.setOnLongClickListener(this); } - public void setPosition(int pos) { - position = pos; - } - @Override public void onClick(View v) { - noteClickListener.onNoteClick(position, v); + noteClickListener.onNoteClick(getAdapterPosition(), v); } @Override public boolean onLongClick(View v) { - return noteClickListener.onNoteLongClick(position, v); + return noteClickListener.onNoteLongClick(getAdapterPosition(), v); } public void showSwipeDelete(boolean left) { @@ -200,16 +202,11 @@ public void showSwipeDelete(boolean left) { } public static class SectionViewHolder extends RecyclerView.ViewHolder { - public TextView sectionTitle; - public int position = -1; + private TextView sectionTitle; private SectionViewHolder(View v) { super(v); - this.sectionTitle = (TextView) v.findViewById(R.id.sectionTitle); - } - - public void setPosition(int pos) { - position = pos; + this.sectionTitle = v.findViewById(R.id.sectionTitle); } } } \ No newline at end of file diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java new file mode 100644 index 000000000..2459ef796 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/NavigationAdapter.java @@ -0,0 +1,146 @@ +package it.niedermann.owncloud.notes.model; + +import android.graphics.Color; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.util.NoteUtil; + +public class NavigationAdapter extends RecyclerView.Adapter { + + @DrawableRes + public static final int ICON_FOLDER = R.drawable.ic_folder_grey600_24dp; + @DrawableRes + public static final int ICON_NOFOLDER = R.drawable.ic_folder_outline_grey600_24dp; + @DrawableRes + public static final int ICON_SUB_FOLDER = R.drawable.ic_folder_grey600_18dp; + @DrawableRes + public static final int ICON_MULTIPLE = R.drawable.ic_folder_plus_grey600_24dp; //R.drawable.ic_folder_multiple_grey600_24dp; + @DrawableRes + public static final int ICON_MULTIPLE_OPEN = R.drawable.ic_folder_grey600_24dp; //R.drawable.ic_folder_multiple_outline_grey600_24dp; + @DrawableRes + public static final int ICON_SUB_MULTIPLE = R.drawable.ic_folder_plus_grey600_18dp; //R.drawable.ic_folder_multiple_grey600_18dp; + + public static class NavigationItem { + @NonNull + public String id; + @NonNull + public String label; + @DrawableRes + public int icon; + @Nullable + public Integer count; + + public NavigationItem(@NonNull String id, @NonNull String label, @Nullable Integer count, @DrawableRes int icon) { + this.id = id; + this.label = label; + this.count = count; + this.icon = icon; + } + } + + class ViewHolder extends RecyclerView.ViewHolder { + @NonNull + private final View view; + @NonNull + private final TextView name, count; + @NonNull + private final ImageView icon; + private NavigationItem currentItem; + + ViewHolder(@NonNull View itemView, @NonNull final ClickListener clickListener) { + super(itemView); + view = itemView; + name = itemView.findViewById(R.id.navigationItemLabel); + count = itemView.findViewById(R.id.navigationItemCount); + icon = itemView.findViewById(R.id.navigationItemIcon); + icon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + clickListener.onIconClick(currentItem); + } + }); + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + clickListener.onItemClick(currentItem); + } + }); + } + + void assignItem(@NonNull NavigationItem item) { + currentItem = item; + boolean isSelected = item.id.equals(selectedItem); + name.setText(NoteUtil.extendCategory(item.label)); + count.setVisibility(item.count==null ? View.GONE : View.VISIBLE); + count.setText(String.valueOf(item.count)); + if(item.icon > 0) { + icon.setImageDrawable(icon.getResources().getDrawable(item.icon)); + icon.setVisibility(View.VISIBLE); + } else { + icon.setVisibility(View.GONE); + } + view.setBackgroundColor(isSelected ? view.getResources().getColor(R.color.bg_highlighted) : Color.TRANSPARENT); + int textColor = view.getResources().getColor(isSelected ? R.color.primary_dark : R.color.fg_default); + name.setTextColor(textColor); + count.setTextColor(textColor); + icon.setColorFilter(isSelected ? textColor : 0); + } + } + + public interface ClickListener { + void onItemClick(NavigationItem item); + void onIconClick(NavigationItem item); + } + + @NonNull + private List items = new ArrayList<>(); + private String selectedItem = null; + @NonNull + private ClickListener clickListener; + + public NavigationAdapter(@NonNull ClickListener clickListener) { + this.clickListener = clickListener; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_navigation, parent, false); + return new ViewHolder(v, clickListener); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + holder.assignItem(items.get(position)); + } + + @Override + public int getItemCount() { + return items.size(); + } + + public void setItems(@NonNull List items) { + this.items = items; + notifyDataSetChanged(); + } + + public void setSelectedItem(String id) { + selectedItem = id; + notifyDataSetChanged(); + } + public String getSelectedItem() { + return selectedItem; + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java index 0248d51f3..c144211b7 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/model/SectionItem.java @@ -1,10 +1,8 @@ package it.niedermann.owncloud.notes.model; -/** - * Created by stefan on 23.10.15. - */ public class SectionItem implements Item { - String title = ""; + + private String title; public SectionItem(String title) { this.title = title; diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java new file mode 100644 index 000000000..594cc73ef --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/LoadNotesListTask.java @@ -0,0 +1,141 @@ +package it.niedermann.owncloud.notes.persistence; + +import android.content.Context; +import android.os.AsyncTask; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import it.niedermann.owncloud.notes.R; +import it.niedermann.owncloud.notes.model.Category; +import it.niedermann.owncloud.notes.model.DBNote; +import it.niedermann.owncloud.notes.model.Item; +import it.niedermann.owncloud.notes.model.SectionItem; +import it.niedermann.owncloud.notes.util.NoteUtil; + +public class LoadNotesListTask extends AsyncTask> { + + public interface NotesLoadedListener { + void onNotesLoaded(List notes, boolean showCategory); + } + + private final Context context; + private final NotesLoadedListener callback; + private final Category category; + private final CharSequence searchQuery; + + public LoadNotesListTask(@NonNull Context context, @NonNull NotesLoadedListener callback, @NonNull Category category, @Nullable CharSequence searchQuery) { + this.context = context; + this.callback = callback; + this.category = category; + this.searchQuery = searchQuery; + } + + @Override + protected List doInBackground(Void... voids) { + List noteList; + NoteSQLiteOpenHelper db = NoteSQLiteOpenHelper.getInstance(context); + noteList = db.searchNotes(searchQuery, category.category, category.favorite); + + if (category.category == null) { + return fillListByTime(noteList); + } else { + return fillListByCategory(noteList); + } + } + + @NonNull + @WorkerThread + private List fillListByCategory(@NonNull List noteList) { + List itemList = new ArrayList<>(); + String currentCategory = category.category; + for (DBNote note : noteList) { + if(currentCategory != null && !currentCategory.equals(note.getCategory())) { + itemList.add(new SectionItem(NoteUtil.extendCategory(note.getCategory()))); + } + itemList.add(note); + currentCategory = note.getCategory(); + } + return itemList; + } + + @NonNull + @WorkerThread + private List fillListByTime(@NonNull List noteList) { + List itemList = new ArrayList<>(); + // #12 Create Sections depending on Time + boolean todaySet, yesterdaySet, weekSet, monthSet, earlierSet; + todaySet = yesterdaySet = weekSet = monthSet = earlierSet = false; + Calendar today = Calendar.getInstance(); + today.set(Calendar.HOUR_OF_DAY, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + today.set(Calendar.MILLISECOND, 0); + Calendar yesterday = Calendar.getInstance(); + yesterday.set(Calendar.DAY_OF_YEAR, yesterday.get(Calendar.DAY_OF_YEAR) - 1); + yesterday.set(Calendar.HOUR_OF_DAY, 0); + yesterday.set(Calendar.MINUTE, 0); + yesterday.set(Calendar.SECOND, 0); + yesterday.set(Calendar.MILLISECOND, 0); + Calendar week = Calendar.getInstance(); + week.set(Calendar.DAY_OF_WEEK, week.getFirstDayOfWeek()); + week.set(Calendar.HOUR_OF_DAY, 0); + week.set(Calendar.MINUTE, 0); + week.set(Calendar.SECOND, 0); + week.set(Calendar.MILLISECOND, 0); + Calendar month = Calendar.getInstance(); + month.set(Calendar.DAY_OF_MONTH, 0); + month.set(Calendar.HOUR_OF_DAY, 0); + month.set(Calendar.MINUTE, 0); + month.set(Calendar.SECOND, 0); + month.set(Calendar.MILLISECOND, 0); + for (int i = 0; i < noteList.size(); i++) { + DBNote currentNote = noteList.get(i); + if (currentNote.isFavorite()) { + // don't show as new section + } else if (!todaySet && currentNote.getModified().getTimeInMillis() >= today.getTimeInMillis()) { + // after 00:00 today + if (i > 0) { + itemList.add(new SectionItem(context.getResources().getString(R.string.listview_updated_today))); + } + todaySet = true; + } else if (!yesterdaySet && currentNote.getModified().getTimeInMillis() < today.getTimeInMillis() && currentNote.getModified().getTimeInMillis() >= yesterday.getTimeInMillis()) { + // between today 00:00 and yesterday 00:00 + if (i > 0) { + itemList.add(new SectionItem(context.getResources().getString(R.string.listview_updated_yesterday))); + } + yesterdaySet = true; + } else if (!weekSet && currentNote.getModified().getTimeInMillis() < yesterday.getTimeInMillis() && currentNote.getModified().getTimeInMillis() >= week.getTimeInMillis()) { + // between yesterday 00:00 and start of the week 00:00 + if (i > 0) { + itemList.add(new SectionItem(context.getResources().getString(R.string.listview_updated_this_week))); + } + weekSet = true; + } else if (!monthSet && currentNote.getModified().getTimeInMillis() < week.getTimeInMillis() && currentNote.getModified().getTimeInMillis() >= month.getTimeInMillis()) { + // between start of the week 00:00 and start of the month 00:00 + if (i > 0) { + itemList.add(new SectionItem(context.getResources().getString(R.string.listview_updated_this_month))); + } + monthSet = true; + } else if (!earlierSet && currentNote.getModified().getTimeInMillis() < month.getTimeInMillis()) { + // before start of the month 00:00 + if (i > 0) { + itemList.add(new SectionItem(context.getResources().getString(R.string.listview_updated_earlier))); + } + earlierSet = true; + } + itemList.add(currentNote); + } + + return itemList; + } + + @Override + protected void onPostExecute(List items) { + callback.onNotesLoaded(items, category.category==null); + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java index a000f02fa..234216e63 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NoteSQLiteOpenHelper.java @@ -6,6 +6,10 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; +import android.text.TextUtils; import android.util.Log; import java.text.ParseException; @@ -22,6 +26,7 @@ import it.niedermann.owncloud.notes.model.CloudNote; import it.niedermann.owncloud.notes.model.DBNote; import it.niedermann.owncloud.notes.model.DBStatus; +import it.niedermann.owncloud.notes.model.NavigationAdapter; import it.niedermann.owncloud.notes.util.ICallback; import it.niedermann.owncloud.notes.util.NoteUtil; @@ -45,7 +50,7 @@ public class NoteSQLiteOpenHelper extends SQLiteOpenHelper { private static final String key_category = "CATEGORY"; private static final String key_etag = "ETAG"; private static final String[] columns = {key_id, key_remote_id, key_status, key_title, key_modified, key_content, key_favorite, key_category, key_etag }; - private static final String default_order = key_favorite + " DESC, " + key_modified + " DESC"; + private static final String default_order = key_modified + " DESC"; private static NoteSQLiteOpenHelper instance; @@ -159,8 +164,8 @@ public Context getContext() { * @param content String */ @SuppressWarnings("UnusedReturnValue") - public long addNoteAndSync(String content) { - CloudNote note = new CloudNote(0, Calendar.getInstance(), NoteUtil.generateNoteTitle(content), content, false, null, null); + public long addNoteAndSync(String content, String category, boolean favorite) { + CloudNote note = new CloudNote(0, Calendar.getInstance(), NoteUtil.generateNoteTitle(content), content, favorite, category, null); return addNoteAndSync(note); } @@ -204,8 +209,7 @@ long addNote(CloudNote note) { values.put(key_favorite, note.isFavorite()); values.put(key_category, note.getCategory()); values.put(key_etag, note.getEtag()); - long id = db.insert(table_notes, null, values); - return id; + return db.insert(table_notes, null, values); } /** @@ -227,7 +231,9 @@ public DBNote getNote(long id) { * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered. * @return List of Notes */ - private List getNotesCustom(String selection, String[] selectionArgs, String orderBy) { + @NonNull + @WorkerThread + private List getNotesCustom(@NonNull String selection, @NonNull String[] selectionArgs, @Nullable String orderBy) { SQLiteDatabase db = getReadableDatabase(); if(selectionArgs.length > 2) { Log.v("Note", selection + " ---- " + selectionArgs[0] + " " + selectionArgs[1] + " " + selectionArgs[2]); @@ -246,7 +252,8 @@ private List getNotesCustom(String selection, String[] selectionArgs, St * @param cursor database cursor * @return DBNote */ - private DBNote getNoteFromCursor(Cursor cursor) { + @NonNull + private DBNote getNoteFromCursor(@NonNull Cursor cursor) { Calendar modified = Calendar.getInstance(); try { String modifiedStr = cursor.getString(4); @@ -266,6 +273,8 @@ public void debugPrintFullDB() { } } + @NonNull + @WorkerThread public Map getIdMap() { Map result = new HashMap<>(); SQLiteDatabase db = getReadableDatabase(); @@ -282,6 +291,8 @@ public Map getIdMap() { * * @return List<Note> */ + @NonNull + @WorkerThread public List getNotes() { return getNotesCustom(key_status + " != ?", new String[]{DBStatus.LOCAL_DELETED.getTitle()}, default_order); } @@ -291,37 +302,91 @@ public List getNotes() { * * @return List<Note> */ - public List searchNotes(CharSequence query) { - return getNotesCustom( - key_status + " != ? AND (" - + key_content + " LIKE ? OR " - + key_category + " LIKE ?" + - ")", new String[]{ - DBStatus.LOCAL_DELETED.getTitle(), - "%" + query + "%", - "%" + query + "%" - }, default_order); - } + @NonNull + @WorkerThread + public List searchNotes(@Nullable CharSequence query, @Nullable String category, @Nullable Boolean favorite) { + List where = new ArrayList<>(); + List args = new ArrayList<>(); + + where.add(key_status + " != ?"); + args.add(DBStatus.LOCAL_DELETED.getTitle()); + + if(query != null) { + where.add(key_status + " != ?"); + args.add(DBStatus.LOCAL_DELETED.getTitle()); + + where.add("(" + key_content + " LIKE ? OR " + key_category + " LIKE ?" + ")"); + args.add("%" + query + "%"); + args.add("%" + query + "%"); + } - /** - * Returns a list of all Notes in the Database with a sepcial status, e.g. Edited, Deleted,... - * - * @return List<Note> - */ - public List getNotesByStatus(DBStatus status) { - return getNotesCustom(key_status + " = ?", new String[]{status.getTitle()}, null); + if(category != null) { + where.add(key_category + "=? OR "+key_category+" LIKE ?"); + args.add(category); + args.add(category+"/%"); + } + + if(favorite != null) { + where.add(key_favorite + "=?"); + args.add(favorite ? "1" : "0"); + } + + String order = category==null ? default_order : key_category + ", "+ key_title; + return getNotesCustom(TextUtils.join(" AND ", where), args.toArray(new String[] {}), order); } + /** * Returns a list of all Notes in the Database with were modified locally * * @return List<Note> */ + @NonNull + @WorkerThread public List getLocalModifiedNotes() { return getNotesCustom(key_status + " != ?", new String[]{DBStatus.VOID.getTitle()}, null); } + @NonNull + @WorkerThread + public Map getFavoritesCount() { + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query( + table_notes, + new String[] {key_favorite, "COUNT(*)"}, + key_status + " != ?", + new String[]{DBStatus.LOCAL_DELETED.getTitle()}, + key_favorite, + null, + key_favorite); + Map favorites = new HashMap<>(cursor.getCount()); + while (cursor.moveToNext()) { + favorites.put(cursor.getString(0), cursor.getInt(1)); + } + cursor.close(); + return favorites; + } - public void toggleFavorite(DBNote note, ICallback callback) { + @NonNull + @WorkerThread + public List getCategories() { + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query( + table_notes, + new String[] {key_category, "COUNT(*)"}, + key_status + " != ?", + new String[]{DBStatus.LOCAL_DELETED.getTitle()}, + key_category, + null, + key_category); + List categories = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { + categories.add(new NavigationAdapter.NavigationItem("category:"+cursor.getString(0), cursor.getString(0), cursor.getInt(1), NavigationAdapter.ICON_FOLDER)); + } + cursor.close(); + return categories; + } + + public void toggleFavorite(@NonNull DBNote note, @Nullable ICallback callback) { note.setFavorite(!note.isFavorite()); note.setStatus(DBStatus.LOCAL_EDITED); SQLiteDatabase db = this.getWritableDatabase(); @@ -335,6 +400,20 @@ public void toggleFavorite(DBNote note, ICallback callback) { serverSyncHelper.scheduleSync(true); } + public void setCategory(@NonNull DBNote note, @NonNull String category, @Nullable ICallback callback) { + note.setCategory(category); + note.setStatus(DBStatus.LOCAL_EDITED); + SQLiteDatabase db = this.getWritableDatabase(); + ContentValues values = new ContentValues(); + values.put(key_status, note.getStatus().getTitle()); + values.put(key_category, note.getCategory()); + db.update(table_notes, values, key_id + " = ?", new String[]{String.valueOf(note.getId())}); + if(callback!=null) { + serverSyncHelper.addCallbackPush(callback); + } + serverSyncHelper.scheduleSync(true); + } + /** * Updates a single Note with a new content. * The title is derived from the new content automatically, and modified date as well as DBStatus are updated, too -- if the content differs to the state in the database. @@ -344,7 +423,7 @@ public void toggleFavorite(DBNote note, ICallback callback) { * @param callback When the synchronization is finished, this callback will be invoked (optional). * @return changed note if differs from database, otherwise the old note. */ - public DBNote updateNoteAndSync(DBNote oldNote, String newContent, ICallback callback) { + public DBNote updateNoteAndSync(@NonNull DBNote oldNote, @Nullable String newContent, @Nullable ICallback callback) { //debugPrintFullDB(); DBNote newNote; if(newContent==null) { @@ -386,7 +465,7 @@ public DBNote updateNoteAndSync(DBNote oldNote, String newContent, ICallback cal * * @return The number of the Rows affected. */ - int updateNote(long id, CloudNote remoteNote, DBNote forceUnchangedDBNoteState) { + int updateNote(long id, @NonNull CloudNote remoteNote, @Nullable DBNote forceUnchangedDBNoteState) { SQLiteDatabase db = this.getWritableDatabase(); // First, update the remote ID, since this field cannot be changed in parallel, but have to be updated always. @@ -451,7 +530,7 @@ public int deleteNoteAndSync(long id) { * @param id long - ID of the Note that should be deleted. * @param forceDBStatus DBStatus, e.g., if Note was marked as LOCAL_DELETED (for NoteSQLiteOpenHelper.SyncTask.pushLocalChanges()) or is unchanged VOID (for NoteSQLiteOpenHelper.SyncTask.pullRemoteChanges()) */ - void deleteNote(long id, DBStatus forceDBStatus) { + void deleteNote(long id, @NonNull DBStatus forceDBStatus) { SQLiteDatabase db = this.getWritableDatabase(); db.delete(table_notes, key_id + " = ? AND " + key_status + " = ?", diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java index 4e4bf42ce..7f2c8f1fc 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/NoteUtil.java @@ -1,5 +1,8 @@ package it.niedermann.owncloud.notes.util; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + import java.util.regex.Pattern; /** @@ -21,7 +24,8 @@ public class NoteUtil { * @param s String - MarkDown * @return Plain Text-String */ - public static String removeMarkDown(String s) { + @NonNull + public static String removeMarkDown(@Nullable String s) { if(s==null) return ""; s = pLists.matcher(s).replaceAll(""); @@ -46,7 +50,7 @@ public static String removeMarkDown(String s) { * @param line String - a single Line which ends with \n * @return boolean isEmpty */ - public static boolean isEmptyLine(String line) { + public static boolean isEmptyLine(@Nullable String line) { return removeMarkDown(line).trim().length() == 0; } @@ -57,7 +61,8 @@ public static boolean isEmptyLine(String line) { * @param len Maximum length of the resulting string * @return truncated string */ - public static String truncateString(String str, int len) { + @NonNull + public static String truncateString(@NonNull String str, int len) { return str.substring(0, Math.min(len, str.length())); } @@ -67,7 +72,8 @@ public static String truncateString(String str, int len) { * @param content String * @return excerpt String */ - public static String generateNoteExcerpt(String content) { + @NonNull + public static String generateNoteExcerpt(@NonNull String content) { if (content.contains("\n")) return truncateString(removeMarkDown(content.replaceFirst("^.*\n", "")), 200).replace("\n", " "); else @@ -80,7 +86,8 @@ public static String generateNoteExcerpt(String content) { * @param content String * @return excerpt String */ - public static String generateNoteTitle(String content) { + @NonNull + public static String generateNoteTitle(@NonNull String content) { return getLineWithoutMarkDown(content, 0); } @@ -91,7 +98,8 @@ public static String generateNoteTitle(String content) { * @param lineNumber int * @return lineContent String */ - public static String getLineWithoutMarkDown(String content, int lineNumber) { + @NonNull + public static String getLineWithoutMarkDown(@NonNull String content, int lineNumber) { String line = ""; if (content.contains("\n")) { String[] lines = content.split("\n"); @@ -107,4 +115,9 @@ public static String getLineWithoutMarkDown(String content, int lineNumber) { } return line; } + + @NonNull + public static String extendCategory(@NonNull String category) { + return category.replace("/", " / "); + } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java b/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java index 821b7d9f2..490a62cd5 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClient.java @@ -1,5 +1,6 @@ package it.niedermann.owncloud.notes.util; +import android.support.annotation.WorkerThread; import android.util.Base64; import android.util.Log; @@ -19,6 +20,7 @@ import it.niedermann.owncloud.notes.util.ServerResponse.NoteResponse; import it.niedermann.owncloud.notes.util.ServerResponse.NotesResponse; +@WorkerThread public class NotesClient { /** @@ -95,11 +97,12 @@ private NoteResponse putNote(CustomCertManager ccm, CloudNote note, String path, JSONObject paramObject = new JSONObject(); paramObject.accumulate(JSON_CONTENT, note.getContent()); paramObject.accumulate(JSON_MODIFIED, note.getModified().getTimeInMillis()/1000); - paramObject.accumulate(JSON_FAVORITE, note.isFavorite()); - paramObject.accumulate(JSON_CATEGORY, note.getCategory()); + paramObject.accumulate(JSON_FAVORITE, note.isFavorite()); + paramObject.accumulate(JSON_CATEGORY, note.getCategory()); return new NoteResponse(requestServer(ccm, path, method, paramObject, null)); } + /** * Creates a Note on the Server * @@ -140,7 +143,7 @@ private ResponseData requestServer(CustomCertManager ccm, String target, String con.setRequestProperty( "Authorization", "Basic " + Base64.encodeToString((username + ":" + password).getBytes(), Base64.NO_WRAP)); - con.setRequestProperty("User-Agent", "nextcloud-notes/" + BuildConfig.VERSION_NAME + " (Android)"); + con.setRequestProperty("User-Agent", "nextcloud-notes/" + BuildConfig.VERSION_NAME + " (Android)"); if(lastETag!=null && METHOD_GET.equals(method)) { con.setRequestProperty("If-None-Match", lastETag); } @@ -167,7 +170,7 @@ private ResponseData requestServer(CustomCertManager ccm, String target, String throw new ServerResponse.NotModifiedException(); } - BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); + BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = rd.readLine()) != null) { result.append(line); diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClientUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClientUtil.java index 71d7ef549..125bfc128 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClientUtil.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/NotesClientUtil.java @@ -1,6 +1,8 @@ package it.niedermann.owncloud.notes.util; import android.content.Context; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; import android.util.Base64; import android.util.Log; @@ -31,8 +33,9 @@ public enum LoginStatus { JSON_FAILED(R.string.error_json), SERVER_FAILED(R.string.error_server); + @StringRes public final int str; - LoginStatus(int str) { + LoginStatus(@StringRes int str) { this.str = str; } } diff --git a/app/src/main/res/drawable-hdpi/ic_clock_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_clock_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1b4ca3615d60da63a8174a60542e2b80c732a0fb GIT binary patch literal 1511 zcmZ{kdpOg37{I@C+1xo@v`I)>D%#wclFJW6#Ac01F}KlNHrM0Qge)qBMw*gJrCP~U zNO?>-lxayT<5Z`z(7ly2*YoTAcm6ov=Xt-M=l#CV=Y9WqpYOrI0B>y#0}TLxwhs{^ z!8H37YDoBg4Qgs&sKmMXy8+N#t~nQ}3g-wG$=e<9MTQe_VnQR5`~mnK3jn(afEoCS z{T_gHJOGn>03g5(R;2LSgEqqjWR#yb1QR|AkB)sX)KiF|ESSW9!>cdR1s-?N2XYGz z5q_)*i#Md8dl%zkl}~s)v2WmDU;Kew3FWD|`?i#A?;}g0s;egYQ^osrFJnJ>>S4Ss zur`U$NWr;!>z5^*Ojv5CakomppYGdsC8#9D(PDOfq2A)55PGU>0_q1oE@->zyCS;;^xBrn%1Xs5 zgaHNT-N?e|_@MJN8^8H;Tht@#JQ ziofTxHs>GV1Sq4K9YzE1n3^Dh|8^ZUAx-i~{mg`lY>w_fwD41D&4$XpaAQNm&2iF< zmF&DEmN{B0f2*@|PTOccxqoy_Ua2>}UZhwv?9L;axkJm$8rBN&qF`l~NbZ;|Wmgeo>k84pk>S#+M!F8|Ln@GrHU>PrVfrq^0Tc@(F~zJ# zx$q7jgL{%bj{{9#Xc1|$D_U=-XA7S@%DLNyHn;A=d!A@iAT&CbgCt!QrP<3$J{9u7 z=11t03G(ODrkRf>qQ+8rubW(fuK<$Y&k(B3gx6fSryrQvd~{IO;_N9zhw1f?MeTNa z{3+^8YwHh#3}R_R`0}Ql1jO;^&>d&DSAG(U#Sypztq(S#W;#QzGiG&gg-gY2K_Vc; zgf0;D%Q|hWt(ktSZaHrp2vxsW6&A`>j$msE|0Z(ZRZJZ!g?ryp*{(J>y)Ir1Gvch~K-4y(ko8w#Ra+ z{AL1(=Sf`t)HMzITt;f@*Qn;L)epC*)(fxlQ$#Xo(f{%mqw-!3G4nDNLz}*x`IuWp zG|MP2FJDA}W5np{2J@|YL8-zXEg^BoVLf18%3M;sZbRVhAA|O_gdk5eg>rs;e0)gh z(G7+)xmucBYhD*1JrfwOUMw+HPRR@llb$LlD8LO(*fLc6^E5kEUvZ=mB!An}({sMv z6&&r0-h?W2GiIa48uO;6raEC23-4I63U9_FKcu9v*h=qQRb}_0g zzC&xzNGcBl?g<0}3+1lK$%GO!AA~8P3%#=YL6VZjX}4Y{*(BGc5W4^7Yso=#)vnJ@ zRELCvoCqSea>XRZH^OTueV!)D)@7^Mi`L_IBJ|$yrn3sZ8m!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3Lh|yh35lr>Ip64rHicP-c{v0sb}o4HJ}tfMzEQ*Z^{qdh zT&h%lt7M;V3oXsgT`K^4s5FFi`zjHsOh*3){6@viH`k>Dl7xm*;v_f}vzz=iSGK{grR}HwL>N z`^cy~lc_+}*)R0+?uqY@6y7O4$IEEq-LOf4W18oroK=xC&YKsp-bgW7X?>XM0?>P^ zC9V-ADTyViR>?)FK#IZ0z|dUR&_LJFGQ_~t%GlV-#9Z6Jz{S6G7^>bP0l+XkKI%2XG literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_folder_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..cbdc108b906f1b64d699a59d77727e13e0268802 GIT binary patch literal 533 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+K*lvs7srr@!*8#7a~(1eX?m&#H%yoO%7v!YbnrvnzYA@Pq~yl?69A zJsj-$S1C*Ml{+%5;#hESUbFHV!?f!rzU4RKeRx(fh8&w=bI5tZ68m>te^1yjq&_I< z1^Q66#5JNMC9x#cD!C{XNHG{07@F%E8t58Yh8UPy85>)fm}?stSQ!}b@g6ip(U6;; zl9^VCTSI+7CCCO1kPXFU=~hXJ#i_cbMVSm~nK`Le`uh4Mxdr;UiRqci*}A%pp#?!X W&iPu=k92@~7(8A5T-G@yGywnvUbmD0 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_outline_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_folder_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a00be0fe1cf7a9cbc96efe5bb414e1267b215d4f GIT binary patch literal 552 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+K*mc?7srr@!*8b@Z#!~g-!hKao@l!&j3!m*i+q8N9|96K3IGYUg@8~uuT!?z@qq&uF zgWR7PmS;czFn1O&VPWPw(%$ zJL4zUf-g4jCoFrpHa1>YHR1CfvBJwHug;d6TV_NMmo=I&29nO2EgL&CX=??4S2ARCIy(yfvbi&J$=i!vF~GILU` q^!4>iatrix6Vo%3vvu<`^CE-u9R1hsm6iqSVeoYIb6Mw<&;$UM2**+Y literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_18dp.png b/app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..3367526cf8fdf5a552d763f2d806c2d27d8c041a GIT binary patch literal 678 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i1|)m0d!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3?EK+34kLDA9V}Q)bBy3(FS^ z-Wqo_i^_22Ims{Ze{f?-Y0ma<%lIE$J9zb|uVcXms~w!{x;(_y14XR2d@p~g8=kp- z>Gvp&FFxugJ@@^wS3D52S*?xz*bLoC)+%2&Z0NXS@qAs<;U2@vN$LzCF8i1j-p{e_ zX5D;k9@7o^WPkPpjU6`baz1rSgI4a&+WO0or;Ib9{E}Gjh3<|gQoYA)|7Ao9MJZNF z@cffzV_5BZ=vLJ0o@-Xj3uHxOJQ%L6y_(g}kg)cx8|(6m$8JoG?e^eim=d)9pvp<* z``@Skw&PB)HtTuPTD#y^ChMX^d4Nraz{Jrd#L)s(LwykMvYdQYx*zjFK+|PZ@e%7=L zZj*c&>X@dsJ?-`=KESbFr2DAv(kt^ibW|CBg?P=ao>xA*fU(#&@cycw*%KbGv1tH? zy=sYTL`h0wNvc(HQ7VvPFfuSS*EKZIHM9&dFtsu^wK6i)HZZUu75Nw2Wrp&*-%`TZk3c+oT^(|l*y2mnUiXzudiQ{TcDqtn4X!Ot?M0c5$YBZ VQ0D)lWGPS&gQu&X%Q~loCIAh80vrGU literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1da52c23a7ec33a8f43bdbaf0d530099768d978b GIT binary patch literal 627 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 L^>bP0l+XkKmuAsT literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_clock_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_clock_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f4934533ffe44d21d6cbd0ddfaeb6d4f46197337 GIT binary patch literal 1044 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3~f4=AX~AB1CIBBlnxzN++)?2}NeV&*K(gX?$FHFZIFnn%AlZ z(OOgGwnnWrXXtxe5jjnk@f@S_&e)`$nLUp!w2$51C>X%;Pi{v>&(56}IU|^+H7V?P zS9!1U0hfT;Y+u$zzWx)YKjr%n=h7FMJwNBBs{+sA_pVPEH+Z|Kt=YP@@0_MtNp5bg z+znkN@ikk^tG>9_-k*N-=+Wgz|5okY_vm*Wv&QOI4>xYyIGdZBTel(TxW<0n-wo55 znVF4mpWLINt*vd|pekrNVcE-y^mZ$B7bsUpBuya*N}K z_=2lhZ{I$yZu+MC+qP@b>dBKQ$BRyloW}e7bp0-dRljWPpWR5ixccfV+vGFmtA4Fs z^>0e*&G~^Mb9Gg2eyqL6Z7^T|Jgeh_9JbEKKlZD5CLJ$yYe-*JC2~u-?b{0nm#kQZ z>!sNTvJ+J5|J9~eRsC9@wYBP!#AoIMA3l6If50)c_G*TS)yX;=twRQL1Sal2z%Hm6 zoh_fwdg^aq$BEj6<*Vj-O-hmd5UBa;>o57mix;!~;InxAyDm8+Ls!)4;3Y4iP%1w=rz^cUoq-Z8YD?S8@!3mF#;2CPpp3 zIAi|InUS~s*6;KADPPAX_K|5R_cdTjS1oakC`m~yNwrEYN(E93Mh1rFx`qb2hL#}) zrdGzLR;C8p1_o9J23&IeX($?U^HVa@DsgM5b~e8S)Sv;fp|~vFDk-rzRkyS#lOZiL sC)G+{U%w=`KtDGzJu^95*Eqt&&D+^Ms=#WZ98eE~r>mdKI;Vst0LpB%82|tP literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_folder_grey600_18dp.png b/app/src/main/res/drawable-mdpi/ic_folder_grey600_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb6b02b86f09aa58bb69f6144970cf8b2f65b0b GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG z?d}4kf#9d}?s_1_S>O>_45U54*zIJt9gs1>)5S5w;`G}K8#$RA1zI20m-FX5ez3#o z&B3s;tcYz)(ia@K4YmmI>TT%co|dk}_DJ(ZlailB|IaqbA2*8_43Ej(V7%*V*COyt zbLm6LD-0IT#U|~tu8j7&Is0Z&(!VLiam-nIy*Hav*Df&;oh51ceCqlS^W+w=9g+Vf zV6rc!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3z1GNhv#(}vJ6qF~V>2F_Of(d15+zwV=EJL zZ36=<0|P$ZgN7&?a`RI%(<*Ums1K;@1!~X$*-%`TZk3c+oT^(|l*y2mnUiXzudiQ{ lTcDqtn4X!Oty>ya8s-;RmTDYw=paxJgQu&X%Q~loCIHFDithjb literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_folder_outline_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_folder_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..3675b6ef54d8cd935b6287dd2fbddd37e0aafc04 GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3XuU z;o-RyA!=k~R#sYSIw6ZucoL&=f#kUZ2M&Dr|NsB5O`D7+={Edcuw}~^`>9S(Pwub( zf2pdvdi&xZ4P6dxot>F#J%^k0Zr{Co)?-%X3I-{mO$K(lH4RK|x)NIxt}tDh^QWb; z(Xq`d^-?mA{GZ?7^?9>6O?mtmm!9Zhdc?>OI9ciLG{LWXfDTkGag8WRNi0dVN-jzT zQVd20hUU742D*lpAqJ*a#wJ##CfWuDRt5%wlMi^KXvob^$xN%nts&uD#dn|v4Ui4R zW$9K)iN&e9rA3(xX_+~xR{Hw-CAkIqxrynS$=SMNS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG z?d}4kf#9d}?s_1_S>O>_45U54*zIJt9guO&)5S5w;`H5#8+i{I2)OQ-Rk_w7V#p}G zftk1ZL2|3cNd_GO#e)n}u886$0^821?p z2#UD|-aZj1^Tj5sr2ksD%5$$x+|?Uh^sjcW(D4@TV`rFC++!p(vDGaq^T^D5g)ZCI zR=)q9^<&G?6^YT=#}z#@N?v+~l}^!b$U7UgTd}fhVX&;{y8RX3y>~I`*?2p>wq%I| z`cSpRHKHUXu_V85k^E(|a04LvDUb zW?Cg~4c9-KmIF0tfNUr(OSei&EKb!eEy`p_%gjl&(%087$t}>&O-#>B&enC!a`w$i W4DpkxsZ#*zVeoYIb6Mw<&;$S`EwGsY literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..30fed8addef8cbd2da6c2187711764fff6e340b9 GIT binary patch literal 488 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3Y&W#WXjE3nru`rOjGZ8QyfB zGbc;DXX}zV)%$w)PhU`S!+L&|bA81L)#82AjU1O}?2+Z@=m-_cWQ=g#tj)cXafOv0 zyVO>OpFl^embgZgq$HN4S|t~y0x1R~14DCNLjzqy%Mb%oD`QhDBSUQi11kfAWovp* zqiD#@PsvQH#I51_N7Hhk1`Uu6#bxPMNr}a&x}`;#3~8A;saE>>`X#vq`nieenaSC@ czAky*0Y!l&aZlc`1NAU?y85}Sb4q9e04*?{#sB~S literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7930918e9656b4d6a706b55d935aa11c90179ebc GIT binary patch literal 972 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3fcFroT|! zq`Jjx?Uf5LYg8n1UCydq%Q8@l63Cw(5xcIWJeS9?D=1>|vz(kiFIMn`HTAY#mdHJy zG@Yf`TFgf8_}#|xGM}&ep8c=RPrG-Z&irQf<`_MBpUYpA3K%UIduFYbKj0p^)~YXf zZHU(FTIQPj`*~Up+_2aC8S2txz!U$C<%5m>^Ih+3AM{23VzJq(^E!9&#TATCiY(1f zZ}NO#Rd8occkb?DmuPrg+?!C=X!dXdu9cRjfzt_gs-oO6s zs{zk_M%4zL(@KlC3MZ^e<@vE?-@bo4rqA9UwKlApV@=nIidoCVtr(Pyco(elpEhlp z)LoZF8k01-c7@IR7-@3Zk0H9WZ`HoH-@n~nwkrS3hY)s!)0>pBP z$oo7QOKx*B+yH{l_|L?~&fY)c;d;J?RqG^vUHQ+X zbJ{AqO@0^SDz<{VpZCPCs;(~z&LE>>J+ERb2wRm0jR%GEmiFH_9*y{s~!SM|SE z?d7~N@qz+}-pW_p+kRcB{OtTcb7@d!kV_mh^C~OZW{uVPyMN7%2OC7#SFv>lzy98d`=Jm|7W|Ss5B?8yHv_7#tQc)JD;eo1c=IR*74~ zCeP04Kn)ro8;Z-)t&$RpQ*}#=G8xh`b5gDJ_4P|~3-ogn(=(H^bzRe)U4z1%@;QQc R90BTK@O1TaS?83{1OSV7j70zd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_tune_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_tune_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..9a5138d6e4a5d62ebdeda3cbf53d11df051f1697 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3o#lCI;FD237_Jy3HoPQ8eV{r(~v8;?@vzug4vzK?7t%aap=mQettc zZfQ{_Lt17|s+GRJeo1bDer{rVW^%S}WRjeFi;V8Zgv1PU)%mQOcwSL2_B9oK;z3jA7Mu)+{wcYfbS0i zz`6*)8a%|B10V_BWj+)DVle=k@#URlOL#(#a>|he6K>LzkFsDW#5?&Xz;yc89A3m& z!>g2?Np@b5<6?hCtf#kD=6HI)!zW@ON-^ZrhCD(SDTg$2X_0mtMkAZ;c>50)=^uj{ zmd9y%(*YF22PsG8%h-eaFOo=i@n%yh1V6=xpr9!7sUy;X>=a6!=rnuS)nqeVBoqo) z8pUr_R`oW{k0-obw|-?+GdpF)JJx$XE5~S3PgS0s`6NpL^M)Y7VoSG&62a+eXB$>l ziPQw6&#vtkC;ud$+ud7?mY2&(%GNoI87u?z!u#v`U>m#EYF9yUXALqSFtBF6a}&X8 z2VOTN7%(RHcSo33pm21wv7nQ6#_+){cCt+Beb)~@%VrV>w;|=id{%F7uR?HBy9{p) z>2?k|hk8xZ>ix*&a&6Mn)7L@h()5eR!uB{DSJHM_yU0+HI*8u>k94}XV0YQ7SeQ~n zL3(-L^r-t|MDW$4QihWt_|>!MUe08EDzEMd)vV((I{*mUqLy;>oDl|_`RK^l*zyU9 z^l|HfpRk;t&$Xxf9@{fqp=vsjP9Vg|K!ZzR#Pzi`AC27#zRfytSlySurqP4duRO~% zy_Bk<&BWW2Gv)qPBAk9TjF+IBM%FPbrEaNKGD^+fpD);E5+d>?tA$)8VSW1##O;jH zAfzCRdT96(@I)xYLJ}4Ielz^Lg;I1C3E&=1>@4%+kaD_HF|F`o81;&>N8xPV#wLX zOFp&Gu5Mp4LNN9MgqO3fAzj&!|BKu?r&5nFS|L%;?-8Rep&XcVlm^qNdw8bQAbaa%M zq_@GXukX?r%5q1YJ*r6}XFMSN-h_A-dF-yo?Fo`AqH9ikKP+VHxm0eM@w8AzjL(JkgfK{5rjbtBRhUf zbKdHo`mEPbu(av={{8!3W8byp0?XUKU@?CSFJ9KUey@y-nCl4-FN z53VN$g}fUYy584D_Ws3XWF-e2q%j0zm^@OZ5fQ2VRQ$Y4ePC6ZQD%%s`%`PwF}SPz zsgZ#s85tQnAX1NnD%{(JOq`nStr_KMI_eyTd_mNEI65*aDs33LdI-Gn-%a>5c$jfL zXnk_A=Mw_@Gt0nC(q8hHsMeNzL;G^r9<%HGGky58wWsY6pHsgQ32_gKYw|d$4_|LQ z*n`UXjY!|bNc|U;y7e#QT5XRiO_t~JH6$5y>pH`}p_|zK=u4Ft`_Cwr0nS_8?6*)q zxu!87a4uS2ImJj%4gE%SkO*+kgBXHoUthhBn6-dL`0Za|k2lvxh%&MB zRFN*ol!dVq{m1umDT<%lWWpnk61uJw0jq> zOc=4MDGB3fM}7dIaKFta|M#j>HoBYuY^ln&t-Dw)s;KK@;@V1ETU(FQ@!KoUN5;l1 zJ=LBq=>F;SCHF~*)RtIr?izn;>qg%l?5hSY7hUHSjVG8>EB$9fBdyGBT7xN~glwI1 zmztrVeb)@gc@e|suTEw1x5A%h&Gu-2v4Fn_{X~1eL~2+fjTp|P!2o6u-W-RAaCi$Z z=m?Q;gm?rph9DvYq4!;*|BrwXM~$MV{eMCFN%K)yVEFBXgyaY!B`kr4OJYU=dQ>cp pXliPj$cQ&(ghfP!$Kc!}?GHy1PQ=ik*nNu%INQ6E8c&2~{}=6HK9m3e literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_grey600_18dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_grey600_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e711922047e56a42ef02005074bbc964ea455f04 GIT binary patch literal 533 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+K*lvs7srr@!*8#7a~(1eX?m&#H%yoO%7v!YbnrvnzYA@Pq~yl?69A zJsj-$S1C*Ml{+%5;#hESUbFHV!?f!rzU4RKeRx(fh8&w=bI5tZ68m>te^1yjq&_I< z1^Q66#5JNMC9x#cD!C{XNHG{07@F%E8t58Yh8UPy85>)fm}?stSQ!}b@g6ip(U6;; zl9^VCTSI+7CCCO1kPXFU=~hXJ#i_cbMVSm~nK`Le`uh4Mxdr;UiRqci*}BNS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)pVryh>nTu$sZZAYL$MSD+10f-TA0 z-33Sk!B6Mi^+1ZVz$3C4NPB>>+sSM@pz)%fE{-7?_ugLK=yfWDw(nD<;voBVmlbBta(Lte!J&?i>t#-=RXfm<6_&idB+QNQX}oQ3O>kUe?9xX zywR3bt5(~bSJz@(V?Vojt7zbF_Dwpg>wYh_j$-6jY$*&B`MjS0t{n62Ys`9!HL5%( zJz3JtIG^p@&e?kG3QCLp*cpz;@~_y)kSn&}EYp_A1~cvpX^gjY9A>j-Y-Y&yWz>GV zbl=B+lN;RM>Y58q{JoY@$%yUVmg%`4xRyjS@A$F?Z%-(`Kg(oijUbk>B z&>J)MKV@F@*lfoH6&_b$NU4^%MwFx^mZVxG7o`Fz1|tJQb6rCNT|>(d15+zwV=EJL zZ36=<0|P$ZgN7&?a`RI%(<*Ums1K;@1!~X$*-%`TZk3c+oT^(|l*y2mnUiXzudiQ{ lTcDqtn4X!Ot?OD6>64jiR_Rw|^$e(o!PC{xWt~$(695M7&lUgx literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_outline_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1be49fcdb2a3095725c3893ef70fbe786097bf80 GIT binary patch literal 621 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)pVryh>nTu$sZZAYL$MSD+10f-TA0 z-33Sk!B6Mi^+1ZVz$3C4NPB>>+sSM@pz(U1E{-7?_uk%c^g8Sya_r;#*&OSlUa20L zYwI8uw8vrnqzM=1mM-;CV81BL!IkG!%^JH~bYm=kVIa#)KhE6DxaRlU=a^jnoD&1=*-{mQxi<+N!G^X3*$-lTK?Z*y8Z@9k^M z27QY%=Bb>l6lboRE1CRmmkh(C>;G|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+K;un3T^vIq4!@mdo7e0h;I`j!;5gl-}gUDwd3TK|j2cmzWAMExPNlaeWfo*;j_mW#SwxOm%|R z9gib4mwpQrv7K1+LRai$_o5p+MY`TNXl@msSkl46FyW3=@*mF56Q6IedgM)3sVr74 zG2Ue2`|?wE^$(@WD^dBMZ2o6XD*vx>Ax%-~^{#b{3fYq`-oIYl+_C4@$0tq<@7^AG ze!|XUU;OS590`_7PDHo6JP8R64GRrbQ(C^Tv{)iiK&o}~{9QWUFRRLJ-hSGIx1!9RNb~cPxfvrS#`NlD#V78!NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)pVryh>nTu$sZZAYL$MSD+10f-TA0 z-33Sk!B6Mi^+1ZVz$3C4NPB>>+sSM@pz#i#E{-7?_ukIf?RVHg!1evsi7T2G^u5s3 zjNRd2vZcd+W2(07Lg(y{x*e00gnFOmFIe6yuyETnr9}t$o95n_ELwbOtEqLmd~zj& zYoN$e`@_o)TJ)W_Ilr5|fHUEerb1vn@@h^Omf~q$7N`neKLsIv(eG4A)<6kLzzpHfAiyU8}oD z!>Tm!!EE9C-{oV(7#g&%v-ZV^uP9V7Eu5BWua$8B)$>1mD;i9+6wW>fT@jVLYv1;j zR+jsjLHzOsZ+Tu%k6``AB09nCO?^W6UH<3g3p^84=U&mT`Qw_PI5$;VWxhGrlvGRR z4|;QRn7tVaOE+AbtJjqz$#PKnq~=M@U!^O`Pj)>KJ}I4iW_E#I*CLHm^FFeE+~;|| zrv2|fV4$j&xJHzuB$lLFB^RXvDF!10Lvvk216@PQ5Cc;yV^b?5Lu~^CD+7aNYkE(k zXvob^$xN%nt>OAd({i8&4Ui4RW$9K)iN&e9rA3(xX_+~xR{Hw-CAkIqxrynS$=SL^ bmL(ZxiCLkybCiIIgn_}+)z4*}Q$iB}+&twy literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_information_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..496421cecaabe8b828d42e003467d8c4fea606aa GIT binary patch literal 1692 zcmZ{kc~sL^7RO%#$X1jnOB5Y#ELN6~1j81T0tQLgiBXJ@Q%Kk{1PBB$Xd{b&VZd<# zH6Xzbr=cjDVPGg?Bo!M}WD_VU1k!-A$&PHY%>11H=8w7OeDCMn_s;jdKkhv@H^9%+ zK<|Ja0KkAuB2pk?zer~nl!M?K*CA*|x%s*QAi1f(6{ZE%FfPT@9n^FloPvrYOcKQx zfXl}KNY4V`GjxW|+<&bDxh@}7O z%#-mT$vk@P+O@_YstgKd zk4KYq48f@V>>L3z~YhO$L6heF)tTUXOwc|X4cf1zG@ z8j4*P>u+eGJ_A_*>b7vr{h8~W4uS@z3(dG;k&%&UkG@q~*^!SJI;!1w98i}nZj(Z6 zuJcUnn}lIV70IFnJi%SLAz0OdXN-Z}#_fThbU&@FT|)Hi|7}}p$e8c$?ymlDD<}*p zH?jDj1<-HAL1T;SQQjt4EVf(tI{d2ULPhI#v*G9;UIjr!pBIbY0Oegu9H#!I$q(7K zMQ?H0TPk9`%4#DT@8#$Gmz(#uMi>%BM>PJkZF=pZ%0ZHWi-b+4n6(a<+$Q~`o98hN z6HF=+RjC+3+n8!F>u@@5H8L&j-(#g(oX%!-#gkQv6E${;7F~Q#lQXP-d=wS$f5b?y zUvb6k+rQsyrry(Nuba~lSj^e<;+NOQ`5GM^9kH*5g~Pr0*-sQQFLfd>L(mB)*~;sj z2g{QPQhnJ^Cv5x?Om^caVZPzT`MtSBMk&{&Trf=?ThcTPtYmy2!djw{EZXuCxW+Q% zP|a6QpI(H6_iw8cHIyG^$9{Vr*!lKDAI!9ZTd54WA9$**d!^+KB0$&L+WM_!%`>#) zn($+qz5|TwBv&erR(jOb)Y$y^%Umjg)5hxS>pLmA2zQ*AR$f|SP_+?s?jYrjsM6e3 z6#QY_GM#(XL*gv)3eA@W-rlp?e+pixtAefGHSEU9&pc7! z+6RX+e+>;6YxWHcwCIOcwl*BeLMG%T8;7o0dfs&o-Ji1<((u|Wr)Rf}I=&Om-f-34)W*}>^@WL^|2WP6wfg14!U7#N9jG)D7n*+6 zs-T!JG4)b`BeiNOI0+N(aM9m#4jQX)`~m*+%=bg$LKTeX)r8-Bv#rb6EcmQts<(H0 z(8|h6H7HH`B^l6XXJ;8*rKbw^?b}y&aI~ED`@b3*_7m}XuESi>+U9n=kB^Vhw(e+C z(*rMYr<;YfeT{|y(L<}%PV2=dUlDzmsqB}NcU(P+n`w&Kl`$}q((Fg%mMr5okvwDB zjhvjE{XqEe;U2i+jZ>Q3Wnj)D?sg*M<@{O;lXhONUu*vGPFc?+3>^OYQu1TX9nejm z76k<^nFS+vsHwu0IVba5yV0mVm{! z8sV(|#}FGI&WcR^|Asnp?tRE`{L2sAlqdotj2nSYPGo^d7CVA~!C;bNIhfe6C>ApY bo#+{t%)zEO26NX(ArByX_z`Q|Lo@#a!xZ=F literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_tune_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_tune_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..895b7dd89cb14f463071f878fb2a59b76eae514f GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)pVryh>nTu$sZZAYL$MSD+10f-TA0 z-33Sk!B6Mi^+1ZVz$3C4NPB>>+sSM@AY+23i(^Q}y|*_may2OMv?g}P-CTad`TA6W zLwY5*62H`!3r4i(YD{Bd@M?c`cHQ;6HCDEJ>nNPUwF4UWHN}CEFYlUaBJJXzgZB~r{A?M`fj)Q zwfReJ2L{t`jHXNs2lm@OnWeXIl7_}lpxabSTq8LfwqBxm4Sh7v&nB14Y~O#nQ4`{HN@QOaR+M90NGGnmTr}lSe&X`T9nC< umYI`krLV7Fl3Spko0y)NoUNN}=9=i_Z)&RbbJI7V9tKZWKbLh*2~7Z_!Ivcf literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_clock_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_clock_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a1644a351d3f10d3b6971693d5f2215c3ec1d5d8 GIT binary patch literal 2628 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 Yrs>|{p=q%@fqED`UHx3vIVCg!0Q&y+pa1{> literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f2771c3ec45d00b09c52556cff5f3e893d8bb663 GIT binary patch literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3*4jLGmdQ8XA_j9NQ$|t6b`Q}U@2HvT$9lU} z46HSm)E@g+_ts|1VtbvSjobo)AP{)I};n`WW8iJvpS*d@-YBo>jwh z*P9zIzm!>X{k1lOJi{C2ik%0u_h*~UHk#?PF34RYnT<;^g}?A#&c|QXD(l5%bDdiBr2*WW6ZcefWywztn$SU#o0=_uiRy zhVc(WL8Qo0i}RmDZ$6y+|Mwa7RPh7R4Dp+EW^cRw_V1>{=M68+@5|nLYr8YNqLh&ULuhUOSqYAYRdSKWY)lGD)z^9&Wq6(>D6lhIN}M?8z{gf(Frk@b zp}=nf&vRcr)hfy5JtfEdZ)VkNu9^3@z7gB)v9~nT<;kU4GaI`WNife?8n=&WbJbqE zZEa}_Y|e)p9uu~C>#>4?0aiG*DpV6?X~L?kM$YWhkl*fk@Kl{{;8F( z)^^m0PYhgq(L$Q9eSh$K7YL}|&F-+iCZMm&%?OwXR7+eVN>UO_QmvAUQh^kMk%6JP zuAzahp=F4Hsg<#@m5I5wfq|8Q0Uz%{Llh0U`6-!cmAEz32UPX~HE4irC@xF4N=htF z)h#W`WJt@*Nww0~*DuK}(9caw&rHtNHSlo_iSjn|GL@VC0jP(;)78&qol`;+01F&2 AY5)KL literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_outline_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..8e6e7cb17219e0ffffb5b9537ba94aab88ec5722 GIT binary patch literal 829 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3L)t;QqRu;e3oX%pdelZ;IS~*G?hk2!teK5KA27^Vey@i0+1IMtB;K&O-#>B&eqLz&xZmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIA^$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG z?d}4kf#9d}?s_1_S>O>_45U54*zIJt9nkpOo-U3d8TZ~!-1}Qwz{|84~_U8rl@oDIxgI}VCh1ZZt(&oEA`jT(rd35 z=H&0OpS6C@POI;Aw{BjIJz&6d*r4Z-;%2E;ySzU!H^d6wj8LkMSbg=|Vht%VH=odW z#vd#SF^2Z$J2f|kt^R7lbND`kT>2Jwy&}g=0qd{x8&6?saFaPM{EZE-@y-PW$y8A{p;f;uIhxGp`aRdW$v=%# zS3uu$-ZIludTf*0&+VLhs*~|Ricw}*kPb)FS+B088(*DO688AV^1&|fpN7)yrDDPp zCw~8T`t7V$ePJipywR8yanoSqrj6IuFZv!Q7O~rY_3~B4`7fu|CaHy)UHjE%`MmG) zE0zCM@6YF55Ba*aW6z9@`y!Ic|2Wn&7ff5RS9$05H*r&CU4^x!f$F(FF6K;#4*h*H zO7zG)28$C$1z94V_nzeL)W}Tt6PA8fd%;z3qJ8nvLk2eN1v9@ViYJ)J^`C#<mNHb>+6@~ l7U<_Dre`K+>xP)68inM9hi_%wwGgO>!PC{xWt~$(697G`G0Ok| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e8af6bab5aa61278a5d60a696493e2c2ecc04f0f GIT binary patch literal 851 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3T(C)U%-DsHArj;PiuRE(*+m3qLN)D z3`ah4YJA*!>;3k5w|_m;58t;+rlA82PO05%Qt@2$wCE?_0mFuLhHqv?i4zZIm{{@3 z9{9W<K$S~Zv`(SIlsTA)_zvbc!l|>AhRXv679;@7V^mVx1r9RUL z9WnJAc`^(QtJMD1{WmG$=$7Go=HsF1h`d&zb$_7*MuruyinEV7Fu0`LpJh0qxlv~81?eC1k3arc&weLY zCa;p+QsTrx2R^nU1CS)olLQ6#r+i)46bpjwf3I)%yyu9JT5%^hXYO*I|91lwLF(9< z5n2})u^%m+^0P?%JxI7K?$I8uy*q_!x3jsfXRPPj`&y`WBb#e|Qu@O3STR9E`_+;f zr#EpnRK7SnJwfjH$0Jg+8ZVjbJ@@$!N4fPSoAaL+A58dgIV#{s?);lM-xlA@sXO!e zk9NcHRlhu3%zpOHzqInz)Q%dViGh3L>g{Ft_P5>>76gO8@7S){cW;}NEqNT6SX4_~ zBT7;dOH!?pi&B9UgOP!uxvrssuAya!fvJ_Tsg;qTwt<0_fx)shy{Az$3nZc<<%yw)6af=DB7|fJEtE+V93X@e%+Lfv2f@M+U?>hU5Tytf zhAJftOc01fsuU3(O+khxUB`$(KzN_;-}~|ITKDdC?p=HBbMIPb-;?G{u#pm%7Y6`9 z$`+4x1rh&!iVA}(X|vG=1i=6+M=JoR&z3l#2!Syq!qo-?)D9`Gf`PIx-qjHR;?w~k z`3?Z^!L8&K0EpBBfHiLbFf9Oplh+H`F6Q8Yu#deB7DRCDS+^#EAa)(^9s%NiHGv=c z0xbYQRMr-2MU0u=eBc?Rc;$G{(TBK>=MRj-a@p8ev86|w63&I}3LP6qqLu7iDf~qy z(d!|L)!W%Ol!e2xr!CxKs1tJTnl*g_viMx+ITsaIY#y=HOYIMWnkJ5>Vx{`{me|kp zs{3uI)KsO>-Xb%z#uCHnlEr+Jo#M8gk9)>D?;>u(luYR>uPIHKnnNp`3lfW#oXY^V z>JPUBUrQ+a7`y^ngy%F-WCZ594fdoYH%5!;Kt22@D6gRKc9FOD6+ZGWKma%}U~B60 zVv(k>Ie*WIqoztBS5l-1N(*S0d|35jO9~k`gC6v|z)XlBi9OcnR{;=M^knr-UEeHb ziKBXMxx!{kDbzjtjVe5`5!b2x;W0&S*ul~9+anj4f_hGwMmBsT1BjbO4%%o#ce85O zJ7{+r*+S_(3#CDZW>RzKq-RbrRwPj+$1on6d3H(Cg3v3sUw8`x;whNNZrZb}JNuVt za@~nomJ|mDB!(mc!Oy(ZHE`Uw*YPFE z`g7tEb|5WWT*>HO!r=&$$yCreiFdhYf#jk?^vNU|zw*iiGAw4Q~)3(SFBjA#ne z$b^uyqBM$*R?F>6YIb-yGBQ%^tU(vf^LF}y$tV{2WbHT_Vu+DbDDC{qgW$h>8W1%` zCpHr`gG-8w+h^%FtD}d`8DF}bFU6H(-oGDLeyUUZtbFEIi8EP{-Fw!JU@AA7C!&A* zWGc6wvY|SZmSEA*M4AUIHS_MD#C#Em87!R|^42q6`ge2r%4L^(p)w=ceo@pzoGK#L zW0d7l_0ruZB&4=3mbZK*EwNgzj-(@M$#69Mv+;+z z+I1)B+~thM1VX*rhF)^0?MB8E*VXpb)zu_+*fJl^+yC|>Y`(B1e5pVBO0qG)`TP3r zIpD0?*T@?kmsZD_Rc7Fm*)Ud|5WJ=DxfZ*roXD6GuUd~Aq%e*@@&v9o7Zow1Tih4f z?AweLle7vyxo-T$d2~i!Ump%B4{`o#d^QwXQOOqISR;7ZKkYSrPJc=Z6)3n{kost3 z9p0%xH1P-62AV;%@P7KmZEH63O_mCR#4od?Lj739_slE!a6r5UB+PaJJD zEW16hTngU{11uCqQwPl7ZuPZ3X>Hvv|6{Qwe?cqHF56^#+vF5;&!ul$CG&aw+TPW_ z&fLYnOYicrfta_wqb~I&A=kCqZqNU-D^EmhL_yoe2E+^mkPS*G)Frv>9&WKv{|BCR z-TOp0{1eyE=J-yp5%i{ca+Tpz@ALTzpS5#n_rD=VY1O|nrnDTe0jh?y>F!mv#Oy`> zUeqw_a=~8VBEPM{qDl0NSL@lUA`SJgme+QV=XQzYD_mToR(F|aeLL0wBShzH_P2SQ zCv!Es(2i4+6a9Q+F;@4MkCW4IO_USsa(Y*pwvkt^rP7>s&Sp{gLU*Qt+Y>=3WU2@` z6B&l+HS9SiDLfN2S%beL(}wub5jyo$RFb<(|E^h5-`YFy=72?1rhZjKRYT2tqFiq> zRucQRgEx!)l_se_q{z$)Aut1PJp-1Du2~2Bw!K^kyJ?rw+oR_g;Wh50nM08ag=kC{ z@MUqQIGQRY!=VCoBi%#>7D*e1g5@EJdi#3?tNvCs)nW8r=AH-gZf`%IBq2-A^LSsb zVJBE6NFq%@aychkl}0yq!KQkQhfXQpDxeF zJ1Q;554Q_n9(=ooo+c04v^tX_0nW}w5SD&+#E_s!` zrAZ7ck_Ju6g_zFT+`Ve}AQ7&m()rXuJz~N^@{=99C!eBvR`=U*>A>FVk_ zOAQFH-*l#aoNe>`>Cd282R{^H_d znf=7Jn4eUwljuLDsQ2V2tI%XWW5pX_xuE@QUh+jQN-3wWiFhnCW25b}k=hg`+nD1V z!pXsB`n*@;l;3%u+B=*U78a!4t3JagpVj=%6NYbAe9*wolq`YP>8&AaXN9P@YhlwB z`_Y5;o}Qjb>uYO#CuNxyF`&yQtcD_|AjNHYzzDenYZ~E(4&32V)b8SCFMgptx3qUV z!x;uxW|i#(?E7)_X3V!*`Iy&+MFg^Uv5vphos0c)d>tMlI%qn!Uq?zc ze}K~6IC@9b+U5Idff69=N!O(K#HwlE$Y`1&TgrcT^u-2 zPWH~M6$gggX>T4i-C$oSv~2b*LMZwy-=H39!)G$=bl$`z5M9D0@^DK~6d75zlXk7W zwKaa|+>6;#>(uW*aZAw=G@)oKr%1H%C$L#iqvPD@eiXXDsc*PH2*3qBeIp%xJso`$ zqMm^%%Ft9_UrSHVR8Nm9tFQGxgy2v=8a4L+6B=yO@ecZG{%*L8y_0W{x0oye=PSHeRu`UiELuR#uAiz8rbG2XZS1BneyKL7v# literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_tune_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_tune_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..bcbd526ad723a8d76df79111473c6c3b6869009e GIT binary patch literal 532 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 J_2#~p{{xxaNyz{J literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_18dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_18dp.png new file mode 100644 index 0000000000000000000000000000000000000000..aa099c90d75fed24c2e085f9fe26923b4272a843 GIT binary patch literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!Ea{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3*4jLGmdQ8XA_j9NQ$|t6b`Q}U@2HvT$9lU} z46HSm)E@g+_ts|1VtbvSjobo)AP{)I};n`WW8iJvpS*d@-YBo>jwh z*P9zIzm!>X{k1lOJi{C2ik%0u_h*~UHk#?PF34RYnT<;^g}?A#&c|QXD(l5%bDdiBr2*WW6ZcefWywztn$SU#o0=_uiRy zhVc(WL8Qo0i}RmDZ$6y+|Mwa7RPh7R4Dp+EW^cRw_V1>{=M68+@5|nLYr8YNqLh&ULuhUOSqYAYRdSKWY)lGD)z^9&Wq6(>D6lhIN}M?8z{gf(Frk@b zp}=nf&vRcr)hfy5JtfEdZ)VkNu9^3@z7gB)v9~nT<;kU4GaI`WNife?8n=&WbJbqE zZEa}_Y|e)p9uu~C>#>4?0aiG*DpV6?X~L?kM$YWhkl*fk@Kl{{;8F( z)^^m0PYhgq(L$Q9eSh$K7YL}|&F-+iCZMm&%?OwXR7+eVN>UO_QmvAUQh^kMk%6JP zuAzahp=F4Hsg<#@m5I5wfq|8Q0Uz%{Llh0U`6-!cmAEz32UPX~HE4irC@xF4N=htF z)h#W`WJt@*Nww0~*DuK}(9caw&rHtNO*HW_&G4}__wFVdQ&MBb@01SFC AaR2}S literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..36c7cfb43bee7ff6f735410e21b43f511658af94 GIT binary patch literal 942 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3^ zpBI`MIh}^Dsu=Gzu$tY<6k8^<&A27EN6llwcfOtlog#M{H-3A}=5Y6J%Goy?Z=ULS z&z<;V^W)E}&!?P!V{DwGaf}CO3mBNpmH*zbNJH${e=g+@nsF0boBY!4?h>&n386kzAL3!`OGsO-+h0!3l`q@E4V(VDZ0D6d*A;3{~bTv z+N^vuvo%$dA_+85r*?`cihv)3vEF_q^ z{Bq^8dyluM?2jnlzc}ubzO|@trHm@G%MsD9lic52?XXt-8518D$M<#8^O*Z*_RYAN z=aRE_{rY;Fa|c;0Vjp+h$k-a?zw7Qhjpq%;pO0@hD;rT4n0&8ddl)+VO&vHtv~M*mLJRPx;4L_wcuV#6L{Z22xzY=KA^Nq}~l<-e~Kckf4TAx=euD5_XsH|GNfhZq+03g>zCvf=;tP;XC`OsCOQ}A6}q^DMfyF`0J+rD)z4*} HQ$iB}x7c|; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_outline_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f994bcf946595ebda644c6506ac2e7f94cade201 GIT binary patch literal 966 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_tune_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_tune_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d46fb7e76d9dc47ddd7fa608d30d525b6901691d GIT binary patch literal 586 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGoEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ua371Hn({-St3Vm(%+WxoUpj7&0a?9bxIn zjr+WA?c(h0*FW|i-(M=9$OaVS6cAQWgD85=$bF7E&kdoTQ^2}LzF=Ev#aSL?b&N^t z*P35>&w6$L{$tgS;>yTYSn_wwWQ1A=G5SqW_PhGq?laItOYU>8+W&p?_aD>GAX_M` zP`2{_x#IHE4irC@xF4N=htF)h#W` vWJt@*Nww0~*DuK}(9caw&rHtNb@X#C@HcnL4l=3z19GINtDnm{r-UW|YJRrT literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_notes_list_view.xml b/app/src/main/res/layout/activity_notes_list_view.xml index 61d9873b1..345230dc0 100644 --- a/app/src/main/res/layout/activity_notes_list_view.xml +++ b/app/src/main/res/layout/activity_notes_list_view.xml @@ -4,22 +4,40 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:orientation="vertical" + > - + android:layout_height="?attr/actionBarSize" + android:background="?attr/colorPrimary" + app:elevation="4dp" + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + > + - + + + + + + + + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="?dialogPreferredPadding" + > - + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_layout.xml b/app/src/main/res/layout/drawer_layout.xml new file mode 100644 index 000000000..399492b7c --- /dev/null +++ b/app/src/main/res/layout/drawer_layout.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_navigation.xml b/app/src/main/res/layout/item_navigation.xml new file mode 100644 index 000000000..171d3f6c6 --- /dev/null +++ b/app/src/main/res/layout/item_navigation.xml @@ -0,0 +1,44 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_list_view.xml b/app/src/main/res/menu/menu_list_view.xml index 6d7f8fbc9..35c46640b 100644 --- a/app/src/main/res/menu/menu_list_view.xml +++ b/app/src/main/res/menu/menu_list_view.xml @@ -5,19 +5,8 @@ tools:context="com.example.owncloudnotes.NotesListViewActivity"> - - - + app:showAsAction="ifRoom" + /> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5a53bff5f..fcd147985 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ No notes yet New note Settings + Search Save Cancel Edit @@ -17,6 +18,11 @@ Note is deleted Note is restored Undo + open navigation + close navigation + Recent + Starred + Uncategorized Delete Copy Edit @@ -28,7 +34,6 @@ About Chose category - Please enter a category name Copy Today diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1ddbdcae0..849638e7e 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ - + + @@ -42,7 +48,13 @@ @dimen/button_elevation - + + \ No newline at end of file From bc34f015e56708a6448a02e07d5185b7227e2788 Mon Sep 17 00:00:00 2001 From: korelstar Date: Fri, 17 Nov 2017 08:26:09 +0100 Subject: [PATCH 2/2] select category when opened in navigation --- .../android/activity/NotesListViewActivity.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java index 65588b2a7..7a56b5b54 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/android/activity/NotesListViewActivity.java @@ -189,13 +189,18 @@ public void onClick(View view) { }); } - private void setupNavigationList(String selectedItem) { + private void setupNavigationList(final String selectedItem) { itemRecent = new NavigationAdapter.NavigationItem(ADAPTER_KEY_RECENT, getString(R.string.action_recent), null, R.drawable.ic_clock_grey600_24dp); itemStarred = new NavigationAdapter.NavigationItem(ADAPTER_KEY_STARRED, getString(R.string.action_starred), null, R.drawable.ic_star_grey600_24dp); adapterCategories = new NavigationAdapter(new NavigationAdapter.ClickListener() { @Override public void onItemClick(NavigationAdapter.NavigationItem item) { + selectItem(item, true); + } + + private void selectItem(NavigationAdapter.NavigationItem item, boolean closeNavigation) { adapterCategories.setSelectedItem(item.id); + // update current selection if(itemRecent == item) { navigationSelection = new Category(null, null); @@ -206,6 +211,7 @@ public void onItemClick(NavigationAdapter.NavigationItem item) { } else { navigationSelection = new Category(item.label, null); } + // auto-close sub-folder in Navigation if selection is outside of that folder if(navigationOpen != null) { int slashIndex = navigationSelection.category==null ? -1 : navigationSelection.category.indexOf('/'); @@ -214,8 +220,11 @@ public void onItemClick(NavigationAdapter.NavigationItem item) { navigationOpen = null; } } + // update views - drawerLayout.closeDrawers(); + if(closeNavigation) { + drawerLayout.closeDrawers(); + } refreshLists(); } @@ -223,7 +232,7 @@ public void onItemClick(NavigationAdapter.NavigationItem item) { public void onIconClick(NavigationAdapter.NavigationItem item) { if(item.icon == NavigationAdapter.ICON_MULTIPLE && !item.label.equals(navigationOpen)) { navigationOpen = item.label; - refreshLists(); + selectItem(item, false); } else if(item.icon== NavigationAdapter.ICON_MULTIPLE || item.icon==NavigationAdapter.ICON_MULTIPLE_OPEN && item.label.equals(navigationOpen)) { navigationOpen = null; refreshLists(); @@ -286,6 +295,7 @@ protected List doInBackground(Void... voids) { } else if(belongsToLastPrimaryCategory) { if(isCategoryOpen) { item.label = currentPrimaryCategory + "/" + currentSecondaryCategory; + item.id = "category:"+item.label; item.icon = NavigationAdapter.ICON_SUB_FOLDER; items.add(item); lastSecondaryCategory = item; @@ -299,6 +309,7 @@ protected List doInBackground(Void... voids) { item.icon = NavigationAdapter.ICON_MULTIPLE_OPEN; } else { item.label = currentPrimaryCategory; + item.id = "category:"+item.label; } items.add(item); lastPrimaryCategory = item;