Extra onboarding step (#158)

* wip

* Add extra onboarding step
This commit is contained in:
Matthias Urhahn
2023-09-11 20:32:41 +02:00
committed by GitHub
parent 09d013588d
commit 3920489dcd
8 changed files with 186 additions and 3 deletions
@@ -8,6 +8,7 @@ import eu.darken.capod.common.error.ErrorEventSource
import eu.darken.capod.common.flow.setupCommonEventHandlers
import eu.darken.capod.common.livedata.SingleLiveEvent
import eu.darken.capod.common.navigation.NavEventSource
import eu.darken.capod.common.navigation.navVia
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn
@@ -31,4 +32,7 @@ abstract class ViewModel3(
.setupCommonEventHandlers(TAG) { "launchInViewModel()" }
.launchIn(vmScope)
fun NavDirections.navigate() {
navVia(navEvents)
}
}
@@ -40,6 +40,8 @@ class GeneralSettings @Inject constructor(
val isOffloadedBatchingDisabled = preferences.createFlowPreference("core.compat.offloaded.batching.disabled", false)
val useIndirectScanResultCallback = preferences.createFlowPreference("core.compat.indirectcallback.enabled", false)
val isOnboardingDone = preferences.createFlowPreference("core.onboarding.done", false)
override val preferenceDataStore: PreferenceDataStore = PreferenceStoreMapper(
monitorMode,
scannerMode,
@@ -0,0 +1,29 @@
package eu.darken.capod.main.ui.onboarding
import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
import eu.darken.capod.R
import eu.darken.capod.common.PrivacyPolicy
import eu.darken.capod.common.WebpageTool
import eu.darken.capod.common.uix.Fragment3
import eu.darken.capod.common.viewbinding.viewBinding
import eu.darken.capod.databinding.OnboardingFragmentBinding
import javax.inject.Inject
@AndroidEntryPoint
class OnboardingFragment : Fragment3(R.layout.onboarding_fragment) {
override val vm: OnboardingFragmentVM by viewModels()
override val ui: OnboardingFragmentBinding by viewBinding()
@Inject lateinit var webpageTool: WebpageTool
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ui.goPrivacyPolicy.setOnClickListener { webpageTool.open(PrivacyPolicy.URL) }
ui.continueAction.setOnClickListener { vm.finishOnboarding() }
super.onViewCreated(view, savedInstanceState)
}
}
@@ -0,0 +1,27 @@
package eu.darken.capod.main.ui.onboarding
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.uix.ViewModel3
import eu.darken.capod.main.core.GeneralSettings
import kotlinx.coroutines.flow.*
import javax.inject.Inject
@HiltViewModel
class OnboardingFragmentVM @Inject constructor(
@Suppress("UNUSED_PARAMETER") handle: SavedStateHandle,
private val dispatcherProvider: DispatcherProvider,
private val generalSettings: GeneralSettings,
) : ViewModel3(dispatcherProvider = dispatcherProvider) {
fun finishOnboarding() = launch {
generalSettings.isOnboardingDone.value = true
OnboardingFragmentDirections.actionOnboardingFragmentToOverviewFragment().navigate()
}
companion object {
val TAG = logTag("Onboarding", "Fragment", "VM")
}
}
@@ -11,7 +11,6 @@ import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.flow.combine
import eu.darken.capod.common.flow.throttleLatest
import eu.darken.capod.common.livedata.SingleLiveEvent
import eu.darken.capod.common.navigation.navVia
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.common.uix.ViewModel3
import eu.darken.capod.common.upgrade.UpgradeRepo
@@ -48,6 +47,12 @@ class OverviewFragmentVM @Inject constructor(
private val bluetoothManager: BluetoothManager2,
) : ViewModel3(dispatcherProvider = dispatcherProvider) {
init {
if (!generalSettings.isOnboardingDone.value) {
OverviewFragmentDirections.actionOverviewFragmentToOnboardingFragment().navigate()
}
}
val upgradeState = upgradeRepo.upgradeInfo.asLiveData2()
val launchUpgradeFlow = SingleLiveEvent<(Activity) -> Unit>()
@@ -124,7 +129,7 @@ class OverviewFragmentVM @Inject constructor(
items.add(0, BluetoothDisabledVH.Item)
} else if (mainPod == null) {
items.add(0, MissingMainDeviceVH.Item {
OverviewFragmentDirections.actionOverviewFragmentToTroubleShooterFragment().navVia(this)
OverviewFragmentDirections.actionOverviewFragmentToTroubleShooterFragment().navigate()
})
}
}
@@ -140,12 +145,14 @@ class OverviewFragmentVM @Inject constructor(
showDebug = isDebugMode,
isMainPod = isMainPod,
)
is SinglePodDevice -> SinglePodsCardVH.Item(
now = now,
device = it,
showDebug = isDebugMode,
isMainPod = isMainPod,
)
else -> UnknownPodDeviceCardVH.Item(
now = now,
device = it,
@@ -166,7 +173,7 @@ class OverviewFragmentVM @Inject constructor(
}
fun goToSettings() = launch {
OverviewFragmentDirections.actionOverviewFragmentToSettingsFragment().navVia(this@OverviewFragmentVM)
OverviewFragmentDirections.actionOverviewFragmentToSettingsFragment().navigate()
}
fun onUpgrade() = launch {
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="32dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/mascot"
android:layout_width="96dp"
android:layout_height="96dp"
android:layout_marginTop="48dp"
android:src="@drawable/splash_graphic2"
app:layout_constraintEnd_toEndOf="@id/title"
app:layout_constraintStart_toStartOf="@id/title"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.HeadlineLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/app_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/mascot" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/body1"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/onboarding_body1"
app:layout_constraintTop_toBottomOf="@id/title" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/body2"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/onboarding_body2"
app:layout_constraintTop_toBottomOf="@id/body1" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/body3"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/onboarding_body3"
app:layout_constraintTop_toBottomOf="@id/body2" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/body4"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/onboarding_body4"
app:layout_constraintTop_toBottomOf="@id/body3" />
<com.google.android.material.button.MaterialButton
android:id="@+id/go_privacy_policy"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="32dp"
android:text="@string/settings_privacy_policy_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/body4" />
<com.google.android.material.button.MaterialButton
android:id="@+id/continue_action"
style="@style/Widget.Material3.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="32dp"
android:text="@string/general_continue_action"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/go_privacy_policy" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
+11
View File
@@ -16,6 +16,9 @@
<action
android:id="@+id/action_overviewFragment_to_troubleShooterFragment"
app:destination="@id/troubleShooterFragment" />
<action
android:id="@+id/action_overviewFragment_to_onboardingFragment"
app:destination="@id/onboardingFragment" />
</fragment>
<fragment
@@ -27,5 +30,13 @@
android:id="@+id/troubleShooterFragment"
android:name="eu.darken.capod.troubleshooter.ui.TroubleShooterFragment"
tools:layout="@layout/troubleshooter_fragment" />
<fragment
android:id="@+id/onboardingFragment"
android:name="eu.darken.capod.main.ui.onboarding.OnboardingFragment"
tools:layout="@layout/onboarding_fragment">
<action
android:id="@+id/action_onboardingFragment_to_overviewFragment"
app:destination="@id/overviewFragment" />
</fragment>
</navigation>
+9
View File
@@ -119,4 +119,13 @@
<string name="troubleshooter_ble_result_failure_phone_headphones">Your phone received BLE data, but the data does not come from any supported device. Are your headphones powered on? Does CAPod support your headphone?</string>
<string name="troubleshooter_ble_result_failure_action">Try again</string>
<string name="troubleshoot_action">Troubleshoot</string>
<string name="onboarding_body1">This app adds support for AirPod specific features to Android.</string>
<string name="onboarding_body2">Not all Android devices fully support the extra AirPod features. Your operating system requires a correctly working Bluetooth-Low-Energy implemtation.</string>
<string name="onboarding_body3">CAPod has no ads and does not collect your data.</string>
<string name="onboarding_body4">You can upgrade to CAPod Pro to gain extra features and support development.</string>
<string name="general_continue_action">Continue</string>
</resources>