From 600954fdc393e3020fd716496aa5ad03c2cd95d7 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Tue, 14 Jun 2022 14:39:16 +0200 Subject: [PATCH] Improve login flow --- .../habitica/extensions/Int-Extensions.kt | 10 ++ wearos/build.gradle | 2 +- .../habitica/ui/activities/BaseActivity.kt | 33 ++++++- .../habitica/ui/activities/SplashActivity.kt | 36 +++----- .../habitica/ui/viewmodels/SplashViewModel.kt | 6 +- .../ui/views/IndeterminateProgressView.kt | 86 ++++++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 18 ++++ wearos/src/main/res/layout/activity_login.xml | 4 +- .../src/main/res/layout/activity_wrapper.xml | 7 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 1404 -> 1420 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 3014 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 982 -> 876 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1958 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 1900 -> 1942 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 4272 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 2884 -> 2866 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 6630 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 3844 -> 3694 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 9132 bytes wearos/src/main/res/values/colors.xml | 4 + wearos/src/main/res/values/styles.xml | 2 +- 23 files changed, 189 insertions(+), 29 deletions(-) create mode 100644 wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt create mode 100644 wearos/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 wearos/src/main/res/layout/activity_wrapper.xml create mode 100644 wearos/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 wearos/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 wearos/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 wearos/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 wearos/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 wearos/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 wearos/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 wearos/src/main/res/values/colors.xml diff --git a/common/src/main/java/com/habitrpg/common/habitica/extensions/Int-Extensions.kt b/common/src/main/java/com/habitrpg/common/habitica/extensions/Int-Extensions.kt index 4edd72bff..9ea5e7366 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/extensions/Int-Extensions.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/extensions/Int-Extensions.kt @@ -6,3 +6,13 @@ fun Int.dpToPx(context: Context?): Int { val displayMetrics = context?.resources?.displayMetrics return ((this * (displayMetrics?.density ?: 1.0f)) + 0.5).toInt() } + +fun Float.dpToPx(context: Context?): Float { + val displayMetrics = context?.resources?.displayMetrics + return ((this * (displayMetrics?.density ?: 1.0f)) + 0.5).toFloat() +} + +fun Double.dpToPx(context: Context?): Double { + val displayMetrics = context?.resources?.displayMetrics + return ((this * (displayMetrics?.density ?: 1.0f)) + 0.5) +} \ No newline at end of file diff --git a/wearos/build.gradle b/wearos/build.gradle index 306a1a394..2e02a5ebe 100644 --- a/wearos/build.gradle +++ b/wearos/build.gradle @@ -55,7 +55,7 @@ dependencies { } implementation("com.squareup.retrofit2:converter-moshi:$retrofit_version") implementation("com.squareup.moshi:moshi-kotlin:$moshi_version") - implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' kapt("com.squareup.moshi:moshi-kotlin-codegen:$moshi_version") //Analytics diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt index 707eae5f0..a69916541 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/BaseActivity.kt @@ -2,18 +2,28 @@ package com.habitrpg.wearos.habitica.ui.activities import android.content.Intent import android.os.Bundle +import android.view.ViewGroup +import android.widget.FrameLayout import androidx.activity.ComponentActivity +import androidx.core.view.children import androidx.viewbinding.ViewBinding import androidx.wear.activity.ConfirmationActivity +import com.habitrpg.android.habitica.databinding.ActivityWrapperBinding import com.habitrpg.wearos.habitica.ui.viewmodels.BaseViewModel +import com.habitrpg.wearos.habitica.ui.views.IndeterminateProgressView abstract class BaseActivity : ComponentActivity() { + private lateinit var wrapperBinding: ActivityWrapperBinding protected lateinit var binding: B abstract val viewModel: VM + private var progressView: IndeterminateProgressView? = null + override fun onCreate(savedInstanceState: Bundle?) { + wrapperBinding = ActivityWrapperBinding.inflate(layoutInflater) super.onCreate(savedInstanceState) - setContentView(binding.root) + wrapperBinding.root.addView(binding.root) + setContentView(wrapperBinding.root) viewModel.errorValues.observe(this) { val intent = Intent(this, ConfirmationActivity::class.java).apply { @@ -24,4 +34,25 @@ abstract class BaseActivity : ComponentActivi startActivity(intent) } } + + fun startAnimatingProgress() { + if (progressView == null) { + progressView = IndeterminateProgressView(this) + wrapperBinding.root.addView(progressView) + progressView?.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + progressView?.startAnimation() + } + } + + fun stopAnimatingProgress() { + if (progressView != null) { + wrapperBinding.root.removeView(progressView) + } else { + wrapperBinding.root.children.forEach { + if (it is IndeterminateProgressView) { + wrapperBinding.root.removeView(it) + } + } + } + } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt index 87804c598..2ceb23896 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/SplashActivity.kt @@ -26,6 +26,7 @@ class SplashActivity: BaseActivity() { super.onCreate(savedInstanceState) if (viewModel.hasAuthentication) { startMainActivity() + return } viewModel.onLoginCompleted = { @@ -36,9 +37,17 @@ class SplashActivity: BaseActivity() { } } - viewModel.showAccountLoader.observe(this) { - binding.progressBar.isVisible = it - binding.textView.isVisible = it + messageClient.addListener(viewModel) + lifecycleScope.launch(Dispatchers.IO) { + val info = Tasks.await(capabilityClient.getCapability("provide_auth", CapabilityClient.FILTER_REACHABLE)) + val nodeID = info.nodes.firstOrNull { it.isNearby } + if (nodeID != null) { + showAccountLoader(true) + Tasks.await(messageClient.sendMessage(nodeID.id, "/request/auth", null)) + } else { + showAccountLoader(false) + startLoginActivity() + } } } @@ -54,24 +63,9 @@ class SplashActivity: BaseActivity() { finish() } - private fun requestAuthenticationData(nodeID: String) { - Tasks.await(messageClient.sendMessage(nodeID, "/request/auth", null).apply { - addOnSuccessListener { - - } - }) - } - - override fun onResume() { - super.onResume() - messageClient.addListener(viewModel) - lifecycleScope.launch(Dispatchers.IO) { - val info = Tasks.await(capabilityClient.getCapability("provide_auth", CapabilityClient.FILTER_REACHABLE)) - val nodeID = info.nodes.firstOrNull { it.isNearby } - if (nodeID != null) { - requestAuthenticationData(nodeID.id) - } - } + private fun showAccountLoader(show: Boolean) { + binding.progressBar.isVisible = show + binding.textView.isVisible = show } override fun onPause() { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/SplashViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/SplashViewModel.kt index 0f8b7136a..a6fb1f105 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/SplashViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/SplashViewModel.kt @@ -2,7 +2,6 @@ package com.habitrpg.wearos.habitica.ui.viewmodels import android.content.SharedPreferences import androidx.core.content.edit -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.google.android.gms.wearable.MessageClient import com.google.android.gms.wearable.MessageEvent @@ -24,9 +23,6 @@ class SplashViewModel @Inject constructor(userRepository: UserRepository, val keyHelper: KeyHelper? ) : BaseViewModel(userRepository, exceptionBuilder), MessageClient.OnMessageReceivedListener { lateinit var onLoginCompleted: (Boolean) -> Unit - - val showAccountLoader = MutableLiveData(false) - val hasAuthentication: Boolean get() { return hostConfig.hasAuthentication() @@ -44,6 +40,8 @@ class SplashViewModel @Inject constructor(userRepository: UserRepository, try { saveTokens(apiKey, userID) } catch (e: Exception) { + onLoginCompleted(false) + return@launch } retrieveUser() onLoginCompleted(true) diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt new file mode 100644 index 000000000..aa9c02f12 --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/IndeterminateProgressView.kt @@ -0,0 +1,86 @@ +package com.habitrpg.wearos.habitica.ui.views + +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Canvas +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.SweepGradient +import android.util.AttributeSet +import android.view.View +import android.view.animation.Animation +import android.view.animation.LinearInterpolator +import androidx.core.content.ContextCompat +import com.habitrpg.android.habitica.R +import com.habitrpg.common.habitica.extensions.dpToPx + +class IndeterminateProgressView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + + var progressBarWidth = 4f.dpToPx(context) + + private val rainbow = listOf( + ContextCompat.getColor(context, R.color.red_100), + ContextCompat.getColor(context, R.color.orange_100), + ContextCompat.getColor(context, R.color.yellow_100), + ContextCompat.getColor(context, R.color.green_100), + ContextCompat.getColor(context, R.color.blue_100), + ContextCompat.getColor(context, R.color.brand_400), + ContextCompat.getColor(context, R.color.red_100), + ).toIntArray() + val gradient = SweepGradient(225f, 225f, rainbow, null) + private val paint = Paint() + private val isCircular: Boolean + private val cornerRadius = 12f.dpToPx(context) + + private var currentAngle = 0f + + init { + paint.style = Paint.Style.STROKE + paint.shader = gradient + paint.strokeWidth = 0f + paint.isAntiAlias = true + setWillNotDraw(false) + isCircular = context.resources.configuration.isScreenRound + } + + private var animator: ValueAnimator? = null + fun startAnimation() { + animator = ValueAnimator.ofFloat(0f, 359f).apply { + duration = 2000 + repeatCount = Animation.INFINITE + repeatMode = ValueAnimator.RESTART + interpolator = LinearInterpolator() + addUpdateListener { + val matrix = Matrix() + matrix.postRotate(it.animatedValue as Float, 225f, 225f) + gradient.setLocalMatrix(matrix) + invalidate() + requestLayout() + } + start() + } + ValueAnimator.ofFloat(0f, progressBarWidth).apply { + duration = 200 + addUpdateListener { paint.strokeWidth = it.animatedValue as Float } + start() + } + } + + fun stopAnimation() { + animator?.end() + animator = null + } + + override fun onDraw(canvas: Canvas?) { + super.onDraw(canvas) + if (canvas == null) return + val halfBar = paint.strokeWidth / 2f + if (isCircular) { + canvas.drawArc(halfBar, halfBar, width.toFloat() - halfBar, height.toFloat() - halfBar, currentAngle, 360f, false, paint) + } else { + canvas.drawRoundRect(halfBar, halfBar, width.toFloat() - halfBar, height.toFloat() - halfBar, cornerRadius, cornerRadius, paint) + } + } +} \ No newline at end of file diff --git a/wearos/src/main/res/drawable/ic_launcher_foreground.xml b/wearos/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..4fc0d90b9 --- /dev/null +++ b/wearos/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,18 @@ + + + + diff --git a/wearos/src/main/res/layout/activity_login.xml b/wearos/src/main/res/layout/activity_login.xml index d5d7f8c1e..e813ce2ac 100644 --- a/wearos/src/main/res/layout/activity_login.xml +++ b/wearos/src/main/res/layout/activity_login.xml @@ -18,13 +18,15 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textEmailAddress" + android:hint="@string/username" android:autofillHints="username" /> -