more colors

This commit is contained in:
Phillip Thelen 2022-11-17 19:01:54 +01:00
parent 2ea1096622
commit 95c78d12e1
7 changed files with 230 additions and 91 deletions

View file

@ -107,6 +107,8 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation "com.google.android.material:compose-theme-adapter:1.1.21"
implementation "androidx.compose.material3:material3:1.0.1"
implementation "com.google.accompanist:accompanist-systemuicontroller:0.27.1"
implementation 'androidx.activity:activity-compose:1.6.1'
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

View file

@ -156,6 +156,32 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
}
}
val lightestTaskColor: Int
get() {
return when {
this.value < -20 -> return R.color.maroon_700
this.value < -10 -> return R.color.red_700
this.value < -1 -> return R.color.orange_700
this.value < 1 -> return R.color.yellow_700
this.value < 5 -> return R.color.green_700
this.value < 10 -> return R.color.teal_700
else -> R.color.blue_700
}
}
val extraExtraLightTaskColor: Int
get() {
return when {
this.value < -20 -> return R.color.maroon_600
this.value < -10 -> return R.color.red_600
this.value < -1 -> return R.color.orange_600
this.value < 1 -> return R.color.yellow_600
this.value < 5 -> return R.color.green_600
this.value < 10 -> return R.color.teal_600
else -> R.color.blue_600
}
}
val extraLightTaskColor: Int
get() {
return when {

View file

@ -1,14 +1,13 @@
package com.habitrpg.android.habitica.ui.activities
import android.os.Bundle
import android.view.Window
import android.view.WindowManager
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
@ -18,30 +17,37 @@ import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.TaskDescriptionBuilder
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel
import com.habitrpg.common.habitica.helpers.MarkdownParser
import com.habitrpg.shared.habitica.models.tasks.TaskType
import java.text.DateFormat
import javax.inject.Inject
@ -56,34 +62,33 @@ class TaskSummaryViewModel(val taskId: String) : BaseViewModel() {
}
@Suppress("UNCHECKED_CAST")
class Factory(private val taskID: String): ViewModelProvider.Factory {
class Factory(private val taskID: String) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return TaskSummaryViewModel(taskID) as T
}
}
}
class TaskSummaryActivity: BaseActivity() {
class TaskSummaryActivity : BaseActivity() {
override fun getLayoutResId(): Int? = null
private val viewModel: TaskSummaryViewModel by viewModels { TaskSummaryViewModel.Factory(intent.extras?.getString(
TaskFormActivity.TASK_ID_KEY
) ?: "") }
private val viewModel: TaskSummaryViewModel by viewModels {
TaskSummaryViewModel.Factory(
intent.extras?.getString(
TaskFormActivity.TASK_ID_KEY
) ?: ""
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TaskSummaryView(viewModel = viewModel)
HabiticaTheme {
TaskSummaryView(viewModel = viewModel)
}
}
}
override fun onStart() {
super.onStart()
val window: Window = window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = ContextCompat.getColor(this, viewModel.task.value?.lightTaskColor ?: R.color.brand_300)
}
override fun injectActivity(component: UserComponent?) {
component?.inject(this)
}
@ -95,103 +100,195 @@ fun TaskSummaryView(viewModel: TaskSummaryViewModel) {
val task by viewModel.task.observeAsState()
val titleModifier = Modifier.padding(top = 30.dp)
val textModifier = Modifier.padding(top = 4.dp)
val completedTimeFormat = DateFormat.getTimeInstance()
val darkestColor = colorResource(task?.darkestTaskColor ?: R.color.text_primary)
Column(Modifier.background(colorResource(task?.lightTaskColor ?: R.color.brand_300))) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(0.dp, 4.dp)) {
Button(onClick = {
MainNavigationController.navigateBack()
}, colors = ButtonDefaults.textButtonColors(contentColor = darkestColor), elevation = ButtonDefaults.elevation(0.dp)) {
Image(painterResource(R.drawable.ic_arrow_back_white_36dp), stringResource(R.string.action_back), colorFilter = ColorFilter.tint(colorResource(task?.darkestTaskColor ?: R.color.white)))
}
Text(
stringResource(R.string.task_summary),
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
color = darkestColor,
modifier = Modifier.padding(start = 6.dp)
)
val completedTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT)
if (task != null) {
val darkestColor = colorResource(task?.darkestTaskColor ?: R.color.text_primary)
val systemUiController = rememberSystemUiController()
val statusBarColor = colorResource(task?.lightTaskColor ?: R.color.brand_400)
val lightestColor = colorResource(task?.lightestTaskColor ?: R.color.window_background)
DisposableEffect(systemUiController) {
systemUiController.setStatusBarColor(statusBarColor, darkIcons = true)
systemUiController.setNavigationBarColor(lightestColor)
onDispose {}
}
Column(
Modifier
.background(
MaterialTheme.colors.background,
RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)
)
.padding(20.dp, 5.dp)
.fillMaxWidth()) {
Text(stringResource(R.string.title), fontSize = 16.sp, color = darkestColor, fontWeight = FontWeight.Medium, modifier = titleModifier)
Text(task?.text ?: "", fontSize = 16.sp, color = MaterialTheme.colors.onBackground, modifier = textModifier)
if (task?.notes?.isNotBlank() == true) {
Column(Modifier.background(colorResource(task?.lightTaskColor ?: R.color.brand_300))) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(vertical = 2.dp)
) {
Button(
onClick = {
MainNavigationController.navigateBack()
},
colors = ButtonDefaults.textButtonColors(contentColor = darkestColor),
elevation = ButtonDefaults.elevation(0.dp)
) {
Image(
painterResource(R.drawable.arrow_back),
stringResource(R.string.action_back),
colorFilter = ColorFilter.tint(
colorResource(
task?.darkestTaskColor ?: R.color.white
)
)
)
}
Text(
stringResource(R.string.notes),
fontSize = 16.sp,
color = MaterialTheme.colors.onSecondary,
stringResource(R.string.task_summary),
fontSize = 18.sp,
fontWeight = FontWeight.Medium,
modifier = titleModifier
)
Text(
task?.notes ?: "",
fontSize = 16.sp,
color = MaterialTheme.colors.onBackground,
modifier = textModifier
color = darkestColor,
modifier = Modifier.padding(start = 0.dp)
)
}
if (task?.type != TaskType.REWARD) {
Column(
Modifier
.shadow(16.dp)
.background(
lightestColor,
RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)
)
.padding(20.dp, 5.dp)
.fillMaxWidth()
.fillMaxHeight()
) {
Text(
stringResource(R.string.description),
stringResource(R.string.title),
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Medium,
modifier = titleModifier
)
Text(MarkdownParser.parseMarkdown(task?.let { taskDescriptionBuilder.describe(it) } ?: "").toString(),
fontSize = 16.sp,
color = MaterialTheme.colors.onBackground,
modifier = textModifier)
}
if (task?.checklist?.isNotEmpty() == true) {
task?.checklist?.let { checklist ->
Text(stringResource(R.string.checklist), fontSize = 16.sp, color = darkestColor, fontWeight = FontWeight.Medium, modifier = titleModifier)
for (item in checklist) {
Text(item.text ?: "", fontSize = 16.sp, fontWeight = FontWeight.Medium, modifier = Modifier
.background(colorResource(R.color.gray_700))
.padding(15.dp)
.fillMaxWidth())
Text(
task?.text ?: "", fontSize = 16.sp, color = darkestColor,
fontWeight = FontWeight.Normal, modifier = textModifier
)
if (task?.notes?.isNotBlank() == true) {
Text(
stringResource(R.string.notes),
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Medium,
modifier = titleModifier
)
Text(
task?.notes ?: "",
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Normal,
modifier = textModifier
)
}
if (task?.type != TaskType.REWARD) {
Text(
stringResource(R.string.description),
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Medium,
modifier = titleModifier
)
Text(task?.let { taskDescriptionBuilder.describe(it) }!!.makeBoldComposable(),
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Normal,
modifier = textModifier)
}
if (task?.checklist?.isNotEmpty() == true) {
task?.checklist?.let { checklist ->
Text(
stringResource(R.string.checklist),
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Medium,
modifier = titleModifier.padding(bottom = 4.dp)
)
for (item in checklist) {
Text(
item.text ?: "",
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
color = darkestColor,
modifier = Modifier
.padding(vertical = 4.dp)
.background(
colorResource(
task?.extraExtraLightTaskColor ?: R.color.gray_700
),
RoundedCornerShape(8.dp)
)
.padding(15.dp)
.fillMaxWidth()
)
}
}
}
}
if (task?.group?.assignedUsersDetail?.isNotEmpty() == true) {
Text(stringResource(R.string.assigned_to), fontSize = 16.sp, color = darkestColor, fontWeight = FontWeight.Medium, modifier = titleModifier.padding(bottom = 4.dp))
for (item in task?.group?.assignedUsersDetail ?: emptyList()) {
UserRow(item.assignedUsername ?: "", Modifier
.padding(vertical = 4.dp)
.background(colorResource(R.color.gray_700), RoundedCornerShape(8.dp))
.padding(15.dp, 12.dp)
.heightIn(min = 24.dp)
.fillMaxWidth(),
extraContent = if (item.completed) ({
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 4.dp)) {
Image(painterResource(R.drawable.completed), null)
Text(stringResource(R.string.completed_at,
item.completedDate?.let { completedTimeFormat.format(it) } ?: ""),
fontSize = 14.sp,
color = colorResource(R.color.green_10), modifier = Modifier.padding(start = 4.dp))
}
}) else null)
if (task?.group?.assignedUsersDetail?.isNotEmpty() == true) {
Text(
stringResource(R.string.assigned_to),
fontSize = 16.sp,
color = darkestColor,
fontWeight = FontWeight.Medium,
modifier = titleModifier.padding(bottom = 4.dp)
)
for (item in task?.group?.assignedUsersDetail ?: emptyList()) {
UserRow(
item.assignedUsername ?: "", Modifier
.padding(vertical = 4.dp)
.background(
colorResource(
task?.extraExtraLightTaskColor ?: R.color.gray_700
),
RoundedCornerShape(8.dp)
)
.padding(15.dp, 12.dp)
.heightIn(min = 24.dp)
.fillMaxWidth(),
color = darkestColor,
extraContent = if (item.completed) ({
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(top = 4.dp)
) {
Image(painterResource(R.drawable.completed), null)
Text(stringResource(R.string.completed_at,
item.completedDate?.let { completedTimeFormat.format(it) }
?: ""),
fontSize = 14.sp,
color = colorResource(R.color.green_10),
modifier = Modifier.padding(start = 4.dp))
}
}) else null
)
}
}
}
}
}
}
private fun String.makeBoldComposable(): AnnotatedString {
return buildAnnotatedString {
var isBold = false
for (segment in split("**")) {
withStyle(style = SpanStyle(fontWeight = if (isBold) FontWeight.SemiBold else FontWeight.Normal)) {
append(segment)
}
isBold = !isBold
}
}
}
@Composable
fun UserRow(username: String, modifier: Modifier = Modifier, extraContent: @Composable (() -> Unit)? = null) {
fun UserRow(
username: String,
modifier: Modifier = Modifier,
extraContent: @Composable (() -> Unit)? = null,
color: Color? = null
) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
Column {
Text(
"@$username", fontSize = 16.sp, fontWeight = FontWeight.Medium, modifier = Modifier
.background(colorResource(R.color.gray_700))
"@$username", fontSize = 16.sp, fontWeight = FontWeight.Medium, color = color ?: MaterialTheme.colors.primary, modifier = Modifier
.fillMaxWidth()
)
if (extraContent != null) {

View file

@ -16,6 +16,8 @@
<color name="brand">@color/brand_100</color>
<!-- HabitRPG task color -->
<color name="maroon_700">#FFF5F5</color>
<color name="maroon_600">#FCEDED</color>
<color name="maroon_500">#f19595</color>
<color name="maroon_100">#DE3F3F</color>
<color name="maroon_50">#C92B2B</color>
@ -23,6 +25,8 @@
<color name="maroon_5">#7D0C0C</color>
<color name="maroon_1">#4C0001</color>
<color name="red_700">#FFF6F7</color>
<color name="red_600">#FCEEEF</color>
<color name="red_500">#ffb6b8</color>
<color name="red_100">#FF6165</color>
<color name="red_50">#F74E52</color>
@ -30,30 +34,40 @@
<color name="red_5">#BF262B</color>
<color name="red_1">#6c0406</color>
<color name="orange_700">#FFF9F5</color>
<color name="orange_600">#FCF3ED</color>
<color name="orange_500">#ffc8a7</color>
<color name="orange_100">#FF944C</color>
<color name="orange_50">#FA8537</color>
<color name="orange_10">#F47825</color>
<color name="orange_5">#A85219</color>
<color name="yellow_700">#FFFCF6</color>
<color name="yellow_600">#FCF3E5</color>
<color name="yellow_500">#fedead</color>
<color name="yellow_100">#FFBE5D</color>
<color name="yellow_50">#FFB445</color>
<color name="yellow_10">#FFA624</color>
<color name="yellow_5">#EE9109</color>
<color name="green_700">#F5FFFB</color>
<color name="green_600">#EDFCF7</color>
<color name="green_500">#77f4c7</color>
<color name="green_100">#24CC8F</color>
<color name="green_50">#20B780</color>
<color name="green_10">#1CA372</color>
<color name="green_5">#168059</color>
<color name="teal_700">#F5FEFF</color>
<color name="teal_600">#EDFBFC</color>
<color name="teal_500">#8eedf6</color>
<color name="teal_100">#3BCAD7</color>
<color name="teal_50">#34B5C1</color>
<color name="teal_10">#26A0AB</color>
<color name="teal_5">#1A7078</color>
<color name="blue_700">#FAFDFF</color>
<color name="blue_600">#EEF5F9</color>
<color name="blue_500">#a9dcf6</color>
<color name="blue_100">#50B5E9</color>
<color name="blue_50">#46A7D9</color>