Skip to content

Commit

Permalink
Nicer onboarding
Browse files Browse the repository at this point in the history
  • Loading branch information
d4rken committed Sep 3, 2024
1 parent d692866 commit f02dee3
Show file tree
Hide file tree
Showing 15 changed files with 308 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package eu.darken.octi.common
import android.util.Log
import androidx.annotation.Keep
import java.lang.reflect.Field
import java.time.Instant


// Can't be const because that prevents them from being mocked in tests
Expand Down Expand Up @@ -41,8 +40,6 @@ object BuildConfigWrap {
;
}

val BUILD_TIME: Instant = Instant.parse(getBuildConfigValue("BUILDTIME") as String)

val VERSION_CODE: Long = (getBuildConfigValue("VERSION_CODE") as String).toLong()
val VERSION_NAME: String = getBuildConfigValue("VERSION_NAME") as String
val GIT_SHA: String = getBuildConfigValue("GITSHA") as String
Expand Down
7 changes: 4 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ plugins {
apply(plugin = "dagger.hilt.android.plugin")
apply(plugin = "androidx.navigation.safeargs.kotlin")

val commitHashProvider = providers.of(CommitHashValueSource::class) {}

android {
val packageName = ProjectConfig.packageName

Expand All @@ -26,8 +28,7 @@ android {
testInstrumentationRunner = "eu.darken.octi.HiltTestRunner"

buildConfigField("String", "PACKAGENAME", "\"${ProjectConfig.packageName}\"")
buildConfigField("String", "GITSHA", "\"${lastCommitHash()}\"")
buildConfigField("String", "BUILDTIME", "\"${buildTime()}\"")
buildConfigField("String", "GITSHA", "\"${commitHashProvider.get()}\"")
buildConfigField("String", "VERSION_CODE", "\"${ProjectConfig.Version.code}\"")
buildConfigField("String", "VERSION_NAME", "\"${ProjectConfig.Version.name}\"")
}
Expand Down Expand Up @@ -94,7 +95,7 @@ android {
if (listOf("release", "beta").any { variantName.toLowerCase().contains(it) }) {
val outputFileName = packageName +
"-v${defaultConfig.versionName}-${defaultConfig.versionCode}" +
"-${variantName.toUpperCase()}-${lastCommitHash()}.apk"
"-${variantName.toUpperCase()}.apk"

variantOutputImpl.outputFileName = outputFileName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class DashboardVM @Inject constructor(

init {
if (!generalSettings.isOnboardingDone.valueBlocking) {
DashboardFragmentDirections.actionDashFragmentToOnboardingFragment().navigate()
DashboardFragmentDirections.actionDashFragmentToWelcomeFragment().navigate()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package eu.darken.octi.main.ui.onboarding.ui
package eu.darken.octi.main.ui.onboarding.privacy

import android.os.Bundle
import android.view.View
Expand All @@ -9,21 +9,21 @@ import eu.darken.octi.common.PrivacyPolicy
import eu.darken.octi.common.WebpageTool
import eu.darken.octi.common.uix.Fragment3
import eu.darken.octi.common.viewbinding.viewBinding
import eu.darken.octi.databinding.OnboardingFragmentBinding
import eu.darken.octi.databinding.OnboardingPrivacyFragmentBinding
import javax.inject.Inject


@AndroidEntryPoint
class OnboardingFragment : Fragment3(R.layout.onboarding_fragment) {
class PrivacyFragment : Fragment3(R.layout.onboarding_privacy_fragment) {

override val vm: OnboardingFragmentVM by viewModels()
override val ui: OnboardingFragmentBinding by viewBinding()
override val vm: PrivacyFragmentVM by viewModels()
override val ui: OnboardingPrivacyFragmentBinding 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() }
ui.continueAction.setOnClickListener { vm.finishScreen() }
super.onViewCreated(view, savedInstanceState)
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
package eu.darken.octi.main.ui.onboarding.ui
package eu.darken.octi.main.ui.onboarding.privacy

import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.octi.common.coroutine.DispatcherProvider
import eu.darken.octi.common.datastore.value
import eu.darken.octi.common.debug.logging.logTag
import eu.darken.octi.common.uix.ViewModel3
import eu.darken.octi.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,
class PrivacyFragmentVM @Inject constructor(
dispatcherProvider: DispatcherProvider,
private val generalSettings: GeneralSettings,
) : ViewModel3(dispatcherProvider = dispatcherProvider) {

fun finishOnboarding() = launch {
fun finishScreen() = launch {
generalSettings.isOnboardingDone.value(true)
OnboardingFragmentDirections.actionOnboardingFragmentToDashFragment().navigate()
PrivacyFragmentDirections.actionPrivacyFragmentToDashFragment().navigate()
}

companion object {
val TAG = logTag("Onboarding", "Fragment", "VM")
val TAG = logTag("Onboarding", "Privacy", "Fragment", "VM")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package eu.darken.octi.main.ui.onboarding.welcome

import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
import eu.darken.octi.R
import eu.darken.octi.common.BuildConfigWrap
import eu.darken.octi.common.WebpageTool
import eu.darken.octi.common.uix.Fragment3
import eu.darken.octi.common.viewbinding.viewBinding
import eu.darken.octi.databinding.OnboardingWelcomeFragmentBinding
import javax.inject.Inject


@AndroidEntryPoint
class WelcomeFragment : Fragment3(R.layout.onboarding_welcome_fragment) {

override val vm: WelcomeFragmentVM by viewModels()
override val ui: OnboardingWelcomeFragmentBinding by viewBinding()

@Inject lateinit var webpageTool: WebpageTool

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ui.continueAction.setOnClickListener { vm.finishScreen() }
ui.betaHint.isVisible = BuildConfigWrap.BUILD_TYPE != BuildConfigWrap.BuildType.RELEASE
super.onViewCreated(view, savedInstanceState)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package eu.darken.octi.main.ui.onboarding.welcome

import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.octi.common.coroutine.DispatcherProvider
import eu.darken.octi.common.debug.logging.logTag
import eu.darken.octi.common.uix.ViewModel3
import javax.inject.Inject

@HiltViewModel
class WelcomeFragmentVM @Inject constructor(
dispatcherProvider: DispatcherProvider,
) : ViewModel3(dispatcherProvider = dispatcherProvider) {

fun finishScreen() = launch {
WelcomeFragmentDirections.actionWelcomeFragmentToPrivacyFragment().navigate()
}

companion object {
val TAG = logTag("Onboarding", "Welcome", "Fragment", "VM")
}
}
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_cellphone_arrow_down_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17,1H7A2,2 0 0,0 5,3V21A2,2 0 0,0 7,23H17A2,2 0 0,0 19,21V3A2,2 0 0,0 17,1M17,19H7V5H17V19M16,13H13V8H11V13H8L12,17L16,13Z" />
</vector>
140 changes: 140 additions & 0 deletions app/src/main/res/layout/onboarding_privacy_fragment.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<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="62dp"
android:src="@mipmap/ic_launcher_round"
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/subtitle"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_privacy_policy_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />


<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="32dp"
android:text="@string/onboarding_privacy_body1"
app:layout_constraintTop_toBottomOf="@id/subtitle" />


<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/description" />

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/update_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="?selectableItemBackground"
android:paddingHorizontal="16dp"
android:paddingVertical="16dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/go_privacy_policy"
tools:visibility="visible">

<ImageView
android:id="@+id/update_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_cellphone_arrow_down_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/update_title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/updatecheck_setting_enabled_label"
app:layout_constraintBottom_toTopOf="@id/update_description"
app:layout_constraintEnd_toStartOf="@id/update_toggle"
app:layout_constraintStart_toEndOf="@id/update_icon"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/update_description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/updatecheck_setting_enabled_explanation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/update_title"
app:layout_constraintStart_toStartOf="@id/update_title"
app:layout_constraintTop_toBottomOf="@id/update_title" />

<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/update_toggle"
style="@style/Widget.Material3.CompoundButton.MaterialSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:showText="false" />
</androidx.constraintlayout.widget.ConstraintLayout>

<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:layout_marginBottom="32dp"
android:text="@string/general_continue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/update_container" />
</androidx.constraintlayout.widget.ConstraintLayout>

</ScrollView>
Loading

0 comments on commit f02dee3

Please sign in to comment.