mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 08:45:27 +02:00
Send analytics option
User can now decide whether or not the app will send analytics (enabled by default)
This commit is contained in:
parent
9d5eb22063
commit
8635b4f54c
@ -11,8 +11,8 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Unitto">
|
android:theme="@style/Theme.Unitto">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_analytics_collection_deactivated"
|
android:name="firebase_analytics_collection_enabled"
|
||||||
android:value="${analytics_deactivated}" />
|
android:value="false" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="firebase_crashlytics_collection_enabled"
|
android:name="firebase_crashlytics_collection_enabled"
|
||||||
android:value="${crashlytics_enabled}" />
|
android:value="${crashlytics_enabled}" />
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package com.sadellie.unitto.data.preferences
|
package com.sadellie.unitto.data.preferences
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.*
|
||||||
import androidx.datastore.preferences.core.edit
|
|
||||||
import androidx.datastore.preferences.core.intPreferencesKey
|
|
||||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
|
||||||
import androidx.datastore.preferences.preferencesDataStore
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -26,6 +23,7 @@ object UserPreferenceKeys {
|
|||||||
val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY")
|
val OUTPUT_FORMAT = intPreferencesKey("OUTPUT_FORMAT_PREF_KEY")
|
||||||
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
|
val LATEST_LEFT_SIDE = stringPreferencesKey("LATEST_LEFT_SIDE_PREF_KEY")
|
||||||
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
|
val LATEST_RIGHT_SIDE = stringPreferencesKey("LATEST_RIGHT_SIDE_PREF_KEY")
|
||||||
|
val ENABLE_ANALYTICS = booleanPreferencesKey("ENABLE_ANALYTICS_PREF_KEY")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,10 +54,21 @@ class UserPreferences @Inject constructor(@ApplicationContext private val contex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets boolean from datastore
|
||||||
|
*
|
||||||
|
* @param[default] Value to return if didn't find anything on fresh install
|
||||||
|
*/
|
||||||
|
fun getItem(key: Preferences.Key<Boolean>, default: Boolean): Flow<Boolean> {
|
||||||
|
return context.settingsDataStore.data.map {
|
||||||
|
it[key] ?: default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves string value by key
|
* Saves string value by key
|
||||||
*/
|
*/
|
||||||
suspend fun saveString(key: Preferences.Key<String>, value: String) {
|
suspend fun saveItem(key: Preferences.Key<String>, value: String) {
|
||||||
context.settingsDataStore.edit {
|
context.settingsDataStore.edit {
|
||||||
it[key] = value
|
it[key] = value
|
||||||
}
|
}
|
||||||
@ -68,7 +77,16 @@ class UserPreferences @Inject constructor(@ApplicationContext private val contex
|
|||||||
/**
|
/**
|
||||||
* Saves int value by key
|
* Saves int value by key
|
||||||
*/
|
*/
|
||||||
suspend fun saveInt(key: Preferences.Key<Int>, value: Int) {
|
suspend fun saveItem(key: Preferences.Key<Int>, value: Int) {
|
||||||
|
context.settingsDataStore.edit {
|
||||||
|
it[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves boolean value by key
|
||||||
|
*/
|
||||||
|
suspend fun saveItem(key: Preferences.Key<Boolean>, value: Boolean) {
|
||||||
context.settingsDataStore.edit {
|
context.settingsDataStore.edit {
|
||||||
it[key] = value
|
it[key] = value
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import com.sadellie.unitto.data.KEY_0
|
import com.sadellie.unitto.data.KEY_0
|
||||||
import com.sadellie.unitto.data.KEY_DOT
|
import com.sadellie.unitto.data.KEY_DOT
|
||||||
@ -45,7 +46,7 @@ class MainViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun saveCurrentAppTheme(value: Int) {
|
fun saveCurrentAppTheme(value: Int) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
mySettingsPrefs.saveInt(key = UserPreferenceKeys.CURRENT_APP_THEME, value)
|
mySettingsPrefs.saveItem(key = UserPreferenceKeys.CURRENT_APP_THEME, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ class MainViewModel @Inject constructor(
|
|||||||
fun setPrecisionPref(value: Int) {
|
fun setPrecisionPref(value: Int) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
precision = value
|
precision = value
|
||||||
mySettingsPrefs.saveInt(UserPreferenceKeys.DIGITS_PRECISION, value)
|
mySettingsPrefs.saveItem(UserPreferenceKeys.DIGITS_PRECISION, value)
|
||||||
convertValue()
|
convertValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +74,7 @@ class MainViewModel @Inject constructor(
|
|||||||
separator = value
|
separator = value
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Formatter.setSeparator(value)
|
Formatter.setSeparator(value)
|
||||||
mySettingsPrefs.saveInt(UserPreferenceKeys.SEPARATOR, value)
|
mySettingsPrefs.saveItem(UserPreferenceKeys.SEPARATOR, value)
|
||||||
convertValue()
|
convertValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,11 +94,24 @@ class MainViewModel @Inject constructor(
|
|||||||
outputFormat = value
|
outputFormat = value
|
||||||
// Updating value on disk
|
// Updating value on disk
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
mySettingsPrefs.saveInt(UserPreferenceKeys.OUTPUT_FORMAT, value)
|
mySettingsPrefs.saveItem(UserPreferenceKeys.OUTPUT_FORMAT, value)
|
||||||
convertValue()
|
convertValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ANALYTICS
|
||||||
|
*/
|
||||||
|
var enableAnalytics: Boolean by mutableStateOf(false)
|
||||||
|
|
||||||
|
fun setAnalyticsPref(value: Boolean) {
|
||||||
|
enableAnalytics = value
|
||||||
|
viewModelScope.launch {
|
||||||
|
mySettingsPrefs.saveItem(UserPreferenceKeys.ENABLE_ANALYTICS, value)
|
||||||
|
FirebaseAnalytics.getInstance(application).setAnalyticsCollectionEnabled(enableAnalytics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit we converting from (left side)
|
* Unit we converting from (left side)
|
||||||
*/
|
*/
|
||||||
@ -400,8 +414,8 @@ class MainViewModel @Inject constructor(
|
|||||||
*/
|
*/
|
||||||
fun saveMe() {
|
fun saveMe() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
mySettingsPrefs.saveString(UserPreferenceKeys.LATEST_LEFT_SIDE, unitFrom.unitId)
|
mySettingsPrefs.saveItem(UserPreferenceKeys.LATEST_LEFT_SIDE, unitFrom.unitId)
|
||||||
mySettingsPrefs.saveString(UserPreferenceKeys.LATEST_RIGHT_SIDE, unitTo.unitId)
|
mySettingsPrefs.saveItem(UserPreferenceKeys.LATEST_RIGHT_SIDE, unitTo.unitId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,6 +546,9 @@ class MainViewModel @Inject constructor(
|
|||||||
* He can choose another unit group and doesn't need to wait for network to appear.
|
* He can choose another unit group and doesn't need to wait for network to appear.
|
||||||
* */
|
* */
|
||||||
updateCurrenciesBasicUnits()
|
updateCurrenciesBasicUnits()
|
||||||
|
|
||||||
|
enableAnalytics = mySettingsPrefs.getItem(UserPreferenceKeys.ENABLE_ANALYTICS, true).first()
|
||||||
|
FirebaseAnalytics.getInstance(application).setAnalyticsCollectionEnabled(enableAnalytics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,10 @@ package com.sadellie.unitto.screens.setttings
|
|||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -17,22 +15,24 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents one item in list on Settings screen
|
* Basic list item for settings screen. By default only has label and support text, clickable.
|
||||||
|
* This component can be easily modified if you provide additional component to it,
|
||||||
|
* for example a switch or a checkbox
|
||||||
*
|
*
|
||||||
* @param modifier Modifier that is applied to a [Row]
|
* @param label Main text
|
||||||
* @param onClick Action to perform when clicking this item
|
* @param supportText Text that is located below label
|
||||||
* @param label Big text that is above support text
|
* @param onClick Action to perform when user clicks on this component (whole component is clickable)
|
||||||
* @param supportText Smaller text that is below label
|
* @param content Additional composable: buttons, switches, checkboxes or something else
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsListItem(
|
private fun BasicSettingsListItem(
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onClick: () -> Unit,
|
|
||||||
label: String,
|
label: String,
|
||||||
supportText: String? = null,
|
supportText: String? = null,
|
||||||
|
onClick: () -> Unit = {},
|
||||||
|
content: @Composable RowScope.() -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(
|
.clickable(
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
@ -43,7 +43,9 @@ fun SettingsListItem(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
Modifier.padding(horizontal = 0.dp)
|
Modifier
|
||||||
|
.padding(horizontal = 0.dp)
|
||||||
|
.weight(1f) // This makes additional composable to be seen
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -62,5 +64,38 @@ fun SettingsListItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents one item in list on Settings screen
|
||||||
|
*
|
||||||
|
* @param label Main text
|
||||||
|
* @param supportText Text that is located below label
|
||||||
|
* @param onClick Action to perform when user clicks on this component (whole component is clickable)
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun SettingsListItem(
|
||||||
|
label: String,
|
||||||
|
supportText: String? = null,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
) = BasicSettingsListItem(label, supportText, onClick)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents one item in list on Settings screen
|
||||||
|
*
|
||||||
|
* @param label Main text
|
||||||
|
* @param supportText Text that is located below label
|
||||||
|
* @param switchState Current switch state
|
||||||
|
* @param onSwitchChange Action to perform when user clicks on this component or just switch
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun SettingsListItem(
|
||||||
|
label: String,
|
||||||
|
supportText: String? = null,
|
||||||
|
switchState: Boolean,
|
||||||
|
onSwitchChange: (Boolean) -> Unit
|
||||||
|
) = BasicSettingsListItem(label, supportText, { onSwitchChange(switchState) }) {
|
||||||
|
Switch(checked = switchState, onCheckedChange = { onSwitchChange(!it) })
|
||||||
|
}
|
||||||
|
@ -130,6 +130,11 @@ fun SettingsScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
SettingsListItem(
|
||||||
|
label = stringResource(id = R.string.send_usage_statistics),
|
||||||
|
supportText = stringResource(id = R.string.send_usage_statistics_support),
|
||||||
|
switchState = mainViewModel.enableAnalytics,
|
||||||
|
onSwitchChange = { mainViewModel.setAnalyticsPref(!it) })
|
||||||
SettingsListItem(
|
SettingsListItem(
|
||||||
label = stringResource(R.string.third_party_licenses),
|
label = stringResource(R.string.third_party_licenses),
|
||||||
onClick = { navControllerAction(ABOUT_SCREEN) }
|
onClick = { navControllerAction(ABOUT_SCREEN) }
|
||||||
|
@ -718,5 +718,7 @@
|
|||||||
<string name="clear_input_description">Clear input</string>
|
<string name="clear_input_description">Clear input</string>
|
||||||
<string name="favorite_button_description">Add or remove unit from favorites</string>
|
<string name="favorite_button_description">Add or remove unit from favorites</string>
|
||||||
<string name="empty_search_result_description">Empty search result</string>
|
<string name="empty_search_result_description">Empty search result</string>
|
||||||
|
<string name="send_usage_statistics">Send usage statistics</string>
|
||||||
|
<string name="send_usage_statistics_support">All data is anonymous and encrypted</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -670,5 +670,7 @@
|
|||||||
<string name="sun_mass_short">Солнце M</string>
|
<string name="sun_mass_short">Солнце M</string>
|
||||||
<string name="pressure">Давление</string>
|
<string name="pressure">Давление</string>
|
||||||
<string name="acceleration">Ускорение</string>
|
<string name="acceleration">Ускорение</string>
|
||||||
|
<string name="send_usage_statistics">Отправлять статистику использования</string>
|
||||||
|
<string name="send_usage_statistics_support">Все данные анонимны и зашифрованы</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -930,6 +930,8 @@
|
|||||||
<string name="privacy_policy">Privacy Policy</string>
|
<string name="privacy_policy">Privacy Policy</string>
|
||||||
<string name="third_party_licenses">Third party licenses</string>
|
<string name="third_party_licenses">Third party licenses</string>
|
||||||
<string name="rate_this_app">Rate this app</string>
|
<string name="rate_this_app">Rate this app</string>
|
||||||
|
<string name="send_usage_statistics">Send usage statistics</string>
|
||||||
|
<string name="send_usage_statistics_support">All data is anonymous and encrypted</string>
|
||||||
<string name="general_settings_group">General</string>
|
<string name="general_settings_group">General</string>
|
||||||
<string name="additional_settings_group">Additional</string>
|
<string name="additional_settings_group">Additional</string>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user