diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt index b92e02ce6..ad4ce1f08 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt @@ -18,11 +18,11 @@ import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Co import com.kunzisoft.keepass.activities.stylish.StylishActivity import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.DatabaseTaskProvider.Companion.startDatabaseService -import com.kunzisoft.keepass.database.ProgressMessage import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment.Companion.PROGRESS_TASK_DIALOG_TAG +import com.kunzisoft.keepass.tasks.ProgressTaskViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import kotlinx.coroutines.launch @@ -32,6 +32,7 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { protected val mDatabase: ContextualDatabase? get() = mDatabaseViewModel.database + private val progressTaskViewModel: ProgressTaskViewModel by viewModels() private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null @@ -81,13 +82,13 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { ) } is DatabaseViewModel.ActionState.OnDatabaseActionStarted -> { - showDialog(uiState.progressMessage) + progressTaskViewModel.start(uiState.progressMessage) } is DatabaseViewModel.ActionState.OnDatabaseActionUpdated -> { - showDialog(uiState.progressMessage) + progressTaskViewModel.update(uiState.progressMessage) } is DatabaseViewModel.ActionState.OnDatabaseActionStopped -> { - stopDialog() + progressTaskViewModel.stop() } is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> { onDatabaseActionFinished( @@ -95,12 +96,24 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { uiState.actionTask, uiState.result ) - stopDialog() + progressTaskViewModel.stop() } } } } } + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + progressTaskViewModel.progressTaskState.collect { state -> + when (state) { + ProgressTaskViewModel.ProgressTaskState.Start -> + showDialog() + ProgressTaskViewModel.ProgressTaskState.Stop -> + stopDialog() + } + } + } + } lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.RESUMED) { mDatabaseViewModel.databaseState.collect { database -> @@ -194,7 +207,7 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { } } - private fun showDialog(progressMessage: ProgressMessage) { + private fun showDialog() { lifecycleScope.launch { if (showDatabaseDialog()) { if (progressTaskDialogFragment == null) { @@ -208,12 +221,6 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { PROGRESS_TASK_DIALOG_TAG ) } - progressTaskDialogFragment?.apply { - updateTitle(progressMessage.titleId) - updateMessage(progressMessage.messageId) - updateWarning(progressMessage.warningId) - setCancellable(progressMessage.cancelable) - } } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt b/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt index f25801ca0..557277ca6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt @@ -1,13 +1,8 @@ package com.kunzisoft.keepass.database -import androidx.annotation.StringRes - data class ProgressMessage( - @StringRes - var titleId: Int, - @StringRes - var messageId: Int? = null, - @StringRes - var warningId: Int? = null, + var title: String, + var message: String? = null, + var warning: String? = null, var cancelable: (() -> Unit)? = null ) diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index f60a5b220..c842644c2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -33,6 +33,7 @@ import com.kunzisoft.keepass.R import com.kunzisoft.keepass.activities.GroupActivity import com.kunzisoft.keepass.app.database.CipherDatabaseAction import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction +import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.MainCredential import com.kunzisoft.keepass.database.ProgressMessage @@ -61,7 +62,6 @@ import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.hardware.HardwareKey -import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.settings.PreferencesUtil @@ -112,7 +112,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress private var mTaskRemovedRequested = false private var mSaveState = false - private var mProgressMessage: ProgressMessage = ProgressMessage(R.string.database_opened) + private lateinit var mProgressMessage: ProgressMessage override fun retrieveChannelId(): String { return CHANNEL_DATABASE_ID @@ -305,6 +305,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress mResponseChallengeChannel = null } + override fun onCreate() { + super.onCreate() + mProgressMessage = ProgressMessage( + title = getString(R.string.database_opened) + ) + } + override fun onBind(intent: Intent): IBinder? { super.onBind(intent) return mActionTaskBinder @@ -391,9 +398,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress TimeoutHelper.temporarilyDisableTimeout() sendBroadcast(Intent(DATABASE_START_TASK_ACTION).apply { - putExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.titleId) - putExtra(DATABASE_TASK_MESSAGE_KEY, mProgressMessage.messageId) - putExtra(DATABASE_TASK_WARNING_KEY, mProgressMessage.warningId) + putExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.title) + putExtra(DATABASE_TASK_MESSAGE_KEY, mProgressMessage.message) + putExtra(DATABASE_TASK_WARNING_KEY, mProgressMessage.warning) }) mActionTaskListeners.forEach { actionTaskListener -> @@ -506,8 +513,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress R.drawable.notification_ic_database_action // Title depending on action - mProgressMessage.titleId = - if (intentAction == null) { + mProgressMessage.title = + getString(if (intentAction == null) { R.string.database_opened } else when (intentAction) { ACTION_DATABASE_CREATE_TASK -> R.string.creating_database @@ -522,24 +529,22 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress else R.string.command_execution } - } + }) // Updated later - mProgressMessage.messageId = null + mProgressMessage.message = null // Warning if data is saved - mProgressMessage.warningId = + mProgressMessage.warning = if (mSaveState) - R.string.do_not_kill_app + getString(R.string.do_not_kill_app) else null val notificationBuilder = buildNewNotification().apply { setSmallIcon(iconId) intent?.let { - setContentTitle(getString( - intent.getIntExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.titleId)) - ) + setContentTitle(intent.getStringExtra(DATABASE_TASK_TITLE_KEY)) } setAutoCancel(false) setContentIntent(null) @@ -661,8 +666,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress } } - private fun updateMessage(resId: Int) { - mProgressMessage.messageId = resId + private fun updateMessage(@StringRes resId: Int) { + mProgressMessage.message = getString(resId) notifyProgressMessage() } @@ -708,7 +713,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress initializeChallengeResponse() val previousMessage = mProgressMessage.copy() mProgressMessage.apply { - messageId = R.string.waiting_challenge_request + message = getString(R.string.waiting_challenge_request) cancelable = { cancelChallengeResponse(R.string.error_cancel_by_user) } @@ -723,7 +728,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress ) // Wait the response mProgressMessage.apply { - messageId = R.string.waiting_challenge_response + message = getString(R.string.waiting_challenge_response) } notifyProgressMessage() response = mResponseChallengeChannel?.receive() ?: byteArrayOf() diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt index e9240b73e..705f20faa 100644 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt @@ -27,32 +27,27 @@ import android.view.View import android.widget.Button import android.widget.ProgressBar import android.widget.TextView -import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.kunzisoft.keepass.R import kotlinx.coroutines.launch open class ProgressTaskDialogFragment : DialogFragment() { - @StringRes - private var title = UNDEFINED - @StringRes - private var message = UNDEFINED - @StringRes - private var warning = UNDEFINED - private var cancellable: (() -> Unit)? = null - private var titleView: TextView? = null private var messageView: TextView? = null private var warningView: TextView? = null private var cancelButton: Button? = null private var progressView: ProgressBar? = null - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + private val progressTaskViewModel: ProgressTaskViewModel by activityViewModels() + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { try { activity?.let { val builder = AlertDialog.Builder(it) @@ -71,68 +66,48 @@ open class ProgressTaskDialogFragment : DialogFragment() { cancelButton = root.findViewById(R.id.progress_dialog_cancel) progressView = root.findViewById(R.id.progress_dialog_bar) - updateTitle(title) - updateMessage(message) - updateWarning(warning) - setCancellable(cancellable) - isCancelable = false return builder.create() } } catch (e: Exception) { - Log.e(TAG, "Unable to create progress dialog") + Log.e(TAG, "Unable to create progress dialog", e) } return super.onCreateDialog(savedInstanceState) } - fun setTitle(@StringRes titleId: Int) { - this.title = titleId + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + progressTaskViewModel.progressMessageState.collect { state -> + updateView(titleView, state.title) + updateView(messageView, state.message) + updateView(warningView, state.warning) + activity?.lifecycleScope?.launch { + cancelButton?.isVisible = state.cancelable != null + cancelButton?.setOnClickListener { + state.cancelable?.invoke() + } + } + } + } + } } - private fun updateView(textView: TextView?, @StringRes resId: Int) { + private fun updateView(textView: TextView?, value: String?) { activity?.lifecycleScope?.launch { - if (resId == UNDEFINED) { + if (value == null) { textView?.visibility = View.GONE } else { - textView?.setText(resId) + textView?.text = value textView?.visibility = View.VISIBLE } } } - private fun updateCancelable() { - activity?.lifecycleScope?.launch { - cancelButton?.isVisible = cancellable != null - cancelButton?.setOnClickListener { - cancellable?.invoke() - } - } - } - - fun updateTitle(@StringRes resId: Int?) { - this.title = resId ?: UNDEFINED - updateView(titleView, title) - } - - fun updateMessage(@StringRes resId: Int?) { - this.message = resId ?: UNDEFINED - updateView(messageView, message) - } - - fun updateWarning(@StringRes resId: Int?) { - this.warning = resId ?: UNDEFINED - updateView(warningView, warning) - } - - fun setCancellable(cancellable: (() -> Unit)?) { - this.cancellable = cancellable - updateCancelable() - } - companion object { private val TAG = ProgressTaskDialogFragment::class.java.simpleName const val PROGRESS_TASK_DIALOG_TAG = "progressDialogFragment" - const val UNDEFINED = -1 } } diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt new file mode 100644 index 000000000..63620103c --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt @@ -0,0 +1,33 @@ +package com.kunzisoft.keepass.tasks + +import androidx.lifecycle.ViewModel +import com.kunzisoft.keepass.database.ProgressMessage +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +class ProgressTaskViewModel: ViewModel() { + + private val mProgressMessageState = MutableStateFlow(ProgressMessage("")) + val progressMessageState: StateFlow = mProgressMessageState + + private val mProgressTaskState = MutableStateFlow(ProgressTaskState.Stop) + val progressTaskState: StateFlow = mProgressTaskState + + fun update(value: ProgressMessage) { + mProgressMessageState.value = value + } + + fun start(value: ProgressMessage) { + mProgressTaskState.value = ProgressTaskState.Start + update(value) + } + + fun stop() { + mProgressTaskState.value = ProgressTaskState.Stop + } + + sealed class ProgressTaskState { + object Start: ProgressTaskState() + object Stop: ProgressTaskState() + } +} \ No newline at end of file