App flow improvements

This commit is contained in:
Phillip Thelen 2022-06-10 15:29:49 +02:00
parent c93b5124c1
commit 12b760131e
21 changed files with 245 additions and 30 deletions

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#ffffff</color>
<color name="black">#000000</color>
<color name="brand_50">#36205D</color>
<color name="brand_100">#432874</color>

View file

@ -42,5 +42,9 @@
<string name="login_validation_error_title">Validation Error</string>
<string name="login_validation_error_fieldsmissing">You have to fill out all fields.</string>
<string name="x_habits">%d Habits</string>
<string name="x_dailies">%d Dailies</string>
<string name="x_todos">%d To do\'s</string>
<string name="x_rewards">%d Rewards</string>
</resources>

View file

@ -25,10 +25,12 @@ android {
applicationIdSuffix ".debug"
ext.enableCrashlytics = false
ext.alwaysUpdateBuildId = false
resValue "string", "app_name", "Habitica Debug"
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
resValue "string", "app_name", "Habitica"
}
}
buildFeatures {
@ -53,6 +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'
kapt("com.squareup.moshi:moshi-kotlin-codegen:$moshi_version")
//Analytics

View file

@ -12,7 +12,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:name="com.habitrpg.wearos.habitica.MainApplication"
android:theme="@style/Theme.AppCompat.NoActionBar">
android:theme="@style/HabiticaAppTheme">
<uses-library
android:name="com.google.android.wearable"
android:required="true" />

View file

@ -7,6 +7,7 @@ data class MenuItem(
val title: String,
val icon: Drawable?,
val color: Int,
val textColor: Int,
val isProminent: Boolean = false,
val onClick: () -> Unit
)

View file

@ -6,9 +6,9 @@ import androidx.activity.viewModels
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.wear.widget.WearableLinearLayoutManager
import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ActivityMainBinding
import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.wearos.habitica.models.MenuItem
import com.habitrpg.wearos.habitica.ui.adapters.HubAdapter
import com.habitrpg.wearos.habitica.ui.viewmodels.MainViewModel
@ -38,6 +38,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
getString(R.string.new_task),
AppCompatResources.getDrawable(this, R.drawable.icon_plus),
ContextCompat.getColor(this, R.color.brand_400),
ContextCompat.getColor(this, R.color.black),
true
) {
openTaskFormActivity()
@ -46,7 +47,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"habits",
getString(R.string.habits),
AppCompatResources.getDrawable(this, R.drawable.icon_habits),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openTasklist(TaskType.HABIT)
},
@ -54,7 +56,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"dailies",
getString(R.string.dailies),
AppCompatResources.getDrawable(this, R.drawable.icon_dailies),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openTasklist(TaskType.DAILY)
},
@ -62,7 +65,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"todos",
getString(R.string.todos),
AppCompatResources.getDrawable(this, R.drawable.icon_todos),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openTasklist(TaskType.TODO)
},
@ -70,7 +74,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"rewards",
getString(R.string.rewards),
AppCompatResources.getDrawable(this, R.drawable.icon_rewards),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openTasklist(TaskType.REWARD)
},
@ -78,7 +83,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"Stats",
getString(R.string.stats),
AppCompatResources.getDrawable(this, R.drawable.icon_stats),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openStatsActivity()
},
@ -86,7 +92,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"avatar",
getString(R.string.avatar),
AppCompatResources.getDrawable(this, R.drawable.icon_avatar),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openAvatarActivity()
},
@ -94,7 +101,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
"settings",
getString(R.string.settings),
AppCompatResources.getDrawable(this, R.drawable.icon_settings),
ContextCompat.getColor(this, R.color.brand_400)
ContextCompat.getColor(this, R.color.brand_500),
ContextCompat.getColor(this, R.color.brand_700)
) {
openSettingsActivity()
}

View file

@ -3,6 +3,7 @@ package com.habitrpg.wearos.habitica.ui.activities
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.tasks.Tasks
import com.google.android.gms.wearable.CapabilityClient
@ -34,18 +35,23 @@ class SplashActivity: BaseActivity<ActivitySplashBinding, SplashViewModel>() {
startLoginActivity()
}
}
viewModel.showAccountLoader.observe(this) {
binding.progressBar.isVisible = it
binding.textView.isVisible = it
}
}
private fun startMainActivity() {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
}
private fun startLoginActivity() {
val intent = Intent(this, LoginActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
}
private fun requestAuthenticationData(nodeID: String) {

View file

@ -1,15 +1,20 @@
package com.habitrpg.wearos.habitica.ui.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.AttributeSet
import android.view.View
import androidx.activity.viewModels
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.wear.activity.ConfirmationActivity
import androidx.wear.widget.WearableLinearLayoutManager
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ActivityTasklistBinding
import com.habitrpg.common.habitica.models.responses.TaskDirection
import com.habitrpg.common.habitica.models.responses.TaskScoringResult
import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ActivityTasklistBinding
import com.habitrpg.wearos.habitica.models.tasks.Task
import com.habitrpg.wearos.habitica.ui.adapters.DailyListAdapter
import com.habitrpg.wearos.habitica.ui.adapters.HabitListAdapter
@ -19,6 +24,8 @@ import com.habitrpg.wearos.habitica.ui.adapters.ToDoListAdapter
import com.habitrpg.wearos.habitica.ui.viewmodels.TaskListViewModel
import com.habitrpg.wearos.habitica.util.HabiticaScrollingLayoutCallback
import dagger.hilt.android.AndroidEntryPoint
import java.lang.Float.max
import java.lang.Float.min
@AndroidEntryPoint
class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>() {
@ -29,7 +36,7 @@ class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>
binding = ActivityTasklistBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
configureAdapter()
binding.root.apply {
binding.recyclerView.apply {
layoutManager =
WearableLinearLayoutManager(this@TaskListActivity, HabiticaScrollingLayoutCallback())
adapter = this@TaskListActivity.adapter
@ -37,11 +44,14 @@ class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>
viewModel.tasks.observe(this) {
adapter.data = it
adapter.title = getTitle(it.size)
}
adapter.onTaskScore = {
scoreTask(it)
}
binding.addTaskButton.setOnClickListener { }
}
private fun scoreTask(task: Task) {
@ -71,25 +81,78 @@ class TaskListActivity: BaseActivity<ActivityTasklistBinding, TaskListViewModel>
startActivity(intent)
}
private fun openTaskFormActivity() {
startActivity(Intent(this, TaskFormActivity::class.java))
}
private fun configureAdapter() {
when (viewModel.taskType) {
TaskType.HABIT -> {
adapter = HabitListAdapter()
adapter.title = getString(R.string.habits)
}
TaskType.DAILY -> {
adapter = DailyListAdapter()
adapter.title = getString(R.string.dailies)
}
TaskType.TODO -> {
adapter = ToDoListAdapter()
adapter.title = getString(R.string.todos)
}
TaskType.REWARD -> {
adapter = RewardListAdapter()
adapter.title = getString(R.string.rewards)
}
else -> {}
}
adapter.title = getTitle(null)
}
private fun getTitle(count: Int?): String {
val taskType = viewModel.taskType ?: return ""
return if (count != null) {
when (taskType) {
TaskType.HABIT -> getString(R.string.x_habits, count)
TaskType.DAILY -> getString(R.string.x_dailies, count)
TaskType.TODO -> getString(R.string.x_todos, count)
TaskType.REWARD -> getString(R.string.x_rewards, count)
}
} else {
when (taskType) {
TaskType.HABIT -> getString(R.string.habits)
TaskType.DAILY -> getString(R.string.dailies)
TaskType.TODO -> getString(R.string.todos)
TaskType.REWARD -> getString(R.string.rewards)
}
}
}
}
class ScrollAwayBehavior<V : View>(context: Context, attrs: AttributeSet) :
CoordinatorLayout.Behavior<V>(context, attrs) {
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int
): Boolean {
return axes == ViewCompat.SCROLL_AXIS_VERTICAL
}
override fun onNestedPreScroll(
coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int
) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
child.translationY = max(0f, min(child.height.toFloat(), child.translationY + dy))
}
override fun onStopNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: V,
target: View,
type: Int
) {
super.onStopNestedScroll(coordinatorLayout, child, target, type)
if (child.translationY != 0f && child.translationY != child.height.toFloat()) {
if (child.translationY < (child.height.toFloat() / 2f)) {
child.translationY = 0f
} else {
child.translationY = child.height.toFloat()
}
}
}
}

View file

@ -12,9 +12,10 @@ class HubViewHolder(itemView: View): BindableViewHolder<MenuItem>(itemView) {
override fun bind(data: MenuItem) {
binding.title.text = data.title
binding.title.setTextColor(data.textColor)
binding.iconView.setImageDrawable(data.icon)
if (data.isProminent) {
binding.iconView.setColorFilter(ContextCompat.getColor(itemView.context, R.color.white))
binding.iconView.setColorFilter(ContextCompat.getColor(itemView.context, R.color.black))
binding.rowContainer.backgroundTintList = ColorStateList.valueOf(data.color)
} else {
binding.iconView.setColorFilter(data.color)

View file

@ -2,6 +2,7 @@ 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,6 +25,8 @@ class SplashViewModel @Inject constructor(userRepository: UserRepository,
) : BaseViewModel(userRepository, exceptionBuilder), MessageClient.OnMessageReceivedListener {
lateinit var onLoginCompleted: (Boolean) -> Unit
val showAccountLoader = MutableLiveData(false)
val hasAuthentication: Boolean
get() {
return hostConfig.hasAuthentication()

View file

@ -0,0 +1,58 @@
package com.habitrpg.wearos.habitica.ui.views
import android.content.Context
import android.graphics.Canvas
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.Shader
import android.util.AttributeSet
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ButtonAddTaskBinding
import com.habitrpg.common.habitica.extensions.dpToPx
import com.habitrpg.common.habitica.extensions.layoutInflater
class AddTaskButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
val binding = ButtonAddTaskBinding.inflate(context.layoutInflater, this)
private val paint = Paint()
private val gradient = LinearGradient(
0f,
0f,
0f,
80.dpToPx(context).toFloat(),
ContextCompat.getColor(context, R.color.brand_400),
ContextCompat.getColor(context, R.color.blue_100),
Shader.TileMode.CLAMP
)
private val path = Path()
private val rect = RectF(0f, 0f, 0f, 0f)
init {
paint.style = Paint.Style.FILL_AND_STROKE
paint.shader = gradient
paint.isAntiAlias = true
setWillNotDraw(false)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
rect.right = bottom.toFloat()
rect.bottom = bottom.toFloat() / 2f
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas == null) return
path.reset()
path.addArc(rect, 180f, 360f)
canvas.drawPath(path, paint)
}
}

View file

@ -10,7 +10,7 @@ class HabiticaRecyclerView @JvmOverloads constructor(
override fun onAttachedToWindow() {
super.onAttachedToWindow()
post {
setPaddingRelative(0, (height * 0.15).toInt(), 0, (height * 0.25).toInt())
setPaddingRelative(0, (height * 0.06).toInt(), 0, (height * 0.25).toInt())
scrollToPosition(0)
}
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="12dp"
android:viewportHeight="12"
android:viewportWidth="24">
<path
android:fillColor="@color/brand_400"
android:pathData="M0,12
A12,4 0 1,1 24,12" />
</vector>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@drawable/avatar_cutout"
android:clipChildren="true"
android:clipToOutline="true"
android:outlineProvider="background"
android:clipToPadding="true">
<com.habitrpg.common.habitica.views.AvatarView
android:id="@+id/avatar_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
</FrameLayout>

View file

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activities.MainActivity"
tools:context="com.habitrpg.wearos.habitica.ui.activities.MainActivity"
android:scrollbars="vertical"
tools:deviceIds="wear">

View file

@ -2,6 +2,17 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/syncing_account"
android:visibility="gone"/>
</LinearLayout>

View file

@ -1,8 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<com.habitrpg.wearos.habitica.ui.views.HabiticaRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:scrollbars="vertical">
</com.habitrpg.wearos.habitica.ui.views.HabiticaRecyclerView>
<com.habitrpg.wearos.habitica.ui.views.HabiticaRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<com.habitrpg.wearos.habitica.ui.views.AddTaskButton
android:id="@+id/add_task_button"
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_gravity="center|bottom"
app:layout_behavior="com.habitrpg.wearos.habitica.ui.activities.ScrollAwayBehavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="android.widget.FrameLayout">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_plus"
android:layout_gravity="center"
/>
</merge>

View file

@ -4,13 +4,13 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/spacing_medium">
android:padding="6dp">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/gray_300"
android:textColor="@color/brand_500"
tools:text="Header Text"
android:fontFamily="sans-serif-medium"
android:textSize="16sp" />

View file

@ -1,4 +1,4 @@
<resources>
<string name="app_name">Habitica</string>
<string name="ok">OK</string>
<string name="syncing_account">Syncing Account from Phone</string>
</resources>

View file

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="HabiticaAppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@color/black</item>
</style>
<style name="Chip">
<item name="android:layout_marginVertical">@dimen/row_spacing</item>
<item name="android:layout_marginHorizontal">@dimen/row_side_spacing</item>