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