Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
hb0 committed Sep 18, 2023
1 parent beed59e commit 4ebf57a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 53 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ ext {
androidxAnnotationVersion = "1.6.0"
androidxAppCompatVersion = "1.6.1"
androidPreferencesVersion = '1.2.1'
datastoreVersion = "1.1.0-alpha04" // only 1.1.0 supports multi-process datastore
datastoreVersion = "1.1.0-alpha05" // only 1.1.0 supports multi-process datastore

// Other dependencies
materialDialogsVersion = '3.3.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.LifecycleCoroutineScope
import com.afollestad.materialdialogs.MaterialDialog
import de.cyface.energy_settings.Constants.TAG
import de.cyface.energy_settings.GnssDisabledWarningDialog.Companion.create
import de.cyface.energy_settings.ProblematicManufacturerWarningDialog.Companion.create
import de.cyface.energy_settings.settings.EnergySettings
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.util.Locale

Expand All @@ -54,12 +54,18 @@ import java.util.Locale
* 2. As [MaterialDialog]. Use the static [create] method which returns the dialog.
*
* @author Armin Schnabel
* @version 2.1.0
* @version 3.0.0
* @since 1.0.0
*
* @param recipientEmail The e-mail address to which the feedback email should be addressed to in the generated template.
* @property recipientEmail The e-mail address to which the feedback email should be addressed to in the generated template.
* @property scope The scope to execute async code in.
* @property settings The settings which contain the user preferences.
*/
internal class ProblematicManufacturerWarningDialog(private val recipientEmail: String) :
internal class ProblematicManufacturerWarningDialog(
private val recipientEmail: String,
private val scope: LifecycleCoroutineScope,
private val settings: EnergySettings
) :
EnergySettingDialog() {

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
Expand All @@ -70,8 +76,8 @@ internal class ProblematicManufacturerWarningDialog(private val recipientEmail:

// Allow the user to express its preference to disable auto-popup of this dialog
builder.setNegativeButton(negativeButtonRes) { _, _ ->
GlobalScope.launch { // FIXME
onNegativeButtonCall(context)
scope.launch {
onNegativeButtonCall(settings)
}
}

Expand Down Expand Up @@ -170,26 +176,36 @@ internal class ProblematicManufacturerWarningDialog(private val recipientEmail:

/**
* Saves the user's preference to disable auto-popup of this dialog
*
* @param settings The settings which contain the user preferences.
*/
private suspend fun onNegativeButtonCall(context: Context?) {
EnergySettings().setManufacturerWarningShown(true)
private suspend fun onNegativeButtonCall(settings: EnergySettings) {
settings.setManufacturerWarningShown(true)
}

/**
* Alternative, `FragmentManager`-less implementation.
*
* @param activity Required to show the dialog
* @param recipientEmail The e-mail address to which the feedback email should be addressed to in the generated template.
* @param settings The settings which contain the user preferences.
* @param scope The scope to execute async code in.
*/
fun create(activity: Activity, recipientEmail: String): MaterialDialog {
fun create(
activity: Activity,
recipientEmail: String,
settings: EnergySettings,
scope: LifecycleCoroutineScope
): MaterialDialog {

// Generate dialog
val dialog = MaterialDialog(activity, DIALOG_BEHAVIOUR)
dialog.title(titleRes, null)

// Allow the user to express its preference to disable auto-popup of this dialog
dialog.negativeButton(negativeButtonRes) {
GlobalScope.launch { // FIXME
onNegativeButtonCall(activity.applicationContext)
scope.launch {
onNegativeButtonCall(settings)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ import android.os.Build
import android.os.PowerManager
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
import de.cyface.energy_settings.TrackingSettings.initialize
import de.cyface.energy_settings.settings.EnergySettings
import de.cyface.energy_settings.settings.PreferencesMigrationFactory
import de.cyface.energy_settings.settings.SettingsSerializer
import de.cyface.energy_settings.settings.StoreMigration
import de.cyface.utils.Validate
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
Expand All @@ -50,7 +47,7 @@ import java.util.Locale
* Attention: You need to call [initialize] before you use this object, e.g. in Activity.onCreate.
*
* @author Armin Schnabel
* @version 2.0.3
* @version 2.0.4
* @since 1.0.0
*/
object TrackingSettings {
Expand All @@ -60,35 +57,9 @@ object TrackingSettings {
*/
private lateinit var settings: EnergySettings

// FIXME: see if we can also mice the datastore to CustomSettings like everywhere else.
/**
* The data store with single-process support.
*
* We don't use multi-process support as this should usually only run in the ui process.
* I.e. there is no need for that overhead.
*
* Attention:
* - Never mix SingleProcessDataStore with MultiProcessDataStore for the same file.
* - We use SingleProcessDataStore, so don't access preferences from multiple processes.
* - Only create one instance of `DataStore` per file in the same process.
* - We use ProtoBuf to ensure type safety. Rebuild after changing the .proto file.
*/
lateinit var dataStore: DataStore<Settings>

@JvmStatic
fun initialize(context: Context) {
val appContext = context.applicationContext
val dataStoreFile = appContext.dataStoreFile("energy_settings.pb")
dataStore = DataStoreFactory.create(
serializer = SettingsSerializer,
produceFile = { dataStoreFile },
migrations = listOf(
PreferencesMigrationFactory.create(appContext),
StoreMigration()
)
)
settings =
EnergySettings() // Depends on dataStore to be initialized
settings = EnergySettings(context)
}

/**
Expand Down Expand Up @@ -366,7 +337,11 @@ object TrackingSettings {
if (isProblematicManufacturer && (force || !warningShown)) {
val fragmentManager = fragment.fragmentManager
Validate.notNull(fragmentManager)
val dialog = ProblematicManufacturerWarningDialog(recipientEmail)
val dialog = ProblematicManufacturerWarningDialog(
recipientEmail,
fragment.lifecycleScope,
settings
)
dialog.setTargetFragment(
fragment,
Constants.DIALOG_PROBLEMATIC_MANUFACTURER_WARNING_CODE
Expand All @@ -386,14 +361,16 @@ object TrackingSettings {
* @param recipientEmail The e-mail address to which the feedback email should be addressed to in the generated
* template.
* @param force `True` if the dialog should be shown no matter of the preferences state
* @param scope The scope to execute async code in.
* @return `True` if the dialog is shown
*/
@JvmStatic
@Suppress("MemberVisibilityCanBePrivate") // Used by implementing app
fun showProblematicManufacturerDialog(
activity: Activity?,
force: Boolean,
recipientEmail: String
recipientEmail: String,
scope: LifecycleCoroutineScope
): Boolean {

if (activity == null || activity.isFinishing) {
Expand All @@ -406,7 +383,8 @@ object TrackingSettings {
}

if (isProblematicManufacturer && (force || !warningShown)) {
ProblematicManufacturerWarningDialog.create(activity, recipientEmail).show()
ProblematicManufacturerWarningDialog.create(activity, recipientEmail, settings, scope)
.show()
return true
}
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
*/
package de.cyface.energy_settings.settings

import de.cyface.energy_settings.TrackingSettings
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import de.cyface.energy_settings.Settings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

Expand All @@ -32,8 +36,35 @@ import kotlinx.coroutines.flow.map
* @author Armin Schnabel
* @version 2.0.0
* @since 3.3.4
* @param context The context to access the settings from.
*/
class EnergySettings {
class EnergySettings(context: Context) {

/**
* This avoids leaking the context when this object outlives the Activity of Fragment.
*/
private val appContext = context.applicationContext

/**
* The data store with single-process support.
*
* We don't use multi-process support as this should usually only run in the ui process.
* I.e. there is no need for that overhead.
*
* Attention:
* - Never mix SingleProcessDataStore with MultiProcessDataStore for the same file.
* - We use SingleProcessDataStore, so don't access preferences from multiple processes.
* - Only create one instance of `DataStore` per file in the same process.
* - We use ProtoBuf to ensure type safety. Rebuild after changing the .proto file.
*/
private var dataStore: DataStore<Settings> = DataStoreFactory.create(
serializer = SettingsSerializer,
produceFile = { appContext.dataStoreFile("energy_settings.pb") },
migrations = listOf(
PreferencesMigrationFactory.create(appContext),
StoreMigration()
)
)

/**
* Saves whether the user marked the manufacturer-specific warning as "don't show again".
Expand All @@ -42,7 +73,7 @@ class EnergySettings {
*/
@Suppress("unused") // Part of the API
suspend fun setManufacturerWarningShown(value: Boolean) {
TrackingSettings.dataStore.updateData { currentSettings ->
dataStore.updateData { currentSettings ->
currentSettings.toBuilder()
.setManufacturerWarningShown(value)
.build()
Expand All @@ -52,7 +83,7 @@ class EnergySettings {
/**
* @return Whether user marked the manufacturer-specific warning as "don't show again".
*/
val manufacturerWarningShownFlow: Flow<Boolean> = TrackingSettings.dataStore.data
val manufacturerWarningShownFlow: Flow<Boolean> = dataStore.data
.map { settings ->
settings.manufacturerWarningShown
}
Expand Down

0 comments on commit 4ebf57a

Please sign in to comment.