Removed the unnecessary creation of ZimFileReader when opening notes on the Notes screen.

* Refactored `AddNoteDialog` to use database values for performing note-related operations (e.g., view, edit, delete notes) instead of setting and using `ZimFileReader`.
This commit is contained in:
MohitMaliFtechiz 2025-01-21 15:55:18 +05:30 committed by Kelson
parent 86ddd87076
commit 6387c5ceae
6 changed files with 80 additions and 94 deletions

View File

@ -25,7 +25,6 @@ import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import org.kiwix.kiwixmobile.core.utils.files.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -49,10 +48,12 @@ import org.kiwix.kiwixmobile.core.extensions.snack
import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.SimpleTextWatcher import org.kiwix.kiwixmobile.core.utils.SimpleTextWatcher
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
import org.kiwix.kiwixmobile.core.utils.files.Log
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
@ -110,6 +111,10 @@ class AddNoteDialog : DialogFragment() {
private val deleteItem by lazy { toolbar?.menu?.findItem(R.id.delete_note) } private val deleteItem by lazy { toolbar?.menu?.findItem(R.id.delete_note) }
private var noteListItem: NoteListItem? = null
private var zimReaderSource: ZimReaderSource? = null
private var favicon: String? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
coreComponent coreComponent
@ -118,35 +123,45 @@ class AddNoteDialog : DialogFragment() {
.build() .build()
.inject(this) .inject(this)
// Returns name of the form ".../Kiwix/granbluefantasy_en_all_all_nopic_2018-10.zim" if (arguments != null) {
zimFileName = zimReaderContainer.zimReaderSource?.toDatabase() ?: zimReaderContainer.name // For opening the note dialog from note screen.
if (zimFileName != null) { // No zim file currently opened noteListItem = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arguments?.getSerializable(NOTE_LIST_ITEM_TAG, NoteListItem::class.java)
} else {
@Suppress("DEPRECATION")
arguments?.getSerializable(NOTE_LIST_ITEM_TAG) as NoteListItem
}
zimFileName = noteListItem?.zimReaderSource?.toDatabase()
zimFileTitle = noteListItem?.title
zimId = noteListItem?.zimId.orEmpty()
zimReaderSource = noteListItem?.zimReaderSource
favicon = noteListItem?.favicon
articleNoteFileName = getArticleNoteFileName()
zimNotesDirectory = noteListItem?.noteFilePath
?.substringBefore(articleNoteFileName)
getArticleTitleAndZimFileUrlFromArguments()
} else {
// Note is opened from the reader screen.
// Returns name of the form ".../Kiwix/granbluefantasy_en_all_all_nopic_2018-10.zim"
zimFileName = zimReaderContainer.zimReaderSource?.toDatabase() ?: zimReaderContainer.name
zimFileTitle = zimReaderContainer.zimFileTitle zimFileTitle = zimReaderContainer.zimFileTitle
zimId = zimReaderContainer.id.orEmpty() zimId = zimReaderContainer.id.orEmpty()
zimReaderSource = zimReaderContainer.zimReaderSource
if (arguments != null) { favicon = zimReaderContainer.favicon
getArticleTitleAndZimFileUrlFromArguments() val webView = (activity as WebViewProvider?)?.getCurrentWebView()
} else { articleTitle = webView?.title
val webView = (activity as WebViewProvider?)?.getCurrentWebView() zimFileUrl = webView?.url.orEmpty()
articleTitle = webView?.title
zimFileUrl = webView?.url.orEmpty()
}
// Corresponds to "ZimFileName" of "{External Storage}/Kiwix/Notes/ZimFileName/ArticleUrl.txt" // Corresponds to "ZimFileName" of "{External Storage}/Kiwix/Notes/ZimFileName/ArticleUrl.txt"
articleNoteFileName = getArticleNoteFileName() articleNoteFileName = getArticleNoteFileName()
zimNotesDirectory = "$NOTES_DIRECTORY$zimNoteDirectoryName/" zimNotesDirectory = "$NOTES_DIRECTORY$zimNoteDirectoryName/"
} else {
articleNoteFileName = getArticleNoteFileName()
zimNotesDirectory = arguments?.getString(NOTE_FILE_PATH)
?.substringBefore(articleNoteFileName)
getArticleTitleAndZimFileUrlFromArguments()
context.toast(R.string.error_file_not_found, Toast.LENGTH_LONG)
} }
} }
private fun getArticleTitleAndZimFileUrlFromArguments() { private fun getArticleTitleAndZimFileUrlFromArguments() {
articleTitle = arguments?.getString(NOTES_TITLE)?.substringAfter(": ") articleTitle = noteListItem?.title?.substringAfter(": ")
zimFileUrl = arguments?.getString(ARTICLE_URL).orEmpty() zimFileUrl = noteListItem?.zimUrl.orEmpty()
} }
private fun isZimFileExist() = zimFileName != null private fun isZimFileExist() = zimFileName != null
@ -174,7 +189,7 @@ class AddNoteDialog : DialogFragment() {
private fun getArticleNoteFileName(): String { private fun getArticleNoteFileName(): String {
// Returns url of the form: "content://org.kiwix.kiwixmobile.zim.base/A/Main_Page.html" // Returns url of the form: "content://org.kiwix.kiwixmobile.zim.base/A/Main_Page.html"
arguments?.getString(NOTE_FILE_PATH)?.let { noteListItem?.noteFilePath?.let {
return@getArticleNoteFileName getTextAfterLastSlashWithoutExtension(it) return@getArticleNoteFileName getTextAfterLastSlashWithoutExtension(it)
} }
@ -365,7 +380,7 @@ class AddNoteDialog : DialogFragment() {
noteEdited = false // As no unsaved changes remain noteEdited = false // As no unsaved changes remain
enableDeleteNoteMenuItem() enableDeleteNoteMenuItem()
// adding only if saving file is success // adding only if saving file is success
addNoteToDao(noteFile.canonicalPath, "${zimFileTitle.orEmpty()}: $articleTitle") addNoteToDao(noteFile.canonicalPath, getNoteTitle())
disableSaveNoteMenuItem() disableSaveNoteMenuItem()
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
@ -380,20 +395,34 @@ class AddNoteDialog : DialogFragment() {
} }
} }
/**
* This method determines the note title to be saved in the database.
* - If the note is opened from the Reader screen, it combines the `zimFileTitle`
* and `articleTitle`, as it previously did.
* - If `noteListItem` is not null, it means the note is opened from the Notes screen,
* as this item is passed in the bundle from the Notes screen. In this case, it
* returns `zimFileTitle`, which represents the current note's title.
*/
private fun getNoteTitle(): String =
noteListItem?.let {
zimFileTitle
} ?: run {
"${zimFileTitle.orEmpty()}: $articleTitle"
}
private fun addNoteToDao(noteFilePath: String?, title: String) { private fun addNoteToDao(noteFilePath: String?, title: String) {
noteFilePath?.let { filePath -> noteFilePath?.let { filePath ->
if (filePath.isNotEmpty() && zimFileUrl.isNotEmpty()) { if (filePath.isNotEmpty() && zimFileUrl.isNotEmpty()) {
val zimReader = zimReaderContainer.zimFileReader val noteToSave = NoteListItem(
if (zimReader != null) { zimId = zimId,
val noteToSave = NoteListItem( title = title,
title = title, url = zimFileUrl,
url = zimFileUrl, noteFilePath = noteFilePath,
noteFilePath = noteFilePath, zimReaderSource = zimReaderSource,
zimFileReader = zimReader favicon = favicon,
) )
mainRepositoryActions.saveNote(noteToSave) mainRepositoryActions.saveNote(noteToSave).also {
} else { Log.e(TAG, "addNoteToDao: $noteToSave")
Log.d(TAG, "zim reader found null")
} }
} else { } else {
Log.d(TAG, "Cannot process with empty zim url or noteFilePath") Log.d(TAG, "Cannot process with empty zim url or noteFilePath")
@ -514,8 +543,6 @@ class AddNoteDialog : DialogFragment() {
@JvmField val NOTES_DIRECTORY = @JvmField val NOTES_DIRECTORY =
instance.getExternalFilesDir("").toString() + "/Kiwix/Notes/" instance.getExternalFilesDir("").toString() + "/Kiwix/Notes/"
const val TAG = "AddNoteDialog" const val TAG = "AddNoteDialog"
const val NOTE_FILE_PATH = "NoteFilePath" const val NOTE_LIST_ITEM_TAG = "NoteListItemTag"
const val ARTICLE_URL = "ArticleUrl"
const val NOTES_TITLE = "NotesTitle"
} }
} }

View File

@ -3,8 +3,8 @@ package org.kiwix.kiwixmobile.core.page.notes.adapter
import org.kiwix.kiwixmobile.core.dao.entities.NotesEntity import org.kiwix.kiwixmobile.core.dao.entities.NotesEntity
import org.kiwix.kiwixmobile.core.dao.entities.NotesRoomEntity import org.kiwix.kiwixmobile.core.dao.entities.NotesRoomEntity
import org.kiwix.kiwixmobile.core.page.adapter.Page import org.kiwix.kiwixmobile.core.page.adapter.Page
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import java.io.Serializable
data class NoteListItem( data class NoteListItem(
val databaseId: Long = 0L, val databaseId: Long = 0L,
@ -17,7 +17,7 @@ data class NoteListItem(
override var isSelected: Boolean = false, override var isSelected: Boolean = false,
override val url: String = zimUrl, override val url: String = zimUrl,
override val id: Long = databaseId override val id: Long = databaseId
) : Page { ) : Page, Serializable {
constructor(notesEntity: NotesEntity) : this( constructor(notesEntity: NotesEntity) : this(
notesEntity.id, notesEntity.id,
@ -30,16 +30,18 @@ data class NoteListItem(
) )
constructor( constructor(
zimId: String,
title: String, title: String,
zimReaderSource: ZimReaderSource?,
url: String, url: String,
noteFilePath: String, favicon: String?,
zimFileReader: ZimFileReader noteFilePath: String
) : this( ) : this(
zimId = zimFileReader.id, zimId = zimId,
title = title, title = title,
zimReaderSource = zimFileReader.zimReaderSource, zimReaderSource = zimReaderSource,
zimUrl = url, zimUrl = url,
favicon = zimFileReader.favicon, favicon = favicon,
noteFilePath = noteFilePath noteFilePath = noteFilePath
) )

View File

@ -29,7 +29,6 @@ import org.kiwix.kiwixmobile.core.page.viewmodel.effects.DeletePageItems
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.DeleteAllNotes import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.DeleteAllNotes
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.DeleteSelectedNotes import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.DeleteSelectedNotes
import org.kiwix.kiwixmobile.core.utils.files.Log
import javax.inject.Inject import javax.inject.Inject
data class ShowDeleteNotesDialog( data class ShowDeleteNotesDialog(
@ -41,7 +40,6 @@ data class ShowDeleteNotesDialog(
@Inject lateinit var dialogShower: DialogShower @Inject lateinit var dialogShower: DialogShower
override fun invokeWith(activity: AppCompatActivity) { override fun invokeWith(activity: AppCompatActivity) {
activity.cachedComponent.inject(this) activity.cachedComponent.inject(this)
Log.d("invoke", "invokeWith: invoked")
dialogShower.show( dialogShower.show(
if (state.isInSelectionState) DeleteSelectedNotes else DeleteAllNotes, if (state.isInSelectionState) DeleteSelectedNotes else DeleteAllNotes,
{ {

View File

@ -20,21 +20,13 @@ package org.kiwix.kiwixmobile.core.page.notes.viewmodel.effects
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import io.reactivex.processors.PublishProcessor import io.reactivex.processors.PublishProcessor
import org.json.JSONArray
import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
import org.kiwix.kiwixmobile.core.page.adapter.Page import org.kiwix.kiwixmobile.core.page.adapter.Page
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenNote import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenNote
import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenPage import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenPage
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_ARTICLES
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_POSITIONS
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_TAB
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.ShowNoteDialog import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.ShowNoteDialog
import javax.inject.Inject import javax.inject.Inject
@ -52,35 +44,7 @@ data class ShowOpenNoteDialog(
{ effects.offer(OpenPage(page, zimReaderContainer)) }, { effects.offer(OpenPage(page, zimReaderContainer)) },
{ {
val item = page as NoteListItem val item = page as NoteListItem
// Check if toDatabase is not null, and then set it in zimReaderContainer. effects.offer(OpenNote(item))
// For custom apps, we are currently using fileDescriptor, and they only have a single file in them,
// which is already set in zimReaderContainer, so there's no need to set it again.
item.zimReaderSource?.toDatabase().let {
val currentZimReaderSource = zimReaderContainer.zimReaderSource
if (!activity.isCustomApp()) {
zimReaderContainer.setZimReaderSource(item.zimReaderSource)
}
if (zimReaderContainer.zimReaderSource != currentZimReaderSource) {
// if current zim file is not the same set the main page of that zim file
// so that when we go back it properly loads the article, and do nothing if the
// zim file is same because there might be multiple tabs opened.
val settings = activity.getSharedPreferences(
SharedPreferenceUtil.PREF_KIWIX_MOBILE,
0
)
val editor = settings.edit()
val urls = JSONArray()
val positions = JSONArray()
urls.put(CONTENT_PREFIX + zimReaderContainer.mainPage)
positions.put(0)
editor.putString(TAG_CURRENT_FILE, zimReaderContainer.zimReaderSource?.toDatabase())
editor.putString(TAG_CURRENT_ARTICLES, "$urls")
editor.putString(TAG_CURRENT_POSITIONS, "$positions")
editor.putInt(TAG_CURRENT_TAB, 0)
editor.apply()
}
}
effects.offer(OpenNote(item.noteFilePath, item.zimUrl, item.title))
} }
) )
} }

View File

@ -110,12 +110,12 @@ abstract class PageViewModel<T : Page, S : PageState<T>>(
abstract fun copyWithNewItems(state: S, newItems: List<T>): S abstract fun copyWithNewItems(state: S, newItems: List<T>): S
private fun handleItemClick(state: S, action: Action.OnItemClick): S { private fun handleItemClick(state: S, action: Action.OnItemClick): S {
if (state.isInSelectionState) {
return copyWithNewItems(state, state.getItemsAfterToggleSelectionOfItem(action.page))
}
if (::pageViewModelClickListener.isInitialized) { if (::pageViewModelClickListener.isInitialized) {
effects.offer(pageViewModelClickListener.onItemClick(action.page)) effects.offer(pageViewModelClickListener.onItemClick(action.page))
} else { } else {
if (state.isInSelectionState) {
return copyWithNewItems(state, state.getItemsAfterToggleSelectionOfItem(action.page))
}
effects.offer(OpenPage(action.page, zimReaderContainer)) effects.offer(OpenPage(action.page, zimReaderContainer))
} }
return state return state

View File

@ -24,15 +24,12 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.main.AddNoteDialog import org.kiwix.kiwixmobile.core.main.AddNoteDialog
import org.kiwix.kiwixmobile.core.main.AddNoteDialog.Companion.ARTICLE_URL import org.kiwix.kiwixmobile.core.main.AddNoteDialog.Companion.NOTE_LIST_ITEM_TAG
import org.kiwix.kiwixmobile.core.main.AddNoteDialog.Companion.NOTES_TITLE
import org.kiwix.kiwixmobile.core.main.AddNoteDialog.Companion.NOTE_FILE_PATH
import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
class OpenNote( class OpenNote(
private val noteFilePath: String, private val noteListItem: NoteListItem
private val zimFileUrl: String,
private val title: String,
) : SideEffect<Unit> { ) : SideEffect<Unit> {
override fun invokeWith(activity: AppCompatActivity) { override fun invokeWith(activity: AppCompatActivity) {
activity as CoreMainActivity activity as CoreMainActivity
@ -49,9 +46,7 @@ class OpenNote(
if (previousInstance == null) { if (previousInstance == null) {
val dialogFragment = AddNoteDialog() val dialogFragment = AddNoteDialog()
val bundle = Bundle().apply { val bundle = Bundle().apply {
putString(NOTE_FILE_PATH, noteFilePath) putSerializable(NOTE_LIST_ITEM_TAG, noteListItem)
putString(ARTICLE_URL, zimFileUrl)
putString(NOTES_TITLE, title)
} }
dialogFragment.arguments = bundle dialogFragment.arguments = bundle
dialogFragment.show(fragmentTransaction, AddNoteDialog.TAG) dialogFragment.show(fragmentTransaction, AddNoteDialog.TAG)