mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 11:08:31 +00:00
Convert NotificationProfilesSettingsFragment to compose.
This commit is contained in:
@@ -1,103 +1,264 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications.profiles
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.Rows
|
||||
import org.signal.core.ui.compose.Scaffolds
|
||||
import org.signal.core.ui.compose.Texts
|
||||
import org.signal.core.ui.compose.horizontalGutters
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.NO_TINT
|
||||
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models.NoNotificationProfiles
|
||||
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models.NotificationProfilePreference
|
||||
import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LargeIconClickPreference
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiStrings
|
||||
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models.NotificationProfileRow
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileId
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileSchedule
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Primary entry point for Notification Profiles. When user has no profiles, shows empty state, otherwise shows
|
||||
* all current profiles.
|
||||
*/
|
||||
class NotificationProfilesFragment : DSLSettingsFragment() {
|
||||
class NotificationProfilesFragment : ComposeFragment() {
|
||||
|
||||
private val viewModel: NotificationProfilesViewModel by viewModels(
|
||||
factoryProducer = { NotificationProfilesViewModel.Factory() }
|
||||
)
|
||||
|
||||
private val lifecycleDisposable = LifecycleDisposable()
|
||||
private var toolbar: Toolbar? = null
|
||||
@Composable
|
||||
override fun FragmentContent() {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle(initialValue = NotificationProfilesState(profiles = emptyList()))
|
||||
val callback = remember { DefaultNotificationProfilesScreenCallback() }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
toolbar = view.findViewById(R.id.toolbar)
|
||||
|
||||
lifecycleDisposable.bindTo(viewLifecycleOwner.lifecycle)
|
||||
NotificationProfilesScreen(
|
||||
state = state,
|
||||
callbacks = callback
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
toolbar = null
|
||||
inner class DefaultNotificationProfilesScreenCallback : NotificationProfilesScreenCallback {
|
||||
override fun onNavigationClick() {
|
||||
requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onCreateNewProfile() {
|
||||
findNavController().safeNavigate(R.id.action_notificationProfilesFragment_to_editNotificationProfileFragment)
|
||||
}
|
||||
|
||||
override fun onProfileClick(profileId: Long) {
|
||||
findNavController().safeNavigate(NotificationProfilesFragmentDirections.actionNotificationProfilesFragmentToNotificationProfileDetailsFragment(profileId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NotificationProfilesScreen(
|
||||
state: NotificationProfilesState,
|
||||
callbacks: NotificationProfilesScreenCallback
|
||||
) {
|
||||
val title = if (state.profiles.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
stringResource(R.string.NotificationsSettingsFragment__notification_profiles)
|
||||
}
|
||||
|
||||
override fun bindAdapter(adapter: MappingAdapter) {
|
||||
NoNotificationProfiles.register(adapter)
|
||||
LargeIconClickPreference.register(adapter)
|
||||
NotificationProfilePreference.register(adapter)
|
||||
|
||||
lifecycleDisposable += viewModel.getProfiles()
|
||||
.subscribe { profiles ->
|
||||
if (profiles.isEmpty()) {
|
||||
toolbar?.title = ""
|
||||
} else {
|
||||
toolbar?.setTitle(R.string.NotificationsSettingsFragment__notification_profiles)
|
||||
Scaffolds.Settings(
|
||||
title = title,
|
||||
onNavigationClick = callbacks::onNavigationClick,
|
||||
navigationIcon = ImageVector.vectorResource(R.drawable.symbol_arrow_start_24),
|
||||
navigationContentDescription = stringResource(R.string.Material3SearchToolbar__close)
|
||||
) { paddingValues ->
|
||||
if (state.profiles.isEmpty()) {
|
||||
NoNotificationProfilesEmpty(
|
||||
onCreateProfileClick = callbacks::onCreateNewProfile,
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
)
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
) {
|
||||
item {
|
||||
Texts.SectionHeader(
|
||||
text = stringResource(R.string.NotificationProfilesFragment__profiles)
|
||||
)
|
||||
}
|
||||
adapter.submitList(getConfiguration(profiles).toMappingModelList())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfiguration(profiles: List<NotificationProfile>): DSLConfiguration {
|
||||
return configure {
|
||||
if (profiles.isEmpty()) {
|
||||
customPref(
|
||||
NoNotificationProfiles.Model(
|
||||
onClick = { findNavController().safeNavigate(R.id.action_notificationProfilesFragment_to_editNotificationProfileFragment) }
|
||||
item {
|
||||
Rows.TextRow(
|
||||
text = {
|
||||
Text(text = stringResource(R.string.NotificationProfilesFragment__new_profile))
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_plus_24),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.background(color = MaterialTheme.colorScheme.secondaryContainer, shape = CircleShape)
|
||||
.padding(8.dp)
|
||||
)
|
||||
},
|
||||
onClick = callbacks::onCreateNewProfile
|
||||
)
|
||||
)
|
||||
} else {
|
||||
sectionHeaderPref(R.string.NotificationProfilesFragment__profiles)
|
||||
}
|
||||
|
||||
customPref(
|
||||
LargeIconClickPreference.Model(
|
||||
title = DSLSettingsText.from(R.string.NotificationProfilesFragment__new_profile),
|
||||
icon = DSLSettingsIcon.from(R.drawable.add_to_a_group, NO_TINT),
|
||||
onClick = { findNavController().safeNavigate(R.id.action_notificationProfilesFragment_to_editNotificationProfileFragment) }
|
||||
)
|
||||
)
|
||||
|
||||
val activeProfile: NotificationProfile? = NotificationProfiles.getActiveProfile(profiles)
|
||||
profiles.sortedDescending().forEach { profile ->
|
||||
customPref(
|
||||
NotificationProfilePreference.Model(
|
||||
title = DSLSettingsText.from(profile.name),
|
||||
summary = if (profile == activeProfile) DSLSettingsText.from(NotificationProfiles.getActiveProfileDescription(requireContext(), profile)) else null,
|
||||
icon = if (profile.emoji.isNotEmpty()) EmojiUtil.convertToDrawable(requireContext(), profile.emoji)?.let { DSLSettingsIcon.from(it) } else DSLSettingsIcon.from(R.drawable.ic_moon_24, NO_TINT),
|
||||
color = profile.color,
|
||||
onClick = {
|
||||
findNavController().safeNavigate(NotificationProfilesFragmentDirections.actionNotificationProfilesFragmentToNotificationProfileDetailsFragment(profile.id))
|
||||
}
|
||||
state.profiles.sortedDescending().forEach { profile ->
|
||||
item {
|
||||
NotificationProfileRow(
|
||||
profile = profile,
|
||||
isActiveProfile = profile == state.activeProfile,
|
||||
onClick = callbacks::onProfileClick
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NoNotificationProfilesEmpty(
|
||||
onCreateProfileClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.horizontalGutters(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(96.dp))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(88.dp)
|
||||
.background(
|
||||
color = Color(AvatarColor.A100.colorInt()),
|
||||
shape = CircleShape
|
||||
)
|
||||
.padding(20.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_sleeping_face),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.NotificationProfilesFragment__notification_profiles),
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.NotificationProfilesFragment__create_a_profile_to_receive_notifications_and_calls_only_from_the_people_and_groups_you_want_to_hear_from),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Button(
|
||||
onClick = onCreateProfileClick,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.NotificationProfilesFragment__create_profile))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
fun NotificationProfilesScreenPreview() {
|
||||
Previews.Preview {
|
||||
val profile = remember {
|
||||
NotificationProfile(
|
||||
id = 1L,
|
||||
name = "Test Profile",
|
||||
emoji = EmojiStrings.AUDIO,
|
||||
createdAt = System.currentTimeMillis(),
|
||||
schedule = NotificationProfileSchedule(
|
||||
id = 1
|
||||
),
|
||||
notificationProfileId = NotificationProfileId(UUID.randomUUID())
|
||||
)
|
||||
}
|
||||
|
||||
NotificationProfilesScreen(
|
||||
state = NotificationProfilesState(
|
||||
profiles = listOf(
|
||||
profile
|
||||
),
|
||||
activeProfile = null
|
||||
),
|
||||
callbacks = NotificationProfilesScreenCallback.Empty
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
private fun NoNotificationProfilesEmptyPreview() {
|
||||
Previews.Preview {
|
||||
NoNotificationProfilesEmpty(
|
||||
onCreateProfileClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface NotificationProfilesScreenCallback {
|
||||
fun onNavigationClick()
|
||||
fun onCreateNewProfile()
|
||||
fun onProfileClick(profileId: Long)
|
||||
|
||||
object Empty : NotificationProfilesScreenCallback {
|
||||
override fun onNavigationClick() = Unit
|
||||
override fun onCreateNewProfile() = Unit
|
||||
override fun onProfileClick(profileId: Long) = Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications.profiles
|
||||
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles
|
||||
|
||||
data class NotificationProfilesState(
|
||||
val profiles: List<NotificationProfile>,
|
||||
val activeProfile: NotificationProfile? = NotificationProfiles.getActiveProfile(profiles)
|
||||
)
|
||||
@@ -2,16 +2,16 @@ package org.thoughtcrime.securesms.components.settings.app.notifications.profile
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.reactive.asFlow
|
||||
import kotlinx.coroutines.rx3.asFlow
|
||||
|
||||
class NotificationProfilesViewModel(private val repository: NotificationProfilesRepository) : ViewModel() {
|
||||
|
||||
fun getProfiles(): Flowable<List<NotificationProfile>> {
|
||||
return repository.getProfiles()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
val state: Flow<NotificationProfilesState> = repository.getProfiles()
|
||||
.asFlow()
|
||||
.map { profiles -> NotificationProfilesState(profiles = profiles) }
|
||||
|
||||
class Factory() : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.airbnb.lottie.SimpleColorFilter
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
|
||||
|
||||
/**
|
||||
* DSL custom preference for showing no profiles/empty state.
|
||||
*/
|
||||
object NoNotificationProfiles {
|
||||
|
||||
fun register(adapter: MappingAdapter) {
|
||||
adapter.registerFactory(Model::class.java, LayoutFactory({ ViewHolder(it) }, R.layout.notification_profiles_empty))
|
||||
}
|
||||
|
||||
class Model(val onClick: () -> Unit) : PreferenceModel<Model>() {
|
||||
override fun areItemsTheSame(newItem: Model): Boolean = true
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View) : MappingViewHolder<Model>(itemView) {
|
||||
|
||||
private val icon: ImageView = findViewById(R.id.notification_profiles_empty_icon)
|
||||
private val button: View = findViewById(R.id.notification_profiles_empty_create_profile)
|
||||
|
||||
override fun bind(model: Model) {
|
||||
icon.background.colorFilter = SimpleColorFilter(AvatarColor.A100.colorInt())
|
||||
button.setOnClickListener { model.onClick() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,51 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models
|
||||
|
||||
import android.view.View
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.airbnb.lottie.SimpleColorFilter
|
||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||
import com.google.android.material.materialswitch.MaterialSwitch
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.horizontalGutters
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileId
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileSchedule
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* DSL custom preference for showing Notification Profile rows.
|
||||
@@ -48,3 +82,122 @@ object NotificationProfilePreference {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NotificationProfileRow(
|
||||
profile: NotificationProfile,
|
||||
isActiveProfile: Boolean = false,
|
||||
showSwitch: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
onClick: (Long) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = { onClick(profile.id) })
|
||||
.horizontalGutters()
|
||||
.padding(vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.background(
|
||||
color = Color(profile.color.colorInt()),
|
||||
shape = CircleShape
|
||||
)
|
||||
.padding(8.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (profile.emoji.isNotEmpty()) {
|
||||
val emojiDrawable = remember(profile.emoji) { EmojiUtil.convertToDrawable(context, profile.emoji) }
|
||||
|
||||
Image(
|
||||
painter = rememberDrawablePainter(drawable = emojiDrawable),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_moon_24),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = profile.name,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
|
||||
val summary = remember(isActiveProfile) {
|
||||
if (isActiveProfile) {
|
||||
NotificationProfiles.getActiveProfileDescription(context, profile)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
if (summary != null) {
|
||||
Text(
|
||||
text = summary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (showSwitch) {
|
||||
Switch(
|
||||
checked = isActiveProfile,
|
||||
onCheckedChange = { onClick(profile.id) },
|
||||
enabled = enabled
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
private fun NotificationProfileRowPreview() {
|
||||
Previews.Preview {
|
||||
Column {
|
||||
NotificationProfileRow(
|
||||
profile = NotificationProfile(
|
||||
id = 1L,
|
||||
name = "Work",
|
||||
createdAt = 0L,
|
||||
schedule = NotificationProfileSchedule(
|
||||
id = 1L
|
||||
),
|
||||
emoji = "",
|
||||
notificationProfileId = NotificationProfileId(UUID.randomUUID())
|
||||
),
|
||||
onClick = {}
|
||||
)
|
||||
|
||||
NotificationProfileRow(
|
||||
profile = NotificationProfile(
|
||||
id = 1L,
|
||||
name = "Sleep",
|
||||
createdAt = 0L,
|
||||
schedule = NotificationProfileSchedule(
|
||||
id = 1L
|
||||
),
|
||||
emoji = "",
|
||||
notificationProfileId = NotificationProfileId(UUID.randomUUID())
|
||||
),
|
||||
onClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:viewBindingIgnore="true"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/notification_profiles_empty_icon"
|
||||
android:layout_width="88dp"
|
||||
android:layout_height="88dp"
|
||||
android:layout_marginTop="96dp"
|
||||
android:background="@drawable/tinted_circle"
|
||||
android:padding="20dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_sleeping_face"
|
||||
tools:backgroundTint="#E3E3FE" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_profiles_empty_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/NotificationProfilesFragment__notification_profiles"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Title1"
|
||||
android:hyphenationFrequency="normal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/notification_profiles_empty_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_profiles_empty_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/notification_profiles_empty_title"
|
||||
android:text="@string/NotificationProfilesFragment__create_a_profile_to_receive_notifications_and_calls_only_from_the_people_and_groups_you_want_to_hear_from" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/notification_profiles_empty_create_profile"
|
||||
style="@style/Signal.Widget.Button.Large.Primary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/NotificationProfilesFragment__create_profile"
|
||||
app:layout_constraintVertical_bias="1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/notification_profiles_empty_description" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user