Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[enhancement] Save storage folder choice if notes are loaded successfully #85

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions app/src/main/java/dev/arkbuilders/arkmemo/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import dev.arkbuilders.arklib.user.properties.PropertiesStorageRepo
import dev.arkbuilders.arkmemo.models.GraphicNote
import dev.arkbuilders.arkmemo.models.TextNote
import dev.arkbuilders.arkmemo.models.VoiceNote
import dev.arkbuilders.arkmemo.preferences.MemoPreferences
import dev.arkbuilders.arkmemo.repo.NotesRepo
import dev.arkbuilders.arkmemo.repo.NotesRepoHelper
import dev.arkbuilders.arkmemo.repo.graphics.GraphicNotesRepo
import dev.arkbuilders.arkmemo.repo.text.TextNotesRepo
import dev.arkbuilders.arkmemo.repo.voices.VoiceNotesRepo
import kotlinx.coroutines.CoroutineDispatcher
import javax.inject.Named
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
Expand All @@ -27,12 +29,15 @@ abstract class RepositoryModule {

@Binds
abstract fun bindVoiceNotesRepo(impl: VoiceNotesRepo): NotesRepo<VoiceNote>
}

companion object {
@Provides
fun provideNotesRepoHelper(
memoPreferences: MemoPreferences,
propertiesStorageRepo: PropertiesStorageRepo,
) = NotesRepoHelper(memoPreferences, propertiesStorageRepo)
}
@InstallIn(SingletonComponent::class)
@Module
object RepoHelperModule {
@Singleton
@Provides
fun provideNotesRepoHelper(
propertiesStorageRepo: PropertiesStorageRepo,
@Named(IO_DISPATCHER) coroutineDispatcher: CoroutineDispatcher,
) = NotesRepoHelper(propertiesStorageRepo, coroutineDispatcher)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ interface MemoPreferences {
fun getCrashReportEnabled(): Boolean

fun storageNotAvailable(): Boolean

fun isLastLaunchSuccess(): Boolean

fun setLastLaunchSuccess(success: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import kotlin.io.path.exists

private const val NAME = "memo_prefs"
private const val CURRENT_NOTES_PATH = "current_notes_path"
private const val PREF_LAST_LAUNCH_SUCCESS = "pref_last_launch_success"

class MemoPreferencesImpl
@Inject
Expand Down Expand Up @@ -38,4 +39,12 @@ class MemoPreferencesImpl
override fun storageNotAvailable(): Boolean {
return getPath().isEmpty() || !getNotesStorage().exists()
}

override fun isLastLaunchSuccess(): Boolean {
return sharedPreferences.getBoolean(PREF_LAST_LAUNCH_SUCCESS, true)
}

override fun setLastLaunchSuccess(success: Boolean) {
prefEditor.putBoolean(PREF_LAST_LAUNCH_SUCCESS, success).apply()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dev.arkbuilders.arkmemo.repo
import dev.arkbuilders.arkmemo.models.SaveNoteResult

interface NotesRepo<Note> {
suspend fun init()
suspend fun init(root: String)

suspend fun save(
note: Note,
Expand Down
24 changes: 18 additions & 6 deletions app/src/main/java/dev/arkbuilders/arkmemo/repo/NotesRepoHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ import dev.arkbuilders.arklib.data.index.RootIndex
import dev.arkbuilders.arklib.user.properties.Properties
import dev.arkbuilders.arklib.user.properties.PropertiesStorage
import dev.arkbuilders.arklib.user.properties.PropertiesStorageRepo
import dev.arkbuilders.arkmemo.di.IO_DISPATCHER
import dev.arkbuilders.arkmemo.models.Note
import dev.arkbuilders.arkmemo.preferences.MemoPreferences
import dev.arkbuilders.arkmemo.utils.isEqual
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext
import java.nio.file.Path
import javax.inject.Inject
import javax.inject.Named
import kotlin.NullPointerException
import kotlin.io.path.Path
import kotlin.io.path.deleteIfExists
import kotlin.io.path.extension
import kotlin.io.path.getLastModifiedTime
Expand All @@ -24,15 +29,22 @@ import kotlin.io.path.name
class NotesRepoHelper
@Inject
constructor(
private val memoPreferences: MemoPreferences,
private val propertiesStorageRepo: PropertiesStorageRepo,
@Named(IO_DISPATCHER) private val iODispatcher: CoroutineDispatcher,
) {
private lateinit var root: Path
lateinit var root: Path

private lateinit var propertiesStorage: PropertiesStorage
private val lazyPropertiesStorage by lazy {
CoroutineScope(iODispatcher).async {
val propertyStorage = propertiesStorageRepo.provide(RootIndex.provide(root))
propertyStorage
}
}

suspend fun init() {
root = memoPreferences.getNotesStorage()
propertiesStorage = propertiesStorageRepo.provide(RootIndex.provide(root))
suspend fun init(root: String) {
this.root = Path(root)
propertiesStorage = lazyPropertiesStorage.await()
}

suspend fun persistNoteProperties(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import dev.arkbuilders.arkmemo.graphics.ColorCode
import dev.arkbuilders.arkmemo.graphics.SVG
import dev.arkbuilders.arkmemo.models.GraphicNote
import dev.arkbuilders.arkmemo.models.SaveNoteResult
import dev.arkbuilders.arkmemo.preferences.MemoPreferences
import dev.arkbuilders.arkmemo.repo.NotesRepo
import dev.arkbuilders.arkmemo.repo.NotesRepoHelper
import dev.arkbuilders.arkmemo.utils.dpToPx
Expand All @@ -39,12 +38,11 @@ import kotlin.io.path.name
class GraphicNotesRepo
@Inject
constructor(
private val memoPreferences: MemoPreferences,
@Named(IO_DISPATCHER) private val iODispatcher: CoroutineDispatcher,
private val helper: NotesRepoHelper,
@ApplicationContext private val context: Context,
) : NotesRepo<GraphicNote> {
private lateinit var root: Path
private val root: Path by lazy { helper.root }

private val displayMetrics by lazy { Resources.getSystem().displayMetrics }
private val screenWidth by lazy { displayMetrics.widthPixels }
Expand All @@ -53,9 +51,8 @@ class GraphicNotesRepo

private val thumbDirectory by lazy { context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) }

override suspend fun init() {
helper.init()
root = memoPreferences.getNotesStorage()
override suspend fun init(root: String) {
helper.init(root)
}

override suspend fun save(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import dev.arkbuilders.arklib.data.index.Resource
import dev.arkbuilders.arkmemo.di.IO_DISPATCHER
import dev.arkbuilders.arkmemo.models.SaveNoteResult
import dev.arkbuilders.arkmemo.models.TextNote
import dev.arkbuilders.arkmemo.preferences.MemoPreferences
import dev.arkbuilders.arkmemo.repo.NotesRepo
import dev.arkbuilders.arkmemo.repo.NotesRepoHelper
import dev.arkbuilders.arkmemo.utils.listFiles
Expand All @@ -27,16 +26,14 @@ import kotlin.io.path.writeLines
class TextNotesRepo
@Inject
constructor(
private val memoPreferences: MemoPreferences,
@Named(IO_DISPATCHER)
private val iODispatcher: CoroutineDispatcher,
private val helper: NotesRepoHelper,
) : NotesRepo<TextNote> {
private lateinit var root: Path
private val root: Path by lazy { helper.root }

override suspend fun init() {
root = memoPreferences.getNotesStorage()
helper.init()
override suspend fun init(root: String) {
helper.init(root)
}

override suspend fun save(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import dev.arkbuilders.arklib.data.index.Resource
import dev.arkbuilders.arkmemo.di.IO_DISPATCHER
import dev.arkbuilders.arkmemo.models.SaveNoteResult
import dev.arkbuilders.arkmemo.models.VoiceNote
import dev.arkbuilders.arkmemo.preferences.MemoPreferences
import dev.arkbuilders.arkmemo.repo.NotesRepo
import dev.arkbuilders.arkmemo.repo.NotesRepoHelper
import dev.arkbuilders.arkmemo.utils.extractDuration
Expand All @@ -26,15 +25,13 @@ import kotlin.io.path.pathString
class VoiceNotesRepo
@Inject
constructor(
private val memoPreferences: MemoPreferences,
@Named(IO_DISPATCHER) private val iODispatcher: CoroutineDispatcher,
private val helper: NotesRepoHelper,
) : NotesRepo<VoiceNote> {
private lateinit var root: Path
private val root: Path by lazy { helper.root }

override suspend fun init() {
root = memoPreferences.getNotesStorage()
helper.init()
override suspend fun init(root: String) {
helper.init(root)
}

override suspend fun read(): List<VoiceNote> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,9 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
onBackPressedDispatcher.onBackPressed()
}

fun showFragment() {
val textDataFromIntent = intent?.getStringExtra(Intent.EXTRA_TEXT)
if (textDataFromIntent != null) {
fragment = EditTextNotesFragment.newInstance(textDataFromIntent)
supportFragmentManager.beginTransaction().apply {
replace(fragContainer, fragment, EditTextNotesFragment.TAG)
commit()
}
} else {
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction().apply {
add(fragContainer, fragment, NotesFragment.TAG)
commit()
}
} else {
supportFragmentManager.apply {
val tag = savedInstanceState.getString(CURRENT_FRAGMENT_TAG)
findFragmentByTag(tag)?.let {
fragment = it
if (!fragment.isInLayout) {
resumeFragment(fragment)
}
}
}
}
}
supportFragmentManager.onArkPathPicked(this) {
memoPreferences.storePath(it.toString())
showFragment(savedInstanceState)
}

val storageFolderExisting = memoPreferences.getNotesStorage().exists()
Expand All @@ -102,13 +79,43 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
} else {
FilePickerDialog.show(this, supportFragmentManager)
}
} else {
if (memoPreferences.isLastLaunchSuccess()) {
showFragment(savedInstanceState)
} else {
showRetrySelectRootDialog(
rootPath = memoPreferences.getPath(),
savedInstanceState = savedInstanceState,
)
}
}
}

supportFragmentManager.onArkPathPicked(this) {
memoPreferences.storePath(it.toString())
showFragment()
private fun showFragment(savedInstanceState: Bundle?) {
val textDataFromIntent = intent?.getStringExtra(Intent.EXTRA_TEXT)
if (textDataFromIntent != null) {
fragment = EditTextNotesFragment.newInstance(textDataFromIntent)
supportFragmentManager.beginTransaction().apply {
replace(fragContainer, fragment, EditTextNotesFragment.TAG)
commit()
}
} else {
showFragment()
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction().apply {
add(fragContainer, fragment, NotesFragment.TAG)
commit()
}
} else {
supportFragmentManager.apply {
val tag = savedInstanceState.getString(CURRENT_FRAGMENT_TAG)
findFragmentByTag(tag)?.let {
fragment = it
if (!fragment.isInLayout) {
resumeFragment(fragment)
}
}
}
}
}
}

Expand All @@ -133,6 +140,35 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
loadFailDialog.show(supportFragmentManager, CommonActionDialog.TAG)
}

private fun showRetrySelectRootDialog(
rootPath: String,
savedInstanceState: Bundle?,
) {
val loadFailDialog =
CommonActionDialog(
title = getString(R.string.error_load_notes_crash_title),
message = getString(R.string.error_load_notes_crash_description, rootPath),
positiveText = R.string.error_load_notes_failed_retry_action,
negativeText = R.string.error_load_notes_failed_negative_action,
neutralText = R.string.error_load_notes_failed_positive_action,
isAlert = false,
enableNeutralOption = true,
onPositiveClick = {
showFragment(savedInstanceState)
},
onNegativeClicked = {
finish()
},
onNeutralClicked = {
FilePickerDialog.show(this, supportFragmentManager)
},
onCloseClicked = {
finish()
},
)
loadFailDialog.show(supportFragmentManager, CommonActionDialog.TAG)
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putString(CURRENT_FRAGMENT_TAG, fragment.tag)
super.onSaveInstanceState(outState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.annotation.StringRes
import androidx.fragment.app.DialogFragment
import dev.arkbuilders.arkmemo.R
import dev.arkbuilders.arkmemo.databinding.DialogCommonActionBinding
import dev.arkbuilders.arkmemo.utils.visible

/**
* This is a common action dialog that can be used inside app.
Expand All @@ -18,9 +19,12 @@ class CommonActionDialog(
private val message: String,
@StringRes private val positiveText: Int,
@StringRes private val negativeText: Int,
@StringRes private val neutralText: Int? = null,
private val isAlert: Boolean = false,
private val enableNeutralOption: Boolean = false,
private val onPositiveClick: (() -> Unit)? = null,
private val onNegativeClicked: (() -> Unit)? = null,
private val onNeutralClicked: (() -> Unit)? = null,
private val onCloseClicked: (() -> Unit)? = null,
) : DialogFragment() {
companion object {
Expand Down Expand Up @@ -48,10 +52,15 @@ class CommonActionDialog(
mBinding.tvPositive.setBackgroundResource(R.drawable.bg_red_button)
}

if (enableNeutralOption) {
mBinding.tvNeutral.visible()
}

mBinding.tvTitle.text = title
mBinding.tvMessage.text = message
mBinding.tvPositive.setText(positiveText)
mBinding.tvNegative.setText(negativeText)
neutralText?.let { mBinding.tvNeutral.setText(neutralText) }
mBinding.ivClose.setOnClickListener {
onCloseClicked?.invoke()
dismiss()
Expand All @@ -66,6 +75,11 @@ class CommonActionDialog(
onNegativeClicked?.invoke()
dismiss()
}

mBinding.tvNeutral.setOnClickListener {
onNeutralClicked?.invoke()
dismiss()
}
}

override fun onResume() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ class ArkRecorderFragment : BaseEditNoteFragment() {
}

private fun observeDataStates() {
notesViewModel.init {}
observeRecordingState()
observeSaveResult(notesViewModel.getSaveNoteResultLiveData())
}
Expand Down
Loading
Loading