Skip to content

Commit

Permalink
Enable Reading Mode in folders' archives #197
Browse files Browse the repository at this point in the history
  • Loading branch information
alialbaali committed Jun 26, 2023
1 parent 488b9b0 commit 764f662
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 67 deletions.
30 changes: 25 additions & 5 deletions app/src/main/java/com/noto/app/filtered/FilteredFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,14 @@ class FilteredFragment : Fragment() {

activity?.onBackPressedDispatcher?.addCallback {
when {
viewModel.isSelection.value -> if (viewModel.isSearchEnabled.value) {
viewModel.disableSearch()
} else {
viewModel.disableSelection()
viewModel.deselectAllNotes()
}

viewModel.isSearchEnabled.value -> viewModel.disableSearch()
viewModel.selectedNotesGroupedByFolder.isNotEmpty() -> viewModel.deselectAllNotes()
viewModel.quickExit.value -> activity?.finish()
else -> navController?.navigateSafely(FilteredFragmentDirections.actionFilteredFragmentToMainFragment(exit = true))
}
Expand Down Expand Up @@ -196,7 +202,8 @@ class FilteredFragment : Fragment() {
viewModel.notesGroupedByFolderVisibility,
viewModel.font,
viewModel.searchTerm,
) { notes, notesVisibility, font, searchTerm ->
viewModel.isSelection,
) { notes, notesVisibility, font, searchTerm, isSelection ->
val isEmpty = notes.getOrDefault(emptyMap()).isEmpty()
val isEmptySelection = notes.getOrDefault(emptyMap()).flatMap { it.value }.none { it.isSelected }
bab.menu?.forEach { menuItem ->
Expand All @@ -207,7 +214,7 @@ class FilteredFragment : Fragment() {
menuItem.icon?.alpha = if (isEmptySelection) DisabledAlpha else EnabledAlpha
}
}
setupNotesGroupedByFolder(notes, notesVisibility, font, searchTerm)
setupNotesGroupedByFolder(notes, notesVisibility, font, searchTerm, isSelection)
}.launchIn(lifecycleScope)
}

Expand Down Expand Up @@ -422,6 +429,7 @@ class FilteredFragment : Fragment() {
notesVisibility: Map<Folder, Boolean>,
font: Font,
searchTerm: String,
isSelection: Boolean,
) {
val isArchivedModel = args.model == FilteredItemModel.Archived

Expand Down Expand Up @@ -484,10 +492,21 @@ class FilteredFragment : Fragment() {
previewSize(folder.notePreviewSize)
isShowCreationDate(folder.isShowNoteCreationDate)
isManualSorting(false)
isSelection(isArchivedModel)
isSelection(isArchivedModel && isSelection)
onClickListener { _ ->
if (isArchivedModel) {
if (model.isSelected) viewModel.deselectNote(model.note.id) else viewModel.selectNote(model.note.id)
if (isSelection) {
if (model.isSelected) viewModel.deselectNote(model.note.id) else viewModel.selectNote(model.note.id)
} else {
navController?.navigateSafely(
FilteredFragmentDirections.actionFilteredFragmentToNotePagerFragment(
model.note.folderId,
model.note.id,
notes.map { it.note.id }.toLongArray(),
isArchive = true,
)
)
}
} else {
navController
?.navigateSafely(
Expand All @@ -502,6 +521,7 @@ class FilteredFragment : Fragment() {
}
onLongClickListener { _ ->
if (isArchivedModel) {
viewModel.enableSelection()
if (model.isSelected) viewModel.deselectNote(model.note.id) else viewModel.selectNote(model.note.id)
} else {
navController
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/java/com/noto/app/filtered/FilteredViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class FilteredViewModel(
val quickExit = settingsRepository.quickExit
.stateIn(viewModelScope, SharingStarted.Eagerly, false)

private val mutableIsSelection = MutableStateFlow(false)
val isSelection get() = mutableIsSelection.asStateFlow()

val selectedNotesGroupedByFolder
get() = notesGroupedByFolder.value
.getOrDefault(emptyMap())
Expand Down Expand Up @@ -92,6 +95,7 @@ class FilteredViewModel(
.toMap()
.let { UiState.Success(it) }
}

FilteredItemModel.Recent -> {
mutableNotesGroupedByDateVisibility.value = notes
.map { it.accessDate.toLocalDate() }
Expand All @@ -107,6 +111,7 @@ class FilteredViewModel(
.toSortedMap(compareByDescending { it })
.let { UiState.Success(it) }
}

FilteredItemModel.Scheduled -> {
mutableNotesGroupedByDateVisibility.value = notes
.mapNotNull { it.reminderDate?.toLocalDate() }
Expand All @@ -122,6 +127,7 @@ class FilteredViewModel(
.toSortedMap(compareByDescending { it })
.let { UiState.Success(it) }
}

FilteredItemModel.Archived -> {
mutableNotesGroupedByFolderVisibility.value = folders.associateWith { notesGroupedByFolderVisibility.value[it] ?: true }
mutableNotesGroupedByFolder.value = notes
Expand All @@ -144,6 +150,16 @@ class FilteredViewModel(
}
}
}.launchIn(viewModelScope)

notesGroupedByFolder
.onEach { notesState ->
val isNoneSelected = notesState.getOrDefault(emptyMap()).none { it.value.none { it.isSelected } }
if (isNoneSelected) {
disableSelection()
deselectAllNotes()
}
}
.launchIn(viewModelScope)
}

fun toggleVisibilityForFolder(folderId: Long) {
Expand Down Expand Up @@ -183,6 +199,7 @@ class FilteredViewModel(
FilteredItemModel.All, FilteredItemModel.Archived -> {
mutableNotesGroupedByFolderVisibility.value = notesGroupedByFolderVisibility.value.mapValues { true }
}

FilteredItemModel.Recent, FilteredItemModel.Scheduled -> {
mutableNotesGroupedByDateVisibility.value = notesGroupedByDateVisibility.value.mapValues { true }
}
Expand All @@ -194,6 +211,7 @@ class FilteredViewModel(
FilteredItemModel.All, FilteredItemModel.Archived -> {
mutableNotesGroupedByFolderVisibility.value = notesGroupedByFolderVisibility.value.mapValues { false }
}

FilteredItemModel.Recent, FilteredItemModel.Scheduled -> {
mutableNotesGroupedByDateVisibility.value = notesGroupedByDateVisibility.value.mapValues { false }
}
Expand Down Expand Up @@ -256,4 +274,13 @@ class FilteredViewModel(
}
}
}

fun enableSelection() {
mutableIsSelection.value = true
}

fun disableSelection() {
mutableIsSelection.value = false
}

}
36 changes: 28 additions & 8 deletions app/src/main/java/com/noto/app/folder/FolderArchiveFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class FolderArchiveFragment : Fragment() {
viewModel.archivedNotes,
viewModel.font,
viewModel.folder,
) { archivedNotes, font, folder ->
viewModel.isSelection,
) { archivedNotes, font, folder, isSelection ->
val notesCount = archivedNotes.getOrDefault(emptyList()).count()
val selectedNotesCount = archivedNotes.getOrDefault(emptyList()).count { it.isSelected }
if (selectedNotesCount != 0) {
Expand All @@ -77,7 +78,7 @@ class FolderArchiveFragment : Fragment() {
fabDelete.disable()
}

setupArchivedNotes(archivedNotes, font, folder)
setupArchivedNotes(archivedNotes, font, folder, isSelection)
}.launchIn(lifecycleScope)

if (isCurrentLocaleArabic()) {
Expand Down Expand Up @@ -112,6 +113,8 @@ class FolderArchiveFragment : Fragment() {
val text = context.quantityStringResource(R.plurals.note_is_unarchived, selectedNotes.count(), selectedNotes.count())
val drawableId = R.drawable.ic_round_unarchive_24
root.snackbar(text, drawableId, anchorViewId, folderColor)
context.updateAllWidgetsData()
context.updateNoteListWidgets()
}
}

Expand Down Expand Up @@ -163,7 +166,12 @@ class FolderArchiveFragment : Fragment() {
}

@SuppressLint("ClickableViewAccessibility")
private fun FolderArchiveFragmentBinding.setupArchivedNotes(state: UiState<List<NoteItemModel>>, font: Font, folder: Folder) {
private fun FolderArchiveFragmentBinding.setupArchivedNotes(
state: UiState<List<NoteItemModel>>,
font: Font,
folder: Folder,
isSelection: Boolean,
) {
if (state is UiState.Success) {
val archivedNotes = state.value
rv.withModels {
Expand Down Expand Up @@ -195,17 +203,29 @@ class FolderArchiveFragment : Fragment() {
font(font)
searchTerm("")
previewSize(folder.notePreviewSize)
isSelection(true)
isSelection(isSelection)
isShowCreationDate(folder.isShowNoteCreationDate)
color(folder.color)
isManualSorting(false)
onClickListener { _ ->
if (archivedNoteModel.isSelected)
viewModel.deselectArchivedNote(archivedNoteModel.note.id)
else
viewModel.selectArchivedNote(archivedNoteModel.note.id)
if (isSelection) {
if (archivedNoteModel.isSelected)
viewModel.deselectArchivedNote(archivedNoteModel.note.id)
else
viewModel.selectArchivedNote(archivedNoteModel.note.id)
} else {
navController?.navigateSafely(
FolderArchiveFragmentDirections.actionFolderArchiveFragmentToNotePagerFragment(
args.folderId,
archivedNoteModel.note.id,
archivedNotes.map { it.note.id }.toLongArray(),
isArchive = true,
)
)
}
}
onLongClickListener { _ ->
viewModel.enableSelection()
if (archivedNoteModel.isSelected)
viewModel.deselectArchivedNote(archivedNoteModel.note.id)
else
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/com/noto/app/folder/FolderViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,16 @@ class FolderViewModel(
}
.launchIn(viewModelScope)

archivedNotes
.onEach { notesState ->
val isNoneSelected = notesState.getOrDefault(emptyList()).none { it.isSelected }
if (isNoneSelected) {
disableSelection()
deselectAllArchivedNotes()
}
}
.launchIn(viewModelScope)

notes.combine(previewAutoScroll) { state, isEnabled ->
if (isEnabled) {
val models = state.getOrDefault(emptyList()).filter { it.isSelected }
Expand Down
72 changes: 62 additions & 10 deletions app/src/main/java/com/noto/app/note/NotePagerFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ import org.koin.core.parameter.parametersOf

class NotePagerFragment : Fragment() {

private val viewModel by viewModel<NotePagerViewModel> { parametersOf(args.folderId, args.noteId, args.selectedNoteIds) }
private val viewModel by viewModel<NotePagerViewModel> { parametersOf(args.folderId, args.noteId, args.selectedNoteIds, args.isArchive) }

private val args by navArgs<NotePagerFragmentArgs>()

private val anchorViewId by lazy { R.id.bab }

private val folderColor by lazy { viewModel.folder.value.color }

private val windowInsetsController by lazy {
val window = activity?.window
val view = window?.decorView
Expand Down Expand Up @@ -62,12 +66,17 @@ class NotePagerFragment : Fragment() {

private fun NotePagerFragmentBinding.setupState() {
abl.bringToFront()
fab.isVisible = !args.isArchive
fabPrevious.isVisible = !args.isArchive
fabNext.isVisible = !args.isArchive
fabUnarchive.isVisible = args.isArchive
fabDelete.isVisible = args.isArchive

viewModel.folder
.onEach { folder ->
context?.let { context ->
val color = context.colorResource(folder.color.toResource())
tvFolderTitle.text = folder.getTitle(context)
tvFolderTitle.text = context.stringResource(R.string.folder_archive, folder.getTitle(context))
tvFolderTitle.setTextColor(color)
tb.navigationIcon?.mutate()?.setTint(color)
fab.backgroundTintList = color.toColorStateList()
Expand All @@ -85,7 +94,8 @@ class NotePagerFragment : Fragment() {
}
.launchIn(lifecycleScope)

combine(viewModel.noteIds, viewModel.selectedId) { noteIds, selectedId ->
combine(viewModel.noteIds, viewModel.selectedNoteId) { noteIds, selectedId ->
if (selectedId == null) navController?.navigateUp()
if (vp.adapter == null && noteIds.isNotEmpty()) {
adapter = object : FragmentStateAdapter(this@NotePagerFragment) {
override fun getItemCount(): Int = noteIds.count()
Expand Down Expand Up @@ -187,7 +197,7 @@ class NotePagerFragment : Fragment() {
vp.registerOnPageChangeCallback(
object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
viewModel.selectIdByIndex(position)
viewModel.selectNoteIdByIndex(position)
bab.performShow(true)
}
}
Expand All @@ -201,7 +211,7 @@ class NotePagerFragment : Fragment() {
navController?.navigateSafely(
NotePagerFragmentDirections.actionNotePagerFragmentToNoteFragment(
folderId = args.folderId,
noteId = viewModel.selectedId.value,
noteId = viewModel.selectedNoteId.value ?: return@setOnClickListener,
scrollPosition = scrollPosition,
isTitleVisible = isTitleVisible,
isBodyVisible = isBodyVisible,
Expand All @@ -211,25 +221,67 @@ class NotePagerFragment : Fragment() {
}

fabPrevious.setOnClickListener {
viewModel.selectPreviousId()
viewModel.selectPreviousNoteId()
}

fabNext.setOnClickListener {
viewModel.selectNextId()

viewModel.selectNextNoteId()
}

fabPrevious.setOnLongClickListener {
adapter?.createFragment(0)
viewModel.selectFirstId()
viewModel.selectFirstNoteId()
true
}

fabNext.setOnLongClickListener {
adapter?.createFragment(viewModel.noteIds.value.lastIndex)
viewModel.selectLastId()
viewModel.selectLastNoteId()
true
}

fabUnarchive.setOnClickListener {
context?.let { context ->
viewModel.unarchiveSelectedArchivedNote().invokeOnCompletion {
vp.adapter = null
val text = context.quantityStringResource(R.plurals.note_is_unarchived, 1)
val drawableId = R.drawable.ic_round_unarchive_24
root.snackbar(text, drawableId, anchorViewId, folderColor)
context.updateAllWidgetsData()
context.updateNoteListWidgets()
}
}
}

fabDelete.setOnClickListener {
context?.let { context ->
val confirmationText = context.quantityStringResource(R.plurals.delete_note_confirmation, 1)
val descriptionText = context.quantityStringResource(R.plurals.delete_note_description, 1)
val btnText = context.quantityStringResource(R.plurals.delete_note, 1)
val liveData = navController?.currentBackStackEntry?.savedStateHandle?.getLiveData<Int>(Constants.ClickListener)
liveData?.observe(viewLifecycleOwner) {
if (it != null) {
liveData.value = null
viewModel.deleteSelectedArchivedNote().invokeOnCompletion {
vp.adapter = null
val text = context.quantityStringResource(R.plurals.note_is_deleted, 1)
val drawableId = R.drawable.ic_round_delete_24
root.snackbar(text, drawableId, anchorViewId, folderColor)
context.updateAllWidgetsData()
context.updateNoteListWidgets()
}
}
}

navController?.navigateSafely(
NotePagerFragmentDirections.actionNotePagerFragmentToConfirmationDialogFragment(
confirmationText,
descriptionText,
btnText,
)
)
}
}
}

override fun onDetach() {
Expand Down

0 comments on commit 764f662

Please sign in to comment.