diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/room/dao/NoteDao.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/room/dao/NoteDao.kt index 5874d48f..a2ae3e88 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/room/dao/NoteDao.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/room/dao/NoteDao.kt @@ -55,7 +55,7 @@ interface NoteDao { fun activeNotesFilteredAlphabetical(thisFilterText: String): Flow?> @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?> + fun trashedNotesFiltered(thisFilterText: String): Flow> @Query("SELECT * FROM notes WHERE (category=:thisCategory) AND (in_trash='0') AND ((LOWER(name) LIKE '%'|| LOWER(:thisFilterText) || '%') OR (LOWER(content) LIKE '%'|| LOWER(:thisFilterText) || '%' AND type = 3) OR type = 1) ORDER BY name DESC") fun activeNotesFilteredFromCategory(thisFilterText: String, thisCategory: Integer): Flow?> diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt index c9556ecf..61481c13 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/RecycleActivity.kt @@ -26,6 +26,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.secuso.privacyfriendlynotes.R +import org.secuso.privacyfriendlynotes.room.model.Note import org.secuso.privacyfriendlynotes.ui.adapter.NoteAdapter import org.secuso.privacyfriendlynotes.ui.main.MainActivityViewModel @@ -35,7 +36,7 @@ import org.secuso.privacyfriendlynotes.ui.main.MainActivityViewModel class RecycleActivity : AppCompatActivity() { private val mainActivityViewModel: MainActivityViewModel by lazy { ViewModelProvider(this)[MainActivityViewModel::class.java] } private val searchView: SearchView by lazy { findViewById(R.id.searchViewFilterRecycle) } - private var adapter: NoteAdapter = NoteAdapter() + private var adapter: NoteAdapter = NoteAdapter(mainActivityViewModel) private var filter: MutableLiveData = MutableLiveData("") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -61,10 +62,12 @@ class RecycleActivity : AppCompatActivity() { }) filter.observe(this) { it -> mainActivityViewModel.getTrashedNotesFiltered(it).observe(this) { notes -> - adapter.setNotes(notes) + if (notes != null) { + adapter.setNotes(notes) + } } } - adapter.setOnItemClickListener { note -> + adapter.setOnItemClickListener { note: Note -> AlertDialog.Builder(this@RecycleActivity) .setTitle(String.format(getString(R.string.dialog_restore_title), note.name)) .setMessage(String.format(getString(R.string.dialog_restore_message), note.name)) diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.java b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.java deleted file mode 100644 index 8614c1ea..00000000 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - This file is part of the application Privacy Friendly Notes. - Privacy Friendly Notes is free software: - you can redistribute it and/or modify it under the terms of the - GNU General Public License as published by the Free Software Foundation, - either version 3 of the License, or any later version. - Privacy Friendly Notes is distributed in the hope - that it will be useful, but WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Privacy Friendly Notes. If not, see . - */ -package org.secuso.privacyfriendlynotes.ui.adapter; - -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.Html; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.secuso.privacyfriendlynotes.R; -import org.secuso.privacyfriendlynotes.room.DbContract; -import org.secuso.privacyfriendlynotes.room.model.Note; - -import java.util.ArrayList; -import java.util.List; - -/** - * Adapter that provides a binding for notes - * @see org.secuso.privacyfriendlynotes.ui.main.MainActivity - * @see org.secuso.privacyfriendlynotes.ui.RecycleActivity - */ - -public class NoteAdapter extends RecyclerView.Adapter { - private List notes = new ArrayList<>(); - private List notesFilteredList = new ArrayList<>(); - private OnItemClickListener listener; - - @NonNull - @Override - public NoteHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View itemView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.note_item, parent, false); - return new NoteHolder(itemView); - } - - - /** - * Defines how notes are presented in the RecyclerView. - * @see org.secuso.privacyfriendlynotes.ui.main.MainActivity - * @param holder - * @param position - */ - @Override - public void onBindViewHolder(@NonNull NoteHolder holder, int position) { - Note currentNote = notes.get(position); - holder.textViewTitle.setText(currentNote.getName()); - holder.textViewDescription.setText(""); - - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(holder.itemView.getContext()); - holder.textViewDescription.setVisibility(pref.getBoolean("settings_show_preview", true) ? View.VISIBLE : View.GONE); - - switch (currentNote.getType()) { - case DbContract.NoteEntry.TYPE_TEXT: - holder.imageViewcategory.setImageResource(R.drawable.ic_short_text_icon_24dp); - holder.textViewDescription.setText(Html.fromHtml(currentNote.getContent())); - holder.textViewDescription.setMaxLines(3); - break; - case DbContract.NoteEntry.TYPE_AUDIO: - holder.imageViewcategory.setImageResource(R.drawable.ic_mic_icon_24dp); - break; - case DbContract.NoteEntry.TYPE_SKETCH: - holder.imageViewcategory.setImageResource(R.drawable.ic_photo_icon_24dp); - break; - case DbContract.NoteEntry.TYPE_CHECKLIST: - holder.imageViewcategory.setImageResource(R.drawable.ic_format_list_bulleted_icon_24dp); - String preview = ""; - try { - JSONArray content = new JSONArray(currentNote.getContent()); - for (int i=0; i < content.length(); i++) { - JSONObject o = content.getJSONObject(i); - if(o.getBoolean("checked")){ - preview = preview + "(\u2713)"; - } else { - preview = preview + "(X)"; - } - preview = preview + " " + o.getString("name"); - if(i != content.length()-1){ - preview = preview + "\n"; - } - - } - } catch (Exception e) { - e.printStackTrace(); - } - holder.textViewDescription.setText(preview); - holder.textViewDescription.setMaxLines(3); - } - - // if the Description is empty, don't show it - if (holder.textViewDescription.getText().toString().isEmpty()) { - holder.textViewDescription.setVisibility(View.GONE); - } - } - - @Override - public int getItemCount() { - return notes.size(); - } - - public void setNotes(List notes) { - this.notes = notes; - notifyDataSetChanged(); - } - - class NoteHolder extends RecyclerView.ViewHolder { - private TextView textViewTitle; - private TextView textViewDescription; - private ImageView imageViewcategory; - - - public NoteHolder(@NonNull View itemView) { - super(itemView); - textViewTitle = itemView.findViewById(R.id.text_view_title); - textViewDescription = itemView.findViewById(R.id.text_view_description); - imageViewcategory = itemView.findViewById(R.id.imageView_category); - - itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - int position = getAdapterPosition(); - if (listener != null && position != RecyclerView.NO_POSITION) { - listener.onItemClick(notes.get(position)); - } - } - }); - } - } - - public interface OnItemClickListener { - void onItemClick(Note note); - } - - public void setOnItemClickListener(OnItemClickListener listener) { - this.listener = listener; - } - - public Note getNoteAt(int pos){ - return notes.get(pos); - } -} diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt new file mode 100644 index 00000000..8bd53bf9 --- /dev/null +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt @@ -0,0 +1,128 @@ +/* + This file is part of the application Privacy Friendly Notes. + Privacy Friendly Notes is free software: + you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation, + either version 3 of the License, or any later version. + Privacy Friendly Notes is distributed in the hope + that it will be useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Privacy Friendly Notes. If not, see . + */ +package org.secuso.privacyfriendlynotes.ui.adapter + +import android.opengl.Visibility +import android.preference.PreferenceManager +import android.text.Html +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import org.secuso.privacyfriendlynotes.R +import org.secuso.privacyfriendlynotes.room.DbContract +import org.secuso.privacyfriendlynotes.room.model.Note +import org.secuso.privacyfriendlynotes.ui.main.MainActivityViewModel + +/** + * Adapter that provides a binding for notes + * @see org.secuso.privacyfriendlynotes.ui.main.MainActivity + * + * @see org.secuso.privacyfriendlynotes.ui.RecycleActivity + */ +class NoteAdapter(private val mainActivityViewModel: MainActivityViewModel) : RecyclerView.Adapter() { + private var notes: List = ArrayList() + private val notesFilteredList: List = ArrayList() + private var listener: ((Note) -> Unit)? = null + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder { + val itemView = LayoutInflater.from(parent.context) + .inflate(R.layout.note_item, parent, false) + return NoteHolder(itemView) + } + + /** + * Defines how notes are presented in the RecyclerView. + * @see org.secuso.privacyfriendlynotes.ui.main.MainActivity + * + * @param holder + * @param position + */ + override fun onBindViewHolder(holder: NoteHolder, position: Int) { + val currentNote = notes[position] + holder.textViewTitle.text = currentNote.name + holder.textViewDescription.text = "" + val pref = PreferenceManager.getDefaultSharedPreferences(holder.itemView.context) + holder.textViewDescription.visibility = if (pref.getBoolean("settings_show_preview", true)) View.VISIBLE else View.GONE + when (currentNote.type) { + DbContract.NoteEntry.TYPE_TEXT -> { + holder.textViewDescription.text = Html.fromHtml(currentNote.content) + holder.textViewDescription.maxLines = 3 + } + + DbContract.NoteEntry.TYPE_AUDIO -> { + holder.imageViewcategory.visibility = View.VISIBLE + holder.imageViewcategory.setImageResource(R.drawable.ic_mic_icon_24dp) + } + + DbContract.NoteEntry.TYPE_SKETCH -> { + holder.imageViewcategory.visibility = View.VISIBLE + holder.imageViewcategory.setImageBitmap(mainActivityViewModel.sketchPreview(currentNote, 360)) + } + + DbContract.NoteEntry.TYPE_CHECKLIST -> { + val preview = mainActivityViewModel.checklistPreview(currentNote) + Log.d("Checklist", preview.toString()) + holder.textViewExtraText.text = "${preview.filter { it.first }.count()}/${preview.size}" + holder.textViewExtraText.visibility = View.VISIBLE + holder.textViewDescription.text = preview.take(3).joinToString(System.lineSeparator()) { it.second } + holder.textViewDescription.maxLines = 3 + } + } + + // if the Description is empty, don't show it + if (holder.textViewDescription.text.toString().isEmpty()) { + holder.textViewDescription.visibility = View.GONE + } + } + + override fun getItemCount(): Int { + return notes.size + } + + fun setNotes(notes: List) { + this.notes = notes + notifyDataSetChanged() + } + + inner class NoteHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val textViewTitle: TextView + val textViewDescription: TextView + val imageViewcategory: ImageView + val textViewExtraText: TextView + + init { + textViewTitle = itemView.findViewById(R.id.text_view_title) + textViewDescription = itemView.findViewById(R.id.text_view_description) + imageViewcategory = itemView.findViewById(R.id.imageView_category) + textViewExtraText = itemView.findViewById(R.id.note_text_extra) + itemView.setOnClickListener { + val position = adapterPosition + if (listener != null && position != RecyclerView.NO_POSITION) { + listener!!(notes[position]) + } + } + } + } + + fun setOnItemClickListener(listener: (Note) -> Unit) { + this.listener = listener + } + + fun getNoteAt(pos: Int): Note { + return notes[pos] + } +} \ No newline at end of file diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.java b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.java index c5c733fc..5b458bdf 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivity.java @@ -72,6 +72,8 @@ import java.util.List; +import kotlin.Unit; + /** * The MainActivity includes the functionality of the primary screen. * It provides the possibility to access existing notes and add new ones. @@ -131,15 +133,15 @@ protected void onCreate(Bundle savedInstanceState) { NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); - //Fill from Room database + mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class); + //Fill from Room database RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setHasFixedSize(true); - adapter = new NoteAdapter(); + adapter = new NoteAdapter(mainActivityViewModel); recyclerView.setAdapter(adapter); - mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class); mainActivityViewModel.getActiveNotes().observe(this, new Observer>() { @Override public void onChanged(@Nullable List notes) { @@ -193,7 +195,7 @@ public boolean onQueryTextSubmit(String query) { - /** + /* * Handels when a note is clicked. */ adapter.setOnItemClickListener(note -> { @@ -208,19 +210,12 @@ public boolean onQueryTextSubmit(String query) { return null; }; switch (note.getType()) { - case DbContract.NoteEntry.TYPE_TEXT: - launchActivity.apply(TextNoteActivity.class); - break; - case DbContract.NoteEntry.TYPE_AUDIO: - launchActivity.apply(AudioNoteActivity.class); - break; - case DbContract.NoteEntry.TYPE_SKETCH: - launchActivity.apply(SketchActivity.class); - break; - case DbContract.NoteEntry.TYPE_CHECKLIST: - launchActivity.apply(ChecklistNoteActivity.class); - break; + case DbContract.NoteEntry.TYPE_TEXT -> launchActivity.apply(TextNoteActivity.class); + case DbContract.NoteEntry.TYPE_AUDIO -> launchActivity.apply(AudioNoteActivity.class); + case DbContract.NoteEntry.TYPE_SKETCH -> launchActivity.apply(SketchActivity.class); + case DbContract.NoteEntry.TYPE_CHECKLIST -> launchActivity.apply(ChecklistNoteActivity.class); } + return Unit.INSTANCE; }); PreferenceManager.setDefaultValues(this, R.xml.pref_settings, false); diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt index 9f1ca4ff..47a56d54 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt @@ -14,13 +14,18 @@ package org.secuso.privacyfriendlynotes.ui.main import android.app.Application +import android.graphics.Bitmap +import android.graphics.drawable.BitmapDrawable import android.text.Html +import android.util.Log import androidx.lifecycle.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject import org.secuso.privacyfriendlynotes.room.DbContract import org.secuso.privacyfriendlynotes.room.NoteDatabase import org.secuso.privacyfriendlynotes.room.model.Category @@ -41,6 +46,7 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica val trashedNotes: LiveData> = repository.noteDao().allTrashedNotes val allCategoriesLive: LiveData> = repository.categoryDao().allCategoriesLive val filesDir = application.filesDir + val resources = application.resources fun insert(note: Note) { viewModelScope.launch(Dispatchers.Default) { @@ -119,11 +125,11 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica return filteredNotes } - fun getTrashedNotesFiltered(filter: String): LiveData?>{ - var filteredNotes = MutableLiveData>(); + fun getTrashedNotesFiltered(filter: String): LiveData?>{ + var filteredNotes = MutableLiveData>(); viewModelScope.launch(Dispatchers.Main) { filterNoteFlow(filter, repository.noteDao().trashedNotesFiltered(filter)).collect { - filteredNotes.value = it + filteredNotes.value = it.filterNotNull() } } return filteredNotes @@ -157,4 +163,28 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica } } + fun sketchPreview(note: Note, size: Int): Bitmap { + if (note.type == DbContract.NoteEntry.TYPE_SKETCH) { + var bitmap = BitmapDrawable( resources, filesDir.path + "/sketches" + note.content) + return Bitmap.createScaledBitmap(bitmap.bitmap, size, size, false) + } else { + throw IllegalArgumentException("Only sketch notes allowed") + } + } + + fun checklistPreview(note: Note): List> { + if (note.type != DbContract.NoteEntry.TYPE_CHECKLIST) { + throw IllegalArgumentException("Only checklist notes allowed") + } + try { + val content = JSONArray(note.content) + return (0 until content.length()).map { + val obj = content.getJSONObject(it) + return@map Pair(obj.getBoolean("checked"), String.format("[%s] ${obj.getString("name")}", if (obj.getBoolean("checked")) "x" else " ")) + }.toList() + } catch (ex: JSONException) { + return ArrayList() + } + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/note_item.xml b/app/src/main/res/layout/note_item.xml index d0f1277d..23116bea 100644 --- a/app/src/main/res/layout/note_item.xml +++ b/app/src/main/res/layout/note_item.xml @@ -10,20 +10,13 @@ > - - - @@ -45,6 +38,24 @@ android:text="Description" /> + + + + + +