Skip to content

Commit

Permalink
Resolves #150, #59,
Browse files Browse the repository at this point in the history
Reworks notes filtering.
Adds more sorting orders.
Sorting Order is now persistent.
  • Loading branch information
coderPaddyS committed Nov 4, 2023
1 parent 3cc1c3d commit 4b03d45
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.secuso.privacyfriendlynotes.model

import android.content.Context
import android.preference.PreferenceManager
import org.secuso.privacyfriendlynotes.preference.PreferenceKeys

class SortingOrder(context: Context) {

val prefManager = PreferenceManager.getDefaultSharedPreferences(context)
var ordering = Options.values().filter {
it.name == prefManager.getString(PreferenceKeys.SP_NOTES_ORDERING, Options.Creation.name)
}.getOrElse(0) { _ -> Options.Creation }
set(value) {
prefManager.edit()
.putString(PreferenceKeys.SP_NOTES_ORDERING, value.name)
.apply()
field = value
}

enum class Options {
AlphabeticalAscending,
TypeAscending,
Creation
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ public class PreferenceKeys {
public static final String SP_DATA_DISPLAY_TRASH_MESSAGE = "sp_data_display_trash_message";
public static final String SP_VALUES = "values";
public static final String SP_VALUES_NAMECOUNTER = "sp_values_namecounter";

public static final String SP_NOTES_ORDERING = "notes_ordering";
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,33 @@ interface NoteDao {
@get:Query("SELECT * FROM notes WHERE in_trash = 0 ORDER BY name ASC")
val allNotesAlphabetical: LiveData<List<Note>>

@get:Query("SELECT * FROM notes WHERE in_trash = 0 ORDER BY name ASC")
val allActiveNotesAlphabetical: Flow<List<Note>>

@get:Query("SELECT * FROM notes WHERE in_trash = 0 ORDER BY name DESC")
val allActiveNotes: LiveData<List<Note>>
val allActiveNotesAlphabeticalDesc: Flow<List<Note>>

@get:Query("SELECT * FROM notes WHERE in_trash = 0 ORDER BY type ASC")
val allActiveNotesType: Flow<List<Note>>

@get:Query("SELECT * FROM notes WHERE in_trash = 0 ORDER BY _id ASC")
val allActiveNotesCreation: Flow<List<Note>>

@get:Query("SELECT * FROM notes WHERE in_trash = 1 ORDER BY name DESC")
val allTrashedNotes: LiveData<List<Note>>

@Query("SELECT * FROM notes WHERE category=:thisCategory AND in_trash='0'")
fun notesFromCategory(thisCategory: Integer): LiveData<List<Note?>?>

@Query("SELECT * FROM notes WHERE ((LOWER(name) LIKE '%'|| LOWER(:thisFilterText) || '%') OR (LOWER(content) LIKE '%'|| LOWER(:thisFilterText) || '%' AND type = 3) OR type = 1) AND in_trash='0' ORDER BY name DESC")
fun activeNotesFiltered(thisFilterText: String): Flow<List<Note?>?>

@Query("SELECT * FROM notes WHERE ((LOWER(name) LIKE '%'|| LOWER(:thisFilterText) || '%') OR (LOWER(content) LIKE '%'|| LOWER(:thisFilterText) || '%' AND type = 3) OR type = 1) AND in_trash='0' ORDER BY name ASC")
fun activeNotesFilteredAlphabetical(thisFilterText: String): Flow<List<Note?>?>

@Query("SELECT * FROM notes WHERE ((LOWER(name) LIKE '%'|| LOWER(:thisFilterText) || '%') OR (LOWER(content) LIKE '%'|| LOWER(:thisFilterText) || '%' AND type = 3) OR type = 1) AND in_trash='0' ORDER BY type ASC")
fun activeNotesFilteredType(thisFilterText: String): Flow<List<Note?>?>

@Query("SELECT * FROM notes WHERE ((LOWER(name) LIKE '%'|| LOWER(:thisFilterText) || '%') OR (LOWER(content) LIKE '%'|| LOWER(:thisFilterText) || '%' AND type = 3) OR type = 1) AND in_trash='0' ORDER BY _id ASC")
fun activeNotesFilteredCreation(thisFilterText: String): Flow<List<Note?>?>

@Query("SELECT * FROM notes WHERE ((LOWER(name) LIKE '%'|| LOWER(:thisFilterText) || '%') OR (LOWER(content) LIKE '%'|| LOWER(:thisFilterText) || '%' AND type = 3) OR type = 1) AND in_trash='1' ORDER BY name DESC")
fun trashedNotesFiltered(thisFilterText: String): Flow<List<Note>>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.secuso.privacyfriendlynotes.ui.helper

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.core.util.Consumer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import org.secuso.privacyfriendlynotes.R
import org.secuso.privacyfriendlynotes.model.SortingOrder

class SortingOptionDialog(
context: Context,
sortingOptionTextResId: Int,
sortingOptionIconResId: Int,
onChosen: Consumer<SortingOrder.Options>
) {

private val dialog = BottomSheetDialog(context)
private val recyclerView by lazy {
dialog.findViewById<RecyclerView>(R.id.sorting_options)!!
}

init {
dialog.setContentView(R.layout.dialog_sorting_options)
recyclerView.layoutManager = LinearLayoutManager(context)

val icons = context.resources.obtainTypedArray(sortingOptionIconResId);
val options = context.resources.getStringArray(sortingOptionTextResId)
.zip((0 until icons.length()).map { icons.getResourceId(it, 0) })
.mapIndexed { i, (text, icon) -> SortingOptionData(
text,
icon,
SortingOrder.Options.values()[i]
) }
icons.recycle()
recyclerView.adapter = SortingOptionAdapter(options) { option ->
onChosen.accept(option)
dialog.dismiss()
}
}

fun chooseSortingOption() {
dialog.show()
}

data class SortingOptionData(
val text: String,
val icon: Int,
val option: SortingOrder.Options
)

inner class SortingOptionAdapter(
private val options: List<SortingOptionData>,
private val onChosen: Consumer<SortingOrder.Options>
): RecyclerView.Adapter<SortingOptionAdapter.SortingOptionHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SortingOptionHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.dialog_sorting_options_item, parent, false)
return SortingOptionHolder(view)
}

override fun getItemCount(): Int {
return options.size
}

override fun onBindViewHolder(holder: SortingOptionHolder, position: Int) {
holder.textView.text = options[position].text
holder.imgView.setImageResource(options[position].icon)
holder.itemView.setOnClickListener { _ -> onChosen.accept(options[position].option) }
}

inner class SortingOptionHolder(view: View): RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.sorting_option_text)
val imgView: ImageView = view.findViewById(R.id.sorting_option_icon)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.preference.PreferenceManager;

Expand Down Expand Up @@ -60,6 +59,7 @@
import org.secuso.privacyfriendlynotes.room.model.Note;
import org.secuso.privacyfriendlynotes.ui.AboutActivity;
import org.secuso.privacyfriendlynotes.ui.TutorialActivity;
import org.secuso.privacyfriendlynotes.ui.helper.SortingOptionDialog;
import org.secuso.privacyfriendlynotes.ui.notes.AudioNoteActivity;
import org.secuso.privacyfriendlynotes.ui.notes.BaseNoteActivity;
import org.secuso.privacyfriendlynotes.ui.notes.ChecklistNoteActivity;
Expand Down Expand Up @@ -141,14 +141,8 @@ protected void onCreate(Bundle savedInstanceState) {
recyclerView.setHasFixedSize(true);
adapter = new NoteAdapter(mainActivityViewModel);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();

mainActivityViewModel.getActiveNotes().observe(this, new Observer<List<Note>>() {
@Override
public void onChanged(@Nullable List<Note> notes) {
adapter.setNotes(notes);
}
});
mainActivityViewModel.getActiveNotes().observe(this, notes -> adapter.setNotes(notes));

new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT) {
@Override
Expand Down Expand Up @@ -259,9 +253,16 @@ public boolean onOptionsItemSelected(MenuItem item) {

//noinspection SimplifiableIfStatement
if (id == R.id.action_sort_alphabetical) {
//switch to an alphabetically ascending or descending order
updateListAlphabetical(searchView.getQuery().toString());
return true;
SortingOptionDialog dialog = new SortingOptionDialog(
this,
R.array.notes_sort_ordering_text,
R.array.notes_sort_ordering_icons,
option -> {
mainActivityViewModel.setOrder(option);
updateList(searchView.getQuery().toString());
}
);
dialog.chooseSortingOption();
}

return super.onOptionsItemSelected(item);
Expand Down Expand Up @@ -371,10 +372,8 @@ public void onChanged(@Nullable List<Category> categories) {
* Sorts filtered notes alphabetical in descending or ascending order.
* @param filter
*/
private void updateListAlphabetical(String filter) {
LiveData<List<Note>> data = alphabeticalAsc ?
mainActivityViewModel.getActiveNotesFiltered(filter)
: mainActivityViewModel.getActiveNotesFilteredAlphabetical(filter);
private void updateList(String filter) {
LiveData<List<Note>> data = mainActivityViewModel.getActiveNotesFiltered(filter);

data.observe(this, notes -> {
adapter.setNotes(notes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONException
import org.secuso.privacyfriendlynotes.model.SortingOrder
import org.secuso.privacyfriendlynotes.room.DbContract
import org.secuso.privacyfriendlynotes.room.NoteDatabase
import org.secuso.privacyfriendlynotes.room.model.Category
Expand All @@ -41,11 +42,15 @@ import java.io.File
class MainActivityViewModel(application: Application) : AndroidViewModel(application) {

private val repository: NoteDatabase = NoteDatabase.getInstance(application)
val activeNotes: LiveData<List<Note>> = repository.noteDao().allActiveNotes
val trashedNotes: LiveData<List<Note>> = repository.noteDao().allTrashedNotes
val allCategoriesLive: LiveData<List<Category>> = repository.categoryDao().allCategoriesLive
val filesDir = application.filesDir
val resources = application.resources
val sortingOrder = SortingOrder(application)

fun setOrder(ordering: SortingOrder.Options) {
this.sortingOrder.ordering = ordering
}

fun insert(note: Note) {
viewModelScope.launch(Dispatchers.Default) {
Expand Down Expand Up @@ -104,20 +109,30 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica
};
}

fun getActiveNotesFiltered(filter: String): LiveData<List<Note?>?> {
var filteredNotes = MutableLiveData<List<Note?>>();
fun getActiveNotes(): LiveData<List<Note?>?> {
val notes = MutableLiveData<List<Note?>>();
viewModelScope.launch(Dispatchers.Main) {
filterNoteFlow(filter, repository.noteDao().activeNotesFiltered(filter)).collect {
filteredNotes.value = it
val flow = when(sortingOrder.ordering) {
SortingOrder.Options.AlphabeticalAscending -> repository.noteDao().allActiveNotesAlphabetical
SortingOrder.Options.TypeAscending -> repository.noteDao().allActiveNotesType
SortingOrder.Options.Creation -> repository.noteDao().allActiveNotesCreation
}
flow.collect {
notes.value = it
}
}
return filteredNotes
return notes
}

fun getActiveNotesFilteredAlphabetical(filter: String): LiveData<List<Note?>?>{
var filteredNotes = MutableLiveData<List<Note?>>();
fun getActiveNotesFiltered(filter: String): LiveData<List<Note?>?> {
val filteredNotes = MutableLiveData<List<Note?>>();
viewModelScope.launch(Dispatchers.Main) {
filterNoteFlow(filter, repository.noteDao().activeNotesFilteredAlphabetical(filter)).collect {
val flow = when(sortingOrder.ordering) {
SortingOrder.Options.AlphabeticalAscending -> repository.noteDao().activeNotesFilteredAlphabetical(filter)
SortingOrder.Options.TypeAscending -> repository.noteDao().activeNotesFilteredType(filter)
SortingOrder.Options.Creation -> repository.noteDao().activeNotesFilteredCreation(filter)
}
filterNoteFlow(filter, flow).collect {
filteredNotes.value = it
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?attr/colorIconFill" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
<path android:fillColor="?attr/colorIconFill" android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
</vector>
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/ic_baseline_edit_note_icon_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?attr/colorIconFill" android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>
</vector>
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/ic_block_icon_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?attr/colorIconFill" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:fillColor="?attr/colorIconFill"
android:pathData="M14.94,4.66h-4.72l2.36,-2.36zM10.25,19.37h4.66l-2.33,2.33zM6.1,6.27L1.6,17.73h1.84l0.92,-2.45h5.11l0.92,2.45h1.84L7.74,6.27L6.1,6.27zM4.97,13.64l1.94,-5.18 1.94,5.18L4.97,13.64zM15.73,16.14h6.12v1.59h-8.53v-1.29l5.92,-8.56h-5.88v-1.6h8.3v1.26l-5.93,8.6z"/>
</vector>
12 changes: 12 additions & 0 deletions app/src/main/res/layout/dialog_sorting_options.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/sorting_options"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>
20 changes: 20 additions & 0 deletions app/src/main/res/layout/dialog_sorting_options_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/alphabetical_ascending"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/sorting_option_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/sorting_option_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginStart="20dp"
android:gravity="center_vertical"/>
</LinearLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,12 @@
<string name="dialog_need_permission_notifications_and_exact_alarm_message">Für diese Funktion ist die Berechtigung zum Senden von Benachrichtigungen und zur Planung von Alarmen und Erinnerungen erforderlich.</string>
<string name="dialog_delete_all_title">Alle Notizen löschen</string>
<string name="dialog_delete_all_message">Wollen Sie alle Notizen entgültig löschen?</string>

<!-- Text for sorting options of notes in main activity -->
<!-- Order has to match the ordering of model/SortingOrder -->
<string-array name="notes_sort_ordering_text">
<item>Alphabetisch</item>
<item>Notizart</item>
<item>Erstellungszeit</item>
</string-array>
</resources>
9 changes: 9 additions & 0 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,13 @@
<item>2</item>
</string-array>

<!-- Text for sorting options of notes in main activity -->
<!-- Order has to match the ordering of model/SortingOrder -->
<integer-array name="notes_sort_ordering_icons">
<item>@drawable/ic_sort_by_alpha_icon_24dp</item>
<item>@drawable/ic_baseline_edit_note_icon_24dp</item>
<item>@drawable/ic_baseline_access_time_icon_24dp</item>
<!-- <item>Alphabetical Descending</item>-->
</integer-array>

</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,12 @@
<item>Dark</item>
</string-array>

<!-- Text for sorting options of notes in main activity -->
<!-- Order has to match the ordering of model/SortingOrder -->
<string-array name="notes_sort_ordering_text">
<item>Alphabetical</item>
<item>Note Type</item>
<item>Creation Time</item>
</string-array>

</resources>

0 comments on commit 4b03d45

Please sign in to comment.