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..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
@@ -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,258 @@ 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(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);
+ } 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
+ if(closeNavigation) {
+ drawerLayout.closeDrawers();
+ }
+ refreshLists();
+ }
+
+ @Override
+ public void onIconClick(NavigationAdapter.NavigationItem item) {
+ if(item.icon == NavigationAdapter.ICON_MULTIPLE && !item.label.equals(navigationOpen)) {
+ navigationOpen = item.label;
+ selectItem(item, false);
+ } 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.id = "category:"+item.label;
+ 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;
+ item.id = "category:"+item.label;
}
- 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 +418,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 +451,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 +508,7 @@ public boolean onQueryTextSubmit(String query) {
@Override
public boolean onQueryTextChange(String newText) {
- refreshList();
+ refreshLists();
return true;
}
});
@@ -383,29 +523,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 +540,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 +553,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 +613,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 +650,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 +678,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 000000000..1b4ca3615
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_clock_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_folder_grey600_18dp.png b/app/src/main/res/drawable-hdpi/ic_folder_grey600_18dp.png
new file mode 100644
index 000000000..f089f29f4
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_grey600_18dp.png differ
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 000000000..cbdc108b9
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_grey600_24dp.png differ
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 000000000..a00be0fe1
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_outline_grey600_24dp.png differ
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 000000000..3367526cf
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_18dp.png differ
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 000000000..1da52c23a
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_folder_plus_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png
new file mode 100644
index 000000000..4158cf814
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_tune_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_tune_grey600_24dp.png
new file mode 100644
index 000000000..fc1f20f1f
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_tune_grey600_24dp.png differ
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 000000000..f4934533f
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_clock_grey600_24dp.png differ
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 000000000..0bb6b02b8
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_grey600_18dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_folder_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_folder_grey600_24dp.png
new file mode 100644
index 000000000..885d18995
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_grey600_24dp.png differ
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 000000000..3675b6ef5
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_outline_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_18dp.png b/app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_18dp.png
new file mode 100644
index 000000000..8555f8514
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_18dp.png differ
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 000000000..30fed8add
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_folder_plus_grey600_24dp.png differ
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 000000000..7930918e9
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png differ
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 000000000..9a5138d6e
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_tune_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_clock_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_clock_grey600_24dp.png
new file mode 100644
index 000000000..8a7e7373d
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_clock_grey600_24dp.png differ
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 000000000..e71192204
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_grey600_18dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_grey600_24dp.png
new file mode 100644
index 000000000..1e0330d7f
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_grey600_24dp.png differ
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 000000000..1be49fcdb
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_outline_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_18dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_18dp.png
new file mode 100644
index 000000000..d1faa8326
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_18dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_24dp.png
new file mode 100644
index 000000000..44a101be3
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_folder_plus_grey600_24dp.png differ
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 000000000..496421cec
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_information_outline_grey600_24dp.png differ
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 000000000..895b7dd89
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_tune_grey600_24dp.png differ
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 000000000..a1644a351
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_clock_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_grey600_18dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_grey600_18dp.png
new file mode 100644
index 000000000..1807bd44f
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_grey600_18dp.png differ
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 000000000..f2771c3ec
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_grey600_24dp.png differ
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 000000000..8e6e7cb17
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_outline_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_18dp.png b/app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_18dp.png
new file mode 100644
index 000000000..11d0cb258
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_18dp.png differ
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 000000000..e8af6bab5
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_folder_plus_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png
new file mode 100644
index 000000000..4c712fc59
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png differ
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 000000000..bcbd526ad
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_tune_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_clock_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_clock_grey600_24dp.png
new file mode 100644
index 000000000..cec5f6de6
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_clock_grey600_24dp.png differ
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 000000000..aa099c90d
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_18dp.png differ
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 000000000..36c7cfb43
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_grey600_24dp.png differ
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 000000000..f994bcf94
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_outline_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_18dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_18dp.png
new file mode 100644
index 000000000..5e423f0b7
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_18dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_24dp.png
new file mode 100644
index 000000000..d8a1ac2f7
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_plus_grey600_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_information_outline_grey600_24dp.png
new file mode 100644
index 000000000..2fc07cf73
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_information_outline_grey600_24dp.png differ
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 000000000..d46fb7e76
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_tune_grey600_24dp.png differ
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