diff --git a/app-common/src/main/java/eu/darken/capod/common/uix/ViewModel3.kt b/app-common/src/main/java/eu/darken/capod/common/uix/ViewModel3.kt
index f5900376..794edafc 100644
--- a/app-common/src/main/java/eu/darken/capod/common/uix/ViewModel3.kt
+++ b/app-common/src/main/java/eu/darken/capod/common/uix/ViewModel3.kt
@@ -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)
+ }
}
\ No newline at end of file
diff --git a/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt b/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt
index a72b1f81..8c4afb3a 100644
--- a/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt
+++ b/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt
@@ -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,
diff --git a/app/src/main/java/eu/darken/capod/main/ui/onboarding/OnboardingFragment.kt b/app/src/main/java/eu/darken/capod/main/ui/onboarding/OnboardingFragment.kt
new file mode 100644
index 00000000..4a833311
--- /dev/null
+++ b/app/src/main/java/eu/darken/capod/main/ui/onboarding/OnboardingFragment.kt
@@ -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)
+ }
+}
diff --git a/app/src/main/java/eu/darken/capod/main/ui/onboarding/OnboardingFragmentVM.kt b/app/src/main/java/eu/darken/capod/main/ui/onboarding/OnboardingFragmentVM.kt
new file mode 100644
index 00000000..ee7ded2d
--- /dev/null
+++ b/app/src/main/java/eu/darken/capod/main/ui/onboarding/OnboardingFragmentVM.kt
@@ -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")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/darken/capod/main/ui/overview/OverviewFragmentVM.kt b/app/src/main/java/eu/darken/capod/main/ui/overview/OverviewFragmentVM.kt
index 15f05e6d..b7ea6900 100644
--- a/app/src/main/java/eu/darken/capod/main/ui/overview/OverviewFragmentVM.kt
+++ b/app/src/main/java/eu/darken/capod/main/ui/overview/OverviewFragmentVM.kt
@@ -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 {
diff --git a/app/src/main/res/layout/onboarding_fragment.xml b/app/src/main/res/layout/onboarding_fragment.xml
new file mode 100644
index 00000000..35957bc5
--- /dev/null
+++ b/app/src/main/res/layout/onboarding_fragment.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
index 3afaa438..29d4e403 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -16,6 +16,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 63fc1187..73228726 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -119,4 +119,13 @@
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?
Try again
Troubleshoot
+
+
+ This app adds support for AirPod specific features to Android.
+ Not all Android devices fully support the extra AirPod features. Your operating system requires a correctly working Bluetooth-Low-Energy implemtation.
+ CAPod has no ads and does not collect your data.
+ You can upgrade to CAPod Pro to gain extra features and support development.
+
+ Continue
+
\ No newline at end of file