From 0f0c2bac93760c9daa68a804abaa7cad803abae6 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Thu, 4 Mar 2021 17:17:55 -0600 Subject: [PATCH] Show list members on caldav list settings screen --- .../BaseCaldavCalendarSettingsActivity.kt | 5 +- .../caldav/CaldavCalendarSettingsActivity.kt | 82 ++++++++++++++++++- app/src/main/java/org/tasks/data/Principal.kt | 11 +++ .../main/java/org/tasks/data/PrincipalDao.kt | 4 + app/src/main/java/org/tasks/themes/Theme.kt | 36 +++++++- .../activity_caldav_calendar_settings.xml | 5 ++ app/src/main/res/values/strings.xml | 1 + .../test/java/org/tasks/data/PrincipalTest.kt | 34 ++++++++ 8 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 app/src/test/java/org/tasks/data/PrincipalTest.kt diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt index 1b9c61051..625aad6a5 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt @@ -46,8 +46,9 @@ abstract class BaseCaldavCalendarSettingsActivity : BaseListSettingsActivity() { @BindView(R.id.progress_bar) lateinit var progressView: ProgressBar - private var caldavCalendar: CaldavCalendar? = null - private lateinit var caldavAccount: CaldavAccount + protected var caldavCalendar: CaldavCalendar? = null + + protected lateinit var caldavAccount: CaldavAccount override val layout: Int get() = R.layout.activity_caldav_calendar_settings diff --git a/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.kt index e0e413ed0..7f0946784 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.kt @@ -2,21 +2,38 @@ package org.tasks.caldav import android.os.Bundle import androidx.activity.viewModels -import androidx.lifecycle.lifecycleScope +import androidx.compose.foundation.layout.* +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.view.isVisible import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch import org.tasks.R import org.tasks.data.CaldavAccount import org.tasks.data.CaldavCalendar +import org.tasks.data.Principal +import org.tasks.data.Principal.Companion.name +import org.tasks.data.PrincipalDao +import javax.inject.Inject @AndroidEntryPoint class CaldavCalendarSettingsActivity : BaseCaldavCalendarSettingsActivity() { + + @Inject lateinit var principalDao: PrincipalDao + private val createCalendarViewModel: CreateCalendarViewModel by viewModels() private val deleteCalendarViewModel: DeleteCalendarViewModel by viewModels() private val updateCalendarViewModel: UpdateCalendarViewModel by viewModels() - override val layout: Int - get() = R.layout.activity_caldav_calendar_settings + override val layout = R.layout.activity_caldav_calendar_settings override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -27,6 +44,54 @@ class CaldavCalendarSettingsActivity : BaseCaldavCalendarSettingsActivity() { this, { updateCalendar() }, this::requestFailed) + + caldavCalendar?.takeIf { it.id > 0 }?.let { + principalDao.getPrincipals(it.id).observe(this) { + findViewById(R.id.people) + .apply { isVisible = it.isNotEmpty() } + .setContent { PrincipalList(it) } + } + } + } + + @Composable + private fun PrincipalList(principals: List) { + tasksTheme.TasksTheme { + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + ) { + Text( + stringResource(R.string.list_members), + style = MaterialTheme.typography.h6, + color = MaterialTheme.colors.onBackground + ) + Spacer(Modifier.height(8.dp)) + principals.forEach { + PrincipalRow(it) + } + } + } + } + + @Composable + fun PrincipalRow(principal: Principal) { + Row(modifier = Modifier + .padding(PaddingValues(0.dp, 16.dp)) + .fillMaxWidth()) { + Icon( + painter = painterResource(R.drawable.ic_outline_perm_identity_24px), + contentDescription = null, + modifier = Modifier.padding(end = 16.dp), + tint = colorResource(R.color.icon_tint_with_alpha) + ) + Text( + principal.name!!, + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.onBackground, + ) + } } override suspend fun createCalendar(caldavAccount: CaldavAccount, name: String, color: Int) = @@ -38,4 +103,13 @@ class CaldavCalendarSettingsActivity : BaseCaldavCalendarSettingsActivity() { override suspend fun deleteCalendar(caldavAccount: CaldavAccount, caldavCalendar: CaldavCalendar) = deleteCalendarViewModel.deleteCalendar(caldavAccount, caldavCalendar) + + @Preview + @Composable + private fun PreviewList() { + PrincipalList(listOf( + Principal().apply { displayName = "user1" }, + Principal().apply { displayName = "user2" }, + )) + } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/data/Principal.kt b/app/src/main/java/org/tasks/data/Principal.kt index 393f7a40d..8599f5fbb 100644 --- a/app/src/main/java/org/tasks/data/Principal.kt +++ b/app/src/main/java/org/tasks/data/Principal.kt @@ -62,4 +62,15 @@ class Principal { override fun toString(): String { return "Principal(id=$id, list=$list, principal=$principal, displayName=$displayName, inviteStatus=$inviteStatus, access=$access)" } + + companion object { + private val MAILTO = "^mailto:".toRegex() + private val LAST_SEGMENT = ".*/([^/]+).*".toRegex() + + val Principal.name: String? + get() = displayName + ?: principal + ?.replace(MAILTO, "") + ?.replaceFirst(LAST_SEGMENT, "$1") + } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/data/PrincipalDao.kt b/app/src/main/java/org/tasks/data/PrincipalDao.kt index da40f9559..b3125a4ae 100644 --- a/app/src/main/java/org/tasks/data/PrincipalDao.kt +++ b/app/src/main/java/org/tasks/data/PrincipalDao.kt @@ -1,5 +1,6 @@ package org.tasks.data +import androidx.lifecycle.LiveData import androidx.room.* @Dao @@ -19,4 +20,7 @@ WHERE principal_list = :list @Query("SELECT * FROM principals") fun getAll(): List + + @Query("SELECT * FROM principals WHERE principal_list = :id") + fun getPrincipals(id: Long): LiveData> } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/themes/Theme.kt b/app/src/main/java/org/tasks/themes/Theme.kt index 4caf46c59..85c4f2c38 100644 --- a/app/src/main/java/org/tasks/themes/Theme.kt +++ b/app/src/main/java/org/tasks/themes/Theme.kt @@ -4,15 +4,49 @@ import android.app.Activity import android.content.Context import android.graphics.PixelFormat import android.view.LayoutInflater +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import dagger.hilt.android.qualifiers.ActivityContext import org.tasks.R import javax.inject.Inject class Theme @Inject constructor( + @ActivityContext val context: Context, val themeBase: ThemeBase, val themeColor: ThemeColor, private val themeAccent: ThemeAccent ) { - fun withThemeColor(themeColor: ThemeColor) = Theme(themeBase, themeColor, themeAccent) + private val darkTheme = themeBase.isDarkTheme(context as Activity) + + @Composable + fun TasksTheme( + content: @Composable () -> Unit, + ) { + val primary = Color(themeColor.primaryColor) + val onPrimary = Color(themeColor.colorOnPrimary) + val secondary = Color(themeAccent.accentColor) + MaterialTheme( + colors = if (darkTheme) { + darkColors( + primary = primary, + onPrimary = onPrimary, + secondary = secondary, + ) + } else { + lightColors( + primary = primary, + onPrimary = onPrimary, + secondary = secondary, + ) + }, + content = content + ) + } + + fun withThemeColor(themeColor: ThemeColor) = Theme(context, themeBase, themeColor, themeAccent) fun getLayoutInflater(context: Context) = wrap(context).getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater diff --git a/app/src/main/res/layout/activity_caldav_calendar_settings.xml b/app/src/main/res/layout/activity_caldav_calendar_settings.xml index 565158010..05f13b417 100644 --- a/app/src/main/res/layout/activity_caldav_calendar_settings.xml +++ b/app/src/main/res/layout/activity_caldav_calendar_settings.xml @@ -36,6 +36,11 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5d751fcf..5bfd2c3c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -688,4 +688,5 @@ File %1$s contained %2$s.\n\n Tasks.org account required Not included with \'Name your price\' subscriptions Use app theme + List members diff --git a/app/src/test/java/org/tasks/data/PrincipalTest.kt b/app/src/test/java/org/tasks/data/PrincipalTest.kt new file mode 100644 index 000000000..b7f12c65b --- /dev/null +++ b/app/src/test/java/org/tasks/data/PrincipalTest.kt @@ -0,0 +1,34 @@ +package org.tasks.data + +import org.junit.Assert.assertEquals +import org.junit.Test +import org.tasks.data.Principal.Companion.name + +class PrincipalTest { + @Test + fun lastSegmentTrailingSlash() { + val principal = Principal().apply { + principal = "principals/users/user1/" + } + + assertEquals("user1", principal.name) + } + + @Test + fun lastSegmentNoTrailingSlash() { + val principal = Principal().apply { + principal = "principals/users/user1" + } + + assertEquals("user1", principal.name) + } + + @Test + fun stripMailto() { + val principal = Principal().apply { + principal = "mailto:user@example.com" + } + + assertEquals("user@example.com", principal.name) + } +} \ No newline at end of file