Feature/compose cleanup (#1543)

* Moving color files

* Moving theme classes into their own package

* Only obtain new theme when required

* UI Tweaks

Using the proper color for danger as opposed to one hardcoded color
Reusing BlackAlpha40
Using the right delete icon in settings

* matching figma

* Matching signature across buttons

* Dialogs do not have a 'x' button by default

* Updated typography

Updated the typography in an composition local so it can be accessed from anyehere in compose and matching the figma declarations.

* Centered text in control messages

* Fixing new color access for action items

* renaming spacing to be more general

* Unifying dimensions and rectifying design inconsistencies

Unifying spacing values and reusing common ones
Identified spacing issues and inconsistencies in design and figma

* Rounded corners for the new conversation sheet

* Rounding sheets corners

* Spacing fixes and UI consolidating

Discussed with QA to make sure the 'new message' screen should  indeed behave as the other screens and use disabled state instead of disappearing

* Disappearing messages tweaks

Re-using our new radio buttons in disappearing messages
Tweaking UI to match designs

* Cleaning up spaces

* Migrating to Material3

* Fixing UI issues found

* PR feedbacks

---------

Co-authored-by: bemusementpark <bemusementpark>
This commit is contained in:
ThomasSession 2024-07-18 16:32:03 +10:00 committed by GitHub
parent c31e89a13d
commit 9e2b24f7b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
90 changed files with 1308 additions and 1058 deletions

View File

@ -381,7 +381,7 @@ dependencies {
implementation "androidx.compose.ui:ui-tooling:$composeVersion"
implementation "androidx.compose.runtime:runtime-livedata:$composeVersion"
implementation "androidx.compose.foundation:foundation-layout:$composeVersion"
implementation "androidx.compose.material:material:$composeVersion"
implementation "androidx.compose.material3:material3:1.2.1"
androidTestImplementation "androidx.compose.ui:ui-test-junit4-android:$composeVersion"
debugImplementation "androidx.compose.ui:ui-test-manifest:$composeVersion"

View File

@ -114,14 +114,14 @@ class SessionDialogBuilder(val context: Context) {
options,
) { dialog, it -> onSelect(it); dialog.dismiss() }
fun destructiveButton(
fun dangerButton(
@StringRes text: Int,
@StringRes contentDescription: Int = text,
listener: () -> Unit = {}
) = button(
text,
contentDescription,
R.style.Widget_Session_Button_Dialog_DestructiveText,
R.style.Widget_Session_Button_Dialog_DangerText,
) { listener() }
fun okButton(listener: (() -> Unit) = {}) = button(android.R.string.ok) { listener() }

View File

@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.components.menu
import android.content.Context
import androidx.annotation.AttrRes
import androidx.annotation.ColorRes
import androidx.annotation.ColorInt
/**
* Represents an action to be rendered
@ -13,5 +13,5 @@ data class ActionItem(
val action: Runnable,
val contentDescription: Int? = null,
val subtitle: ((Context) -> CharSequence?)? = null,
@ColorRes val color: Int? = null,
@ColorInt val color: Int? = null,
)

View File

@ -78,7 +78,7 @@ class ContextMenuList(recyclerView: RecyclerView, onItemClick: () -> Unit) {
override fun bind(model: DisplayItem) {
val item = model.item
val color = item.color?.let { ContextCompat.getColor(context, it) }
val color = item.color
if (item.iconRes > 0) {
val typedValue = TypedValue()

View File

@ -14,7 +14,6 @@ import org.session.libsession.utilities.ExpirationUtil
import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.getExpirationTypeDisplayValue
import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.showSessionDialog
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
@ -57,7 +56,7 @@ class DisappearingMessages @Inject constructor(
context.getExpirationTypeDisplayValue(message.isNotDisappearAfterRead)
)
})
destructiveButton(
dangerButton(
text = if (message.expiresIn == 0L) R.string.dialog_disappearing_messages_follow_setting_confirm else R.string.dialog_disappearing_messages_follow_setting_set,
contentDescription = if (message.expiresIn == 0L) R.string.AccessibilityId_confirm else R.string.AccessibilityId_set_button
) {

View File

@ -13,8 +13,8 @@ import kotlin.time.Duration.Companion.seconds
fun State.toUiState() = UiState(
cards = listOfNotNull(
typeOptions()?.let { ExpiryOptionsCard(GetString(R.string.activity_disappearing_messages_delete_type), it) },
timeOptions()?.let { ExpiryOptionsCard(GetString(R.string.activity_disappearing_messages_timer), it) }
typeOptions()?.let { ExpiryOptionsCardData(GetString(R.string.activity_disappearing_messages_delete_type), it) },
timeOptions()?.let { ExpiryOptionsCardData(GetString(R.string.activity_disappearing_messages_timer), it) }
),
showGroupFooter = isGroup && isNewConfigEnabled,
showSetButton = isSelfAdmin

View File

@ -3,11 +3,13 @@ package org.thoughtcrime.securesms.conversation.disappearingmessages.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -18,15 +20,15 @@ import androidx.compose.ui.unit.dp
import network.loki.messenger.R
import network.loki.messenger.libsession_util.util.ExpiryMode
import org.thoughtcrime.securesms.ui.Callbacks
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.NoOpCallbacks
import org.thoughtcrime.securesms.ui.OptionsCard
import org.thoughtcrime.securesms.ui.RadioOption
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.extraSmall
import org.thoughtcrime.securesms.ui.fadingEdges
import org.thoughtcrime.securesms.ui.theme.LocalType
typealias ExpiryCallbacks = Callbacks<ExpiryMode>
typealias ExpiryRadioOption = RadioOption<ExpiryMode>
@ -39,26 +41,32 @@ fun DisappearingMessages(
) {
val scrollState = rememberScrollState()
Column(modifier = modifier.padding(horizontal = LocalDimensions.current.margin)) {
Column(modifier = modifier.padding(horizontal = LocalDimensions.current.spacing)) {
Box(modifier = Modifier.weight(1f)) {
Column(
modifier = Modifier
.padding(bottom = 20.dp)
.padding(vertical = LocalDimensions.current.spacing)
.verticalScroll(scrollState)
.fadingEdges(scrollState),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing)
) {
state.cards.forEach {
OptionsCard(it, callbacks)
state.cards.forEachIndexed { index, option ->
OptionsCard(option, callbacks)
// add spacing if not the last item
if(index != state.cards.lastIndex){
Spacer(modifier = Modifier.height(LocalDimensions.current.spacing))
}
}
if (state.showGroupFooter) Text(
text = stringResource(R.string.activity_disappearing_messages_group_footer),
style = extraSmall,
style = LocalType.current.extraSmall,
fontWeight = FontWeight(400),
color = LocalColors.current.textSecondary,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.padding(top = LocalDimensions.current.xsSpacing)
)
}
}
@ -68,7 +76,7 @@ fun DisappearingMessages(
modifier = Modifier
.contentDescription(R.string.AccessibilityId_set_button)
.align(Alignment.CenterHorizontally)
.padding(bottom = 20.dp),
.padding(bottom = LocalDimensions.current.spacing),
onClick = callbacks::onSetClick
)
}

View File

@ -10,9 +10,9 @@ import androidx.compose.ui.unit.dp
import network.loki.messenger.libsession_util.util.ExpiryMode
import org.thoughtcrime.securesms.conversation.disappearingmessages.ExpiryType
import org.thoughtcrime.securesms.conversation.disappearingmessages.State
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
@Preview(widthDp = 450, heightDp = 700)
@Composable
@ -51,7 +51,7 @@ class StatePreviewParameterProvider : PreviewParameterProvider<State> {
@Preview
@Composable
fun PreviewThemes(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
DisappearingMessages(

View File

@ -5,15 +5,15 @@ import network.loki.messenger.libsession_util.util.ExpiryMode
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.RadioOption
typealias ExpiryOptionsCard = OptionsCard<ExpiryMode>
typealias ExpiryOptionsCardData = OptionsCardData<ExpiryMode>
data class UiState(
val cards: List<ExpiryOptionsCard> = emptyList(),
val cards: List<ExpiryOptionsCardData> = emptyList(),
val showGroupFooter: Boolean = false,
val showSetButton: Boolean = true
) {
constructor(
vararg cards: ExpiryOptionsCard,
vararg cards: ExpiryOptionsCardData,
showGroupFooter: Boolean = false,
showSetButton: Boolean = true,
): this(
@ -23,7 +23,7 @@ data class UiState(
)
}
data class OptionsCard<T>(
data class OptionsCardData<T>(
val title: GetString,
val options: List<RadioOption<T>>
) {

View File

@ -7,8 +7,9 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
@ -21,23 +22,25 @@ import org.thoughtcrime.securesms.conversation.start.NullStartConversationDelega
import org.thoughtcrime.securesms.conversation.start.StartConversationDelegate
import org.thoughtcrime.securesms.ui.Divider
import org.thoughtcrime.securesms.ui.ItemButton
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.AppBar
import org.thoughtcrime.securesms.ui.components.QrImage
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.xl
import org.thoughtcrime.securesms.ui.theme.LocalType
@Composable
internal fun StartConversationScreen(
accountId: String,
delegate: StartConversationDelegate
) {
Column(modifier = Modifier.background(LocalColors.current.backgroundSecondary)) {
Column(modifier = Modifier.background(
LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small
)) {
AppBar(stringResource(R.string.dialog_start_conversation_title), onClose = delegate::onDialogClosePressed)
Surface(
modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection()),
@ -74,18 +77,18 @@ internal fun StartConversationScreen(
)
Column(
modifier = Modifier
.padding(horizontal = LocalDimensions.current.margin)
.padding(top = LocalDimensions.current.itemSpacing)
.padding(bottom = LocalDimensions.current.margin)
.padding(horizontal = LocalDimensions.current.spacing)
.padding(top = LocalDimensions.current.spacing)
.padding(bottom = LocalDimensions.current.spacing)
) {
Text(stringResource(R.string.accountIdYours), style = xl)
Spacer(modifier = Modifier.height(LocalDimensions.current.xxxsItemSpacing))
Text(stringResource(R.string.accountIdYours), style = LocalType.current.xl)
Spacer(modifier = Modifier.height(LocalDimensions.current.xxsSpacing))
Text(
text = stringResource(R.string.qrYoursDescription),
color = LocalColors.current.textSecondary,
style = small
style = LocalType.current.small
)
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
QrImage(
string = accountId,
Modifier.contentDescription(R.string.AccessibilityId_qr_code),
@ -100,7 +103,7 @@ internal fun StartConversationScreen(
@Preview
@Composable
private fun PreviewStartConversationScreen(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
StartConversationScreen(

View File

@ -8,23 +8,23 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.AppBar
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
import org.thoughtcrime.securesms.ui.components.SlimOutlineCopyButton
import org.thoughtcrime.securesms.ui.components.border
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.theme.LocalType
@Composable
internal fun InviteFriend(
@ -34,10 +34,14 @@ internal fun InviteFriend(
copyPublicKey: () -> Unit = {},
sendInvitation: () -> Unit = {},
) {
Column(modifier = Modifier.background(LocalColors.current.backgroundSecondary)) {
Column(modifier = Modifier.background(
LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small
)) {
AppBar(stringResource(R.string.invite_a_friend), onBack = onBack, onClose = onClose)
Column(
modifier = Modifier.padding(horizontal = LocalDimensions.current.itemSpacing),
modifier = Modifier.padding(horizontal = LocalDimensions.current.spacing)
.padding(top = LocalDimensions.current.spacing),
) {
Text(
accountId,
@ -45,24 +49,24 @@ internal fun InviteFriend(
.contentDescription(R.string.AccessibilityId_account_id)
.fillMaxWidth()
.border()
.padding(LocalDimensions.current.smallMargin),
.padding(LocalDimensions.current.spacing),
textAlign = TextAlign.Center,
style = base
style = LocalType.current.base
)
Spacer(modifier = Modifier.height(LocalDimensions.current.xsItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
Text(
stringResource(R.string.invite_your_friend_to_chat_with_you_on_session_by_sharing_your_account_id_with_them),
textAlign = TextAlign.Center,
style = small,
style = LocalType.current.small,
color = LocalColors.current.textSecondary,
modifier = Modifier.padding(horizontal = LocalDimensions.current.smallItemSpacing)
modifier = Modifier.padding(horizontal = LocalDimensions.current.smallSpacing)
)
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
Row(horizontalArrangement = spacedBy(LocalDimensions.current.smallItemSpacing)) {
Row(horizontalArrangement = spacedBy(LocalDimensions.current.smallSpacing)) {
SlimOutlineButton(
stringResource(R.string.share),
modifier = Modifier

View File

@ -3,17 +3,19 @@ package org.thoughtcrime.securesms.conversation.start.newmessage
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
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.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -23,12 +25,13 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import network.loki.messenger.R
import org.thoughtcrime.securesms.onboarding.ui.ContinuePrimaryOutlineButton
import org.thoughtcrime.securesms.ui.LoadingArcOr
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.AppBar
import org.thoughtcrime.securesms.ui.components.BorderlessButtonWithIcon
import org.thoughtcrime.securesms.ui.components.MaybeScanQrCode
@ -36,7 +39,7 @@ import org.thoughtcrime.securesms.ui.components.PrimaryOutlineButton
import org.thoughtcrime.securesms.ui.components.SessionOutlinedTextField
import org.thoughtcrime.securesms.ui.components.SessionTabRow
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.theme.LocalType
private val TITLES = listOf(R.string.enter_account_id, R.string.qrScan)
@ -52,7 +55,10 @@ internal fun NewMessage(
) {
val pagerState = rememberPagerState { TITLES.size }
Column(modifier = Modifier.background(LocalColors.current.backgroundSecondary)) {
Column(modifier = Modifier.background(
LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small
)) {
AppBar(stringResource(R.string.messageNew), onClose = onClose, onBack = onBack)
SessionTabRow(pagerState, TITLES)
HorizontalPager(pagerState) {
@ -70,7 +76,6 @@ private fun EnterAccountId(
callbacks: Callbacks,
onHelp: () -> Unit = {}
) {
Column(
modifier = Modifier
.fillMaxSize()
@ -78,14 +83,13 @@ private fun EnterAccountId(
.imePadding()
) {
Column(
modifier = Modifier.padding(horizontal = LocalDimensions.current.xxsMargin, vertical = LocalDimensions.current.xsMargin),
modifier = Modifier.padding(vertical = LocalDimensions.current.spacing),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.xsMargin)
) {
SessionOutlinedTextField(
text = state.newMessageIdOrOns,
modifier = Modifier
.padding(horizontal = LocalDimensions.current.smallMargin),
.padding(horizontal = LocalDimensions.current.spacing),
contentDescription = "Session id input box",
placeholder = stringResource(R.string.accountIdOrOnsEnter),
onChange = callbacks::onChange,
@ -94,31 +98,36 @@ private fun EnterAccountId(
isTextErrorColor = state.isTextErrorColor
)
Spacer(modifier = Modifier.height(LocalDimensions.current.xxxsSpacing))
BorderlessButtonWithIcon(
text = stringResource(R.string.messageNewDescription),
modifier = Modifier
.contentDescription(R.string.AccessibilityId_help_desk_link)
.padding(horizontal = LocalDimensions.current.margin)
.padding(horizontal = LocalDimensions.current.mediumSpacing)
.fillMaxWidth(),
style = small,
style = LocalType.current.small,
color = LocalColors.current.textSecondary,
iconRes = R.drawable.ic_circle_question_mark,
onClick = onHelp
)
}
AnimatedVisibility(state.isNextButtonVisible) {
PrimaryOutlineButton(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(horizontal = LocalDimensions.current.largeMargin)
.fillMaxWidth()
.contentDescription(R.string.next),
onClick = callbacks::onContinue
) {
LoadingArcOr(state.loading) {
Text(stringResource(R.string.next))
}
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
Spacer(Modifier.weight(2f))
PrimaryOutlineButton(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(horizontal = LocalDimensions.current.xlargeSpacing)
.padding(bottom = LocalDimensions.current.smallSpacing)
.fillMaxWidth()
.contentDescription(R.string.next),
enabled = state.isNextButtonEnabled,
onClick = callbacks::onContinue
) {
LoadingArcOr(state.loading) {
Text(stringResource(R.string.next))
}
}
}
@ -127,7 +136,7 @@ private fun EnterAccountId(
@Preview
@Composable
private fun PreviewNewMessage(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
NewMessage(State("z"))

View File

@ -6,7 +6,6 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@ -22,8 +21,6 @@ import org.session.libsignal.utilities.timeout
import org.thoughtcrime.securesms.ui.GetString
import java.util.concurrent.TimeoutException
import javax.inject.Inject
import kotlin.coroutines.cancellation.CancellationException
import kotlin.time.Duration.Companion.seconds
@HiltViewModel
internal class NewMessageViewModel @Inject constructor(
@ -112,7 +109,7 @@ internal data class State(
val error: GetString? = null,
val loading: Boolean = false
) {
val isNextButtonVisible: Boolean get() = newMessageIdOrOns.isNotBlank()
val isNextButtonEnabled: Boolean get() = newMessageIdOrOns.isNotBlank()
}
internal data class Success(val publicKey: String)

View File

@ -1120,7 +1120,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
showSessionDialog {
title(R.string.RecipientPreferenceActivity_block_this_contact_question)
text(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
destructiveButton(R.string.RecipientPreferenceActivity_block, R.string.AccessibilityId_block_confirm) {
dangerButton(R.string.RecipientPreferenceActivity_block, R.string.AccessibilityId_block_confirm) {
viewModel.block()
if (deleteThread) {
viewModel.deleteThread()
@ -1163,7 +1163,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
showSessionDialog {
title(R.string.ConversationActivity_unblock_this_contact_question)
text(R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
destructiveButton(
dangerButton(
R.string.ConversationActivity_unblock,
R.string.AccessibilityId_block_confirm
) { viewModel.unblock() }

View File

@ -545,7 +545,8 @@ class ConversationReactionOverlay : FrameLayout {
}
// Delete message
if (userCanDeleteSelectedItems(context, message, openGroup, userPublicKey, blindedPublicKey)) {
items += ActionItem(R.attr.menu_trash_icon, R.string.delete, { handleActionItemClicked(Action.DELETE) }, R.string.AccessibilityId_delete_message, message.subtitle, R.color.destructive)
items += ActionItem(R.attr.menu_trash_icon, R.string.delete, { handleActionItemClicked(Action.DELETE) },
R.string.AccessibilityId_delete_message, message.subtitle, ThemeUtil.getThemedColor(context, R.attr.danger))
}
// Ban user
if (userCanBanSelectedUsers(context, message, openGroup, userPublicKey, blindedPublicKey)) {

View File

@ -27,9 +27,9 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -63,20 +63,19 @@ import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
import org.thoughtcrime.securesms.ui.Divider
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.HorizontalPagerIndicator
import org.thoughtcrime.securesms.ui.ItemButton
import org.thoughtcrime.securesms.ui.LargeItemButton
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.TitledText
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.baseBold
import org.thoughtcrime.securesms.ui.baseMonospace
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.blackAlpha40
import org.thoughtcrime.securesms.ui.color.destructiveButtonColors
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.blackAlpha40
import org.thoughtcrime.securesms.ui.theme.dangerButtonColors
import org.thoughtcrime.securesms.ui.setComposeContent
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.bold
import org.thoughtcrime.securesms.ui.theme.monospace
import javax.inject.Inject
@AndroidEntryPoint
@ -152,12 +151,12 @@ fun MessageDetails(
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.padding(vertical = LocalDimensions.current.smallItemSpacing),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing)
.padding(vertical = LocalDimensions.current.smallSpacing),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)
) {
state.record?.let { message ->
AndroidView(
modifier = Modifier.padding(horizontal = LocalDimensions.current.margin),
modifier = Modifier.padding(horizontal = LocalDimensions.current.spacing),
factory = {
ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(it)).mainContainerConstraint.apply {
bind(
@ -193,7 +192,7 @@ fun CellMetadata(
state.apply {
if (listOfNotNull(sent, received, error, senderInfo).isEmpty()) return
CellWithPaddingAndMargin {
Column(verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing)) {
Column(verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)) {
TitledText(sent)
TitledText(received)
TitledErrorText(error)
@ -237,7 +236,7 @@ fun CellButtons(
LargeItemButton(
R.string.delete,
R.drawable.ic_message_details__trash,
colors = destructiveButtonColors(),
colors = dangerButtonColors(),
onClick = onDelete
)
}
@ -251,7 +250,7 @@ fun Carousel(attachments: List<Attachment>, onClick: (Int) -> Unit) {
val pagerState = rememberPagerState { attachments.size }
Column(verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing)) {
Column(verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)) {
Row {
CarouselPrevButton(pagerState)
Box(modifier = Modifier.weight(1f)) {
@ -260,7 +259,7 @@ fun Carousel(attachments: List<Attachment>, onClick: (Int) -> Unit) {
ExpandButton(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(LocalDimensions.current.xxsItemSpacing)
.padding(LocalDimensions.current.xxsSpacing)
) { onClick(pagerState.currentPage) }
}
CarouselNextButton(pagerState)
@ -313,7 +312,7 @@ fun ExpandButton(modifier: Modifier = Modifier, onClick: () -> Unit) {
@Preview
@Composable
fun PreviewMessageDetails(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
MessageDetails(
@ -340,8 +339,8 @@ fun FileDetails(fileDetails: List<TitledText>) {
Cell {
FlowRow(
modifier = Modifier.padding(horizontal = LocalDimensions.current.xsItemSpacing, vertical = LocalDimensions.current.itemSpacing),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing)
modifier = Modifier.padding(horizontal = LocalDimensions.current.xsSpacing, vertical = LocalDimensions.current.spacing),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)
) {
fileDetails.forEach {
BoxWithConstraints {
@ -349,7 +348,7 @@ fun FileDetails(fileDetails: List<TitledText>) {
it,
modifier = Modifier
.widthIn(min = maxWidth.div(2))
.padding(horizontal = LocalDimensions.current.xsItemSpacing)
.padding(horizontal = LocalDimensions.current.xsSpacing)
.width(IntrinsicSize.Max)
)
}
@ -362,7 +361,7 @@ fun FileDetails(fileDetails: List<TitledText>) {
fun TitledErrorText(titledText: TitledText?) {
TitledText(
titledText,
style = base,
style = LocalType.current.base,
color = LocalColors.current.danger
)
}
@ -371,7 +370,7 @@ fun TitledErrorText(titledText: TitledText?) {
fun TitledMonospaceText(titledText: TitledText?) {
TitledText(
titledText,
style = baseMonospace
style = LocalType.current.base.monospace()
)
}
@ -379,7 +378,7 @@ fun TitledMonospaceText(titledText: TitledText?) {
fun TitledText(
titledText: TitledText?,
modifier: Modifier = Modifier,
style: TextStyle = base,
style: TextStyle = LocalType.current.base,
color: Color = Color.Unspecified
) {
titledText?.apply {
@ -396,8 +395,8 @@ fun TitledText(
@Composable
fun TitledView(title: GetString, modifier: Modifier = Modifier, content: @Composable () -> Unit) {
Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.xxxsItemSpacing)) {
Text(title.string(), style = baseBold)
Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.xxxsSpacing)) {
Text(title.string(), style = LocalType.current.base.bold())
content()
}
}

View File

@ -36,6 +36,7 @@ import org.session.libsession.messaging.contacts.Contact.ContactContext
import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.ThemeUtil.getThemedColor
import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.getColorFromAttr
import org.session.libsession.utilities.modifyLayoutParams
@ -382,7 +383,7 @@ class VisibleMessageView : FrameLayout {
private fun getMessageStatusInfo(message: MessageRecord): MessageStatusInfo = when {
message.isFailed ->
MessageStatusInfo(R.drawable.ic_delivery_status_failed,
resources.getColor(R.color.destructive, context.theme),
getThemedColor(context, R.attr.danger),
R.string.delivery_status_failed
)
message.isSyncFailed ->

View File

@ -15,6 +15,7 @@ import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewConversationBinding
import org.session.libsession.utilities.ThemeUtil
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities.highlightMentions
import org.thoughtcrime.securesms.database.RecipientDatabase.NOTIFY_TYPE_ALL
@ -67,7 +68,7 @@ class ConversationView : LinearLayout {
}
val unreadCount = thread.unreadCount
if (thread.recipient.isBlocked) {
binding.accentView.setBackgroundResource(R.color.destructive)
binding.accentView.setBackgroundColor(ThemeUtil.getThemedColor(context, R.attr.danger))
binding.accentView.visibility = View.VISIBLE
} else {
val accentColor = context.getAccentColor()
@ -120,7 +121,7 @@ class ConversationView : LinearLayout {
!thread.isOutgoing -> binding.statusIndicatorImageView.visibility = View.GONE
thread.isFailed -> {
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_error)?.mutate()
drawable?.setTint(ContextCompat.getColor(context, R.color.destructive))
drawable?.setTint(ThemeUtil.getThemedColor(context, R.attr.danger))
binding.statusIndicatorImageView.setImageDrawable(drawable)
}
thread.isPending -> binding.statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)

View File

@ -3,8 +3,8 @@ package org.thoughtcrime.securesms.home
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -14,24 +14,22 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.Divider
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.h8
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalType
@Composable
internal fun EmptyView(newAccount: Boolean) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(horizontal = LocalDimensions.current.homeEmptyViewMargin)
.padding(horizontal = 50.dp)
) {
Spacer(modifier = Modifier.weight(1f))
Icon(
@ -42,27 +40,27 @@ internal fun EmptyView(newAccount: Boolean) {
if (newAccount) {
Text(
stringResource(R.string.onboardingAccountCreated),
style = h4,
style = LocalType.current.h4,
textAlign = TextAlign.Center
)
Text(
stringResource(R.string.welcome_to_session),
style = base,
style = LocalType.current.base,
color = LocalColors.current.primary,
textAlign = TextAlign.Center
)
}
Divider(modifier = Modifier.padding(vertical = LocalDimensions.current.xsMargin))
Divider(modifier = Modifier.padding(vertical = LocalDimensions.current.smallSpacing))
Text(
stringResource(R.string.conversationsNone),
style = h8,
style = LocalType.current.h8,
textAlign = TextAlign.Center,
modifier = Modifier.padding(bottom = LocalDimensions.current.xsItemSpacing))
modifier = Modifier.padding(bottom = LocalDimensions.current.xsSpacing))
Text(
stringResource(R.string.onboardingHitThePlusButton),
style = small,
style = LocalType.current.small,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.weight(2f))
@ -72,7 +70,7 @@ internal fun EmptyView(newAccount: Boolean) {
@Preview
@Composable
fun PreviewEmptyView(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
EmptyView(newAccount = false)
@ -82,7 +80,7 @@ fun PreviewEmptyView(
@Preview
@Composable
fun PreviewEmptyViewNew(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
EmptyView(newAccount = true)

View File

@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.width
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -18,16 +18,15 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.SessionShieldIcon
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.SlimPrimaryOutlineButton
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.h8
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.theme.LocalType
@Composable
internal fun SeedReminder(startRecoveryPasswordActivity: () -> Unit) {
@ -43,25 +42,25 @@ internal fun SeedReminder(startRecoveryPasswordActivity: () -> Unit) {
Modifier
.background(LocalColors.current.backgroundSecondary)
.padding(
horizontal = LocalDimensions.current.smallMargin,
vertical = LocalDimensions.current.xsMargin
horizontal = LocalDimensions.current.spacing,
vertical = LocalDimensions.current.smallSpacing
)
) {
Column(Modifier.weight(1f)) {
Row {
Text(
stringResource(R.string.save_your_recovery_password),
style = h8
style = LocalType.current.h8
)
Spacer(Modifier.requiredWidth(LocalDimensions.current.xxsItemSpacing))
Spacer(Modifier.requiredWidth(LocalDimensions.current.xxsSpacing))
SessionShieldIcon()
}
Text(
stringResource(R.string.save_your_recovery_password_to_make_sure_you_don_t_lose_access_to_your_account),
style = small
style = LocalType.current.small
)
}
Spacer(Modifier.width(LocalDimensions.current.xxsMargin))
Spacer(Modifier.width(LocalDimensions.current.xsSpacing))
SlimPrimaryOutlineButton(
text = stringResource(R.string.continue_2),
modifier = Modifier
@ -76,7 +75,7 @@ internal fun SeedReminder(startRecoveryPasswordActivity: () -> Unit) {
@Preview
@Composable
private fun PreviewSeedReminder(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
SeedReminder {}

View File

@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.recyclerview.widget.RecyclerView
import network.loki.messenger.R
import org.session.libsession.utilities.ThemeUtil
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
@ -60,8 +61,9 @@ class MessageRequestsAdapter(
for (i in 0 until popupMenu.menu.size()) {
val item = popupMenu.menu.getItem(i)
val s = SpannableString(item.title)
s.setSpan(ForegroundColorSpan(context.getColor(R.color.destructive)), 0, s.length, 0)
item.iconTintList = ColorStateList.valueOf(context.getColor(R.color.destructive))
val danger = ThemeUtil.getThemedColor(context, R.attr.danger)
s.setSpan(ForegroundColorSpan(danger), 0, s.length, 0)
item.iconTintList = ColorStateList.valueOf(danger)
item.title = s
}
popupMenu.setForceShowIcon(true)

View File

@ -7,7 +7,7 @@ import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
@Composable
fun OnboardingBackPressAlertDialog(

View File

@ -5,6 +5,7 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -16,10 +17,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -40,23 +39,22 @@ import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.components.BorderlessHtmlButton
import org.thoughtcrime.securesms.ui.components.PrimaryFillButton
import org.thoughtcrime.securesms.ui.components.PrimaryOutlineButton
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.large
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import kotlin.time.Duration.Companion.milliseconds
@Preview
@Composable
private fun PreviewLandingScreen(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
LandingScreen({}, {}, {}, {})
@ -80,6 +78,7 @@ internal fun LandingScreen(
onDismissRequest = { isUrlDialogVisible = false },
title = stringResource(R.string.urlOpen),
text = stringResource(R.string.urlOpenBrowser),
showCloseButton = true, // display the 'x' button
buttons = listOf(
DialogButtonModel(
text = GetString(R.string.activity_landing_terms_of_service),
@ -107,24 +106,24 @@ internal fun LandingScreen(
Column {
Column(modifier = Modifier
.weight(1f)
.padding(horizontal = LocalDimensions.current.onboardingMargin)
.padding(horizontal = LocalDimensions.current.mediumSpacing)
) {
Spacer(modifier = Modifier.weight(1f))
Text(
stringResource(R.string.onboardingBubblePrivacyInYourPocket),
modifier = Modifier.align(Alignment.CenterHorizontally),
style = h4,
style = LocalType.current.h4,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(LocalDimensions.current.itemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.spacing))
LazyColumn(
state = listState,
modifier = Modifier
.heightIn(min = LocalDimensions.current.minScrollableViewHeight)
.heightIn(min = 200.dp)
.fillMaxWidth()
.weight(3f),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing)
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)
) {
items(
MESSAGES.take(count),
@ -140,7 +139,7 @@ internal fun LandingScreen(
Spacer(modifier = Modifier.weight(1f))
}
Column(modifier = Modifier.padding(horizontal = LocalDimensions.current.largeMargin)) {
Column(modifier = Modifier.padding(horizontal = LocalDimensions.current.xlargeSpacing)) {
PrimaryFillButton(
text = stringResource(R.string.onboardingAccountCreate),
modifier = Modifier
@ -149,7 +148,7 @@ internal fun LandingScreen(
.contentDescription(R.string.AccessibilityId_create_account_button),
onClick = createAccount
)
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
PrimaryOutlineButton(
stringResource(R.string.onboardingAccountExists),
modifier = Modifier
@ -166,7 +165,7 @@ internal fun LandingScreen(
.contentDescription(R.string.AccessibilityId_open_url),
onClick = { isUrlDialogVisible = true }
)
Spacer(modifier = Modifier.height(LocalDimensions.current.xxsItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.xxsSpacing))
}
}
}
@ -195,7 +194,7 @@ private fun MessageText(text: String, isOutgoing: Boolean, modifier: Modifier) {
Box(modifier = modifier then Modifier.fillMaxWidth()) {
MessageText(
text,
color = if (isOutgoing) LocalColors.current.backgroundBubbleSent else LocalColors.current.backgroundBubbleReceived,
color = if (isOutgoing) LocalColors.current.primary else LocalColors.current.backgroundBubbleReceived,
textColor = if (isOutgoing) LocalColors.current.textBubbleSent else LocalColors.current.textBubbleReceived,
modifier = Modifier.align(if (isOutgoing) Alignment.TopEnd else Alignment.TopStart)
)
@ -209,19 +208,17 @@ private fun MessageText(
modifier: Modifier = Modifier,
textColor: Color = Color.Unspecified
) {
Card(
modifier = modifier.fillMaxWidth(0.666f),
shape = MaterialTheme.shapes.small,
backgroundColor = color,
elevation = 0.dp
Box(
modifier = modifier.fillMaxWidth(0.666f)
.background(color = color, shape = MaterialTheme.shapes.small)
) {
Text(
text,
style = large,
style = LocalType.current.large,
color = textColor,
modifier = Modifier.padding(
horizontal = LocalDimensions.current.smallItemSpacing,
vertical = LocalDimensions.current.xsItemSpacing
horizontal = LocalDimensions.current.smallSpacing,
vertical = LocalDimensions.current.xsSpacing
)
)
}

View File

@ -13,8 +13,8 @@ import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -24,13 +24,12 @@ import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.flow.Flow
import network.loki.messenger.R
import org.thoughtcrime.securesms.onboarding.ui.ContinuePrimaryOutlineButton
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.components.MaybeScanQrCode
import org.thoughtcrime.securesms.ui.components.SessionOutlinedTextField
import org.thoughtcrime.securesms.ui.components.SessionTabRow
import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.theme.LocalType
private val TITLES = listOf(R.string.sessionRecoveryPassword, R.string.qrScan)
@ -75,29 +74,29 @@ private fun RecoveryPassword(state: State, onChange: (String) -> Unit = {}, onCo
.verticalScroll(rememberScrollState())
) {
Spacer(Modifier.weight(1f))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
Column(
modifier = Modifier.padding(horizontal = LocalDimensions.current.largeMargin)
modifier = Modifier.padding(horizontal = LocalDimensions.current.mediumSpacing)
) {
Row {
Text(
text = stringResource(R.string.sessionRecoveryPassword),
style = h4
style = LocalType.current.h4
)
Spacer(Modifier.width(LocalDimensions.current.xxsItemSpacing))
Spacer(Modifier.width(LocalDimensions.current.xxsSpacing))
Icon(
modifier = Modifier.align(Alignment.CenterVertically),
painter = painterResource(id = R.drawable.ic_shield_outline),
contentDescription = null,
)
}
Spacer(Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(Modifier.height(LocalDimensions.current.smallSpacing))
Text(
stringResource(R.string.activity_link_enter_your_recovery_password_to_load_your_account_if_you_haven_t_saved_it_you_can_find_it_in_your_app_settings),
style = base
style = LocalType.current.base
)
Spacer(Modifier.height(LocalDimensions.current.itemSpacing))
Spacer(Modifier.height(LocalDimensions.current.spacing))
SessionOutlinedTextField(
text = state.recoveryPhrase,
modifier = Modifier.fillMaxWidth(),
@ -110,7 +109,7 @@ private fun RecoveryPassword(state: State, onChange: (String) -> Unit = {}, onCo
)
}
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
Spacer(Modifier.weight(2f))
ContinuePrimaryOutlineButton(modifier = Modifier.align(Alignment.CenterHorizontally), onContinue)

View File

@ -3,17 +3,16 @@ package org.thoughtcrime.securesms.onboarding.loading
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.ProgressArc
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.h7
import org.thoughtcrime.securesms.ui.theme.LocalType
@Composable
internal fun LoadingScreen(progress: Float) {
@ -25,12 +24,12 @@ internal fun LoadingScreen(progress: Float) {
)
Text(
stringResource(R.string.waitOneMoment),
style = h7
style = LocalType.current.h7
)
Spacer(modifier = Modifier.height(LocalDimensions.current.xxxsItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.xxxsSpacing))
Text(
stringResource(R.string.loadAccountProgressMessage),
style = base
style = LocalType.current.base
)
Spacer(modifier = Modifier.weight(2f))
}

View File

@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -22,22 +22,15 @@ import network.loki.messenger.R
import org.thoughtcrime.securesms.onboarding.OnboardingBackPressAlertDialog
import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsViewModel.UiState
import org.thoughtcrime.securesms.onboarding.ui.ContinuePrimaryOutlineButton
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.CircularProgressIndicator
import org.thoughtcrime.securesms.ui.components.RadioButton
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.h8
import org.thoughtcrime.securesms.ui.h9
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.theme.LocalType
@Composable
internal fun MessageNotificationsScreen(
@ -63,11 +56,11 @@ internal fun MessageNotificationsScreen(
Column {
Spacer(Modifier.weight(1f))
Column(modifier = Modifier.padding(horizontal = LocalDimensions.current.onboardingMargin)) {
Text(stringResource(R.string.notificationsMessage), style = h4)
Spacer(Modifier.height(LocalDimensions.current.xsMargin))
Text(stringResource(R.string.onboardingMessageNotificationExplaination), style = base)
Spacer(Modifier.height(LocalDimensions.current.itemSpacing))
Column(modifier = Modifier.padding(horizontal = LocalDimensions.current.mediumSpacing)) {
Text(stringResource(R.string.notificationsMessage), style = LocalType.current.h4)
Spacer(Modifier.height(LocalDimensions.current.smallSpacing))
Text(stringResource(R.string.onboardingMessageNotificationExplaination), style = LocalType.current.base)
Spacer(Modifier.height(LocalDimensions.current.spacing))
}
NotificationRadioButton(
@ -107,8 +100,8 @@ private fun NotificationRadioButton(
RadioButton(
onClick = onClick,
modifier = modifier,
checked = checked,
contentPadding = PaddingValues(horizontal = LocalDimensions.current.margin, vertical = 7.dp)
selected = checked,
contentPadding = PaddingValues(horizontal = LocalDimensions.current.mediumSpacing, vertical = 7.dp)
) {
Box(
modifier = Modifier
@ -120,17 +113,18 @@ private fun NotificationRadioButton(
),
) {
Column(modifier = Modifier
.padding(horizontal = 15.dp)
.padding(top = 10.dp, bottom = 11.dp)) {
Text(stringResource(title), style = h8)
.padding(horizontal = LocalDimensions.current.smallSpacing,
vertical = LocalDimensions.current.xsSpacing)
) {
Text(stringResource(title), style = LocalType.current.h8)
Text(stringResource(explanation), style = small, modifier = Modifier.padding(top = 7.dp))
Text(stringResource(explanation), style = LocalType.current.small, modifier = Modifier.padding(top = LocalDimensions.current.xxsSpacing))
tag?.let {
Text(
stringResource(it),
modifier = Modifier.padding(top = 6.dp),
modifier = Modifier.padding(top = LocalDimensions.current.xxsSpacing),
color = LocalColors.current.primary,
style = h9
style = LocalType.current.h9
)
}
}
@ -141,7 +135,7 @@ private fun NotificationRadioButton(
@Preview
@Composable
private fun MessageNotificationsScreenPreview(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
MessageNotificationsScreen()

View File

@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -17,11 +17,10 @@ import androidx.compose.ui.tooling.preview.Preview
import network.loki.messenger.R
import org.thoughtcrime.securesms.onboarding.OnboardingBackPressAlertDialog
import org.thoughtcrime.securesms.onboarding.ui.ContinuePrimaryOutlineButton
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.components.SessionOutlinedTextField
import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.theme.LocalType
@Preview
@Composable
@ -52,18 +51,18 @@ internal fun PickDisplayName(
.verticalScroll(rememberScrollState())
) {
Spacer(Modifier.weight(1f))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
Column(
modifier = Modifier.padding(horizontal = LocalDimensions.current.largeMargin)
modifier = Modifier.padding(horizontal = LocalDimensions.current.mediumSpacing)
) {
Text(stringResource(state.title), style = h4)
Spacer(Modifier.height(LocalDimensions.current.smallItemSpacing))
Text(stringResource(state.title), style = LocalType.current.h4)
Spacer(Modifier.height(LocalDimensions.current.smallSpacing))
Text(
stringResource(state.description),
style = base,
modifier = Modifier.padding(bottom = LocalDimensions.current.xsItemSpacing))
Spacer(Modifier.height(LocalDimensions.current.itemSpacing))
style = LocalType.current.base,
modifier = Modifier.padding(bottom = LocalDimensions.current.xsSpacing))
Spacer(Modifier.height(LocalDimensions.current.spacing))
SessionOutlinedTextField(
text = state.displayName,
modifier = Modifier.fillMaxWidth(),
@ -76,7 +75,7 @@ internal fun PickDisplayName(
)
}
Spacer(modifier = Modifier.height(LocalDimensions.current.smallItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
Spacer(Modifier.weight(2f))
ContinuePrimaryOutlineButton(modifier = Modifier.align(Alignment.CenterHorizontally), onContinue)

View File

@ -6,7 +6,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.components.PrimaryOutlineButton
import org.thoughtcrime.securesms.ui.contentDescription
@ -17,8 +17,8 @@ fun ContinuePrimaryOutlineButton(modifier: Modifier, onContinue: () -> Unit) {
modifier = modifier
.contentDescription(R.string.AccessibilityId_continue)
.fillMaxWidth()
.padding(horizontal = LocalDimensions.current.largeMargin)
.padding(bottom = LocalDimensions.current.xxsMargin),
.padding(horizontal = LocalDimensions.current.xlargeSpacing)
.padding(bottom = LocalDimensions.current.smallSpacing),
onClick = onContinue,
)
}

View File

@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -25,14 +25,14 @@ import org.session.libsignal.utilities.PublicKeyValidation
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.database.threadDatabase
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.MaybeScanQrCode
import org.thoughtcrime.securesms.ui.components.QrImage
import org.thoughtcrime.securesms.ui.components.SessionTabRow
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.setComposeContent
import org.thoughtcrime.securesms.ui.small
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.util.start
private val TITLES = listOf(R.string.view, R.string.scan)
@ -93,14 +93,14 @@ private fun Tabs(accountId: String, errors: Flow<String>, onScan: (String) -> Un
fun QrPage(string: String) {
Column(
modifier = Modifier
.background(LocalColors.current.backgroundSecondary)
.padding(horizontal = LocalDimensions.current.margin)
.background(LocalColors.current.background)
.padding(horizontal = LocalDimensions.current.mediumSpacing)
.fillMaxSize()
) {
QrImage(
string = string,
modifier = Modifier
.padding(top = LocalDimensions.current.margin, bottom = LocalDimensions.current.xxsMargin)
.padding(top = LocalDimensions.current.mediumSpacing, bottom = LocalDimensions.current.xsSpacing)
.contentDescription(R.string.AccessibilityId_qr_code),
icon = R.drawable.session
)
@ -109,7 +109,7 @@ fun QrPage(string: String) {
text = stringResource(R.string.this_is_your_account_id_other_users_can_scan_it_to_start_a_conversation_with_you),
color = LocalColors.current.textSecondary,
textAlign = TextAlign.Center,
style = small
style = LocalType.current.small
)
}
}

View File

@ -77,8 +77,8 @@ import org.thoughtcrime.securesms.ui.Cell
import org.thoughtcrime.securesms.ui.Divider
import org.thoughtcrime.securesms.ui.LargeItemButton
import org.thoughtcrime.securesms.ui.LargeItemButtonWithDrawable
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.destructiveButtonColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.dangerButtonColors
import org.thoughtcrime.securesms.ui.components.PrimaryOutlineButton
import org.thoughtcrime.securesms.ui.components.PrimaryOutlineCopyButton
import org.thoughtcrime.securesms.ui.contentDescription
@ -448,9 +448,9 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
Column {
Row(
modifier = Modifier
.padding(horizontal = LocalDimensions.current.smallMargin)
.padding(top = LocalDimensions.current.xxxsMargin),
horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing),
.padding(horizontal = LocalDimensions.current.spacing)
.padding(top = LocalDimensions.current.xxsSpacing),
horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing),
) {
PrimaryOutlineButton(
stringResource(R.string.share),
@ -464,7 +464,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
)
}
Spacer(modifier = Modifier.height(LocalDimensions.current.itemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.spacing))
val hasPaths by hasPaths().collectAsState(initial = false)
@ -492,7 +492,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
}
LargeItemButton(R.string.activity_settings_help_button, R.drawable.ic_help, Modifier.contentDescription(R.string.AccessibilityId_help)) { show<HelpSettingsActivity>() }
Divider()
LargeItemButton(R.string.activity_settings_clear_all_data_button_title, R.drawable.ic_clear_data, Modifier.contentDescription(R.string.AccessibilityId_clear_data), destructiveButtonColors()) { ClearAllDataDialog().show(supportFragmentManager, "Clear All Data Dialog") }
LargeItemButton(R.string.activity_settings_clear_all_data_button_title, R.drawable.ic_message_details__trash, Modifier.contentDescription(R.string.AccessibilityId_clear_data), dangerButtonColors()) { ClearAllDataDialog().show(supportFragmentManager, "Clear All Data Dialog") }
}
}
}
@ -509,4 +509,4 @@ private fun LocalBroadcastManager.hasPaths(): Flow<Boolean> = callbackFlow {
registerReceiver(receiver, IntentFilter("pathsBuilt"))
awaitClose { unregisterReceiver(receiver) }
}.onStart { emit(Unit) }.map { OnionRequestAPI.paths.isNotEmpty() }
}.onStart { emit(Unit) }.map { OnionRequestAPI.paths.isNotEmpty() }

View File

@ -6,6 +6,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.ui.theme.selectedTheme
import org.thoughtcrime.securesms.util.ThemeState
import org.thoughtcrime.securesms.util.themeState
import javax.inject.Inject
@ -26,11 +27,17 @@ class AppearanceSettingsViewModel @Inject constructor(private val prefs: TextSec
prefs.setThemeStyle(newThemeStyle)
// update UI state
_uiState.value = prefs.themeState()
// force compose to refresh its style reference
selectedTheme = null
}
fun setNewFollowSystemSettings(followSystemSettings: Boolean) {
prefs.setFollowSystemSettings(followSystemSettings)
_uiState.value = prefs.themeState()
// force compose to refresh its style reference
selectedTheme = null
}
}

View File

@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -26,20 +26,19 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.SessionShieldIcon
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.components.QrImage
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
import org.thoughtcrime.securesms.ui.components.SlimOutlineCopyButton
import org.thoughtcrime.securesms.ui.components.border
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.extraSmallMonospace
import org.thoughtcrime.securesms.ui.h8
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.monospace
@Composable
internal fun RecoveryPasswordScreen(
@ -49,11 +48,11 @@ internal fun RecoveryPasswordScreen(
onHide:() -> Unit = {}
) {
Column(
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.xsMargin),
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing),
modifier = Modifier
.contentDescription(R.string.AccessibilityId_recovery_password)
.verticalScroll(rememberScrollState())
.padding(bottom = LocalDimensions.current.xsMargin)
.padding(bottom = LocalDimensions.current.smallSpacing)
) {
RecoveryPasswordCell(mnemonic, seed, copyMnemonic)
HideRecoveryPasswordCell(onHide)
@ -75,17 +74,17 @@ private fun RecoveryPasswordCell(
Row {
Text(
stringResource(R.string.sessionRecoveryPassword),
style = h8
style = LocalType.current.h8
)
Spacer(Modifier.width(LocalDimensions.current.xxsItemSpacing))
Spacer(Modifier.width(LocalDimensions.current.xxsSpacing))
SessionShieldIcon()
}
Spacer(modifier = Modifier.height(LocalDimensions.current.xxxsMargin))
Spacer(modifier = Modifier.height(LocalDimensions.current.xxsSpacing))
Text(
stringResource(R.string.recoveryPasswordDescription),
style = base
style = LocalType.current.base
)
AnimatedVisibility(!showQr) {
@ -99,7 +98,7 @@ private fun RecoveryPasswordCell(
QrImage(
seed,
modifier = Modifier
.padding(vertical = LocalDimensions.current.smallMargin)
.padding(vertical = LocalDimensions.current.spacing)
.contentDescription(R.string.AccessibilityId_qr_code),
contentPadding = 10.dp,
icon = R.drawable.session_shield
@ -108,7 +107,7 @@ private fun RecoveryPasswordCell(
AnimatedVisibility(!showQr) {
Row(
horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing),
horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing),
verticalAlignment = Alignment.CenterVertically
) {
SlimOutlineCopyButton(
@ -138,11 +137,11 @@ private fun RecoveryPassword(mnemonic: String) {
mnemonic,
modifier = Modifier
.contentDescription(R.string.AccessibilityId_recovery_password_container)
.padding(vertical = LocalDimensions.current.smallMargin)
.padding(vertical = LocalDimensions.current.spacing)
.border()
.padding(LocalDimensions.current.smallMargin),
.padding(LocalDimensions.current.spacing),
textAlign = TextAlign.Center,
style = extraSmallMonospace,
style = LocalType.current.extraSmall.monospace(),
color = LocalColors.current.run { if (isLight) text else primary },
)
}
@ -156,14 +155,14 @@ private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
) {
Text(
stringResource(R.string.recoveryPasswordHideRecoveryPassword),
style = h8
style = LocalType.current.h8
)
Text(
stringResource(R.string.recoveryPasswordHideRecoveryPasswordDescription),
style = base
style = LocalType.current.base
)
}
Spacer(modifier = Modifier.width(LocalDimensions.current.xxsMargin))
Spacer(modifier = Modifier.width(LocalDimensions.current.xsSpacing))
SlimOutlineButton(
text = stringResource(R.string.hide),
modifier = Modifier
@ -180,7 +179,7 @@ private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
@Preview
@Composable
private fun PreviewRecoveryPasswordScreen(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
RecoveryPasswordScreen(mnemonic = "voyage urban toyed maverick peculiar tuxedo penguin tree grass building listen speak withdraw terminal plane")

View File

@ -34,7 +34,7 @@ class RecoveryPasswordActivity : BaseActionBarActivity() {
showSessionDialog {
title(R.string.recoveryPasswordHidePermanently)
htmlText(R.string.recoveryPasswordHidePermanentlyDescription1)
destructiveButton(R.string.continue_2, R.string.AccessibilityId_continue) { onHideConfirm() }
dangerButton(R.string.continue_2, R.string.AccessibilityId_continue) { onHideConfirm() }
cancelButton()
}
}
@ -44,7 +44,7 @@ class RecoveryPasswordActivity : BaseActionBarActivity() {
title(R.string.recoveryPasswordHidePermanently)
text(R.string.recoveryPasswordHidePermanentlyDescription2)
cancelButton()
destructiveButton(
dangerButton(
R.string.yes,
contentDescription = R.string.AccessibilityId_confirm_button
) {

View File

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
@ -8,11 +9,13 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -20,9 +23,16 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.bold
class DialogButtonModel(
val text: GetString,
@ -32,29 +42,35 @@ class DialogButtonModel(
val onClick: () -> Unit = {},
)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AlertDialog(
onDismissRequest: () -> Unit,
title: String? = null,
text: String? = null,
content: @Composable () -> Unit = {},
buttons: List<DialogButtonModel>? = null
buttons: List<DialogButtonModel>? = null,
showCloseButton: Boolean = false,
content: @Composable () -> Unit = {}
) {
androidx.compose.material.AlertDialog(
onDismissRequest,
shape = MaterialTheme.shapes.small,
backgroundColor = LocalColors.current.backgroundSecondary,
buttons = {
Box {
IconButton(
onClick = onDismissRequest,
modifier = Modifier.align(Alignment.TopEnd)
) {
Icon(
painter = painterResource(id = R.drawable.ic_dialog_x),
tint = LocalColors.current.text,
contentDescription = "back"
)
BasicAlertDialog(
onDismissRequest = onDismissRequest,
content = {
Box(
modifier = Modifier.background(color = LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small)
) {
// only show the 'x' button is required
if(showCloseButton) {
IconButton(
onClick = onDismissRequest,
modifier = Modifier.align(Alignment.TopEnd)
) {
Icon(
painter = painterResource(id = R.drawable.ic_dialog_x),
tint = LocalColors.current.text,
contentDescription = "back"
)
}
}
Column(modifier = Modifier.fillMaxWidth()) {
@ -62,23 +78,23 @@ fun AlertDialog(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(top = LocalDimensions.current.smallItemSpacing)
.padding(horizontal = LocalDimensions.current.smallItemSpacing)
.padding(top = LocalDimensions.current.smallSpacing)
.padding(horizontal = LocalDimensions.current.smallSpacing)
) {
title?.let {
Text(
it,
textAlign = TextAlign.Center,
style = h7,
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsItemSpacing)
style = LocalType.current.h7,
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsSpacing)
)
}
text?.let {
Text(
it,
textAlign = TextAlign.Center,
style = large,
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsItemSpacing)
style = LocalType.current.large,
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsSpacing)
)
}
content()
@ -116,12 +132,59 @@ fun DialogButton(text: String, modifier: Modifier, color: Color = Color.Unspecif
Text(
text,
color = color.takeOrElse { LocalColors.current.text },
style = largeBold,
style = LocalType.current.large.bold(),
textAlign = TextAlign.Center,
modifier = Modifier.padding(
top = LocalDimensions.current.smallItemSpacing,
bottom = LocalDimensions.current.itemSpacing
top = LocalDimensions.current.smallSpacing,
bottom = LocalDimensions.current.spacing
)
)
}
}
@Preview
@Composable
fun PreviewSimpleDialog(){
PreviewTheme {
AlertDialog(
onDismissRequest = {},
title = stringResource(R.string.warning),
text = stringResource(R.string.you_cannot_go_back_further_in_order_to_stop_loading_your_account_session_needs_to_quit),
buttons = listOf(
DialogButtonModel(
GetString(stringResource(R.string.quit)),
color = LocalColors.current.danger,
onClick = {}
),
DialogButtonModel(
GetString(stringResource(R.string.cancel))
)
)
)
}
}
@Preview
@Composable
fun PreviewXCloseDialog(){
PreviewTheme {
AlertDialog(
title = stringResource(R.string.urlOpen),
text = stringResource(R.string.urlOpenBrowser),
showCloseButton = true, // display the 'x' button
buttons = listOf(
DialogButtonModel(
text = GetString(R.string.activity_landing_terms_of_service),
contentDescription = GetString(R.string.AccessibilityId_terms_of_service_button),
onClick = {}
),
DialogButtonModel(
text = GetString(R.string.activity_landing_privacy_policy),
contentDescription = GetString(R.string.AccessibilityId_privacy_policy_button),
onClick = {}
)
),
onDismissRequest = {}
)
}
}

View File

@ -16,12 +16,8 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Card
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@ -37,26 +33,27 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.blackAlpha40
import org.thoughtcrime.securesms.ui.theme.pillShape
import kotlin.math.absoluteValue
import kotlin.math.sign
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun BoxScope.HorizontalPagerIndicator(pagerState: PagerState) {
if (pagerState.pageCount >= 2) Card(
shape = pillShape,
backgroundColor = Color.Black.copy(alpha = 0.4f),
if (pagerState.pageCount >= 2) Box(
modifier = Modifier
.background(color = blackAlpha40, shape = pillShape)
.align(Alignment.BottomCenter)
.padding(8.dp)
.padding(LocalDimensions.current.xxsSpacing)
) {
Box(modifier = Modifier.padding(8.dp)) {
Box(modifier = Modifier.padding(LocalDimensions.current.xxsSpacing)) {
ClickableHorizontalPagerIndicator(
pagerState = pagerState,
pageCount = pagerState.pageCount,
activeColor = Color.White,
inactiveColor = LocalColors.current.textSecondary)
pageCount = pagerState.pageCount
)
}
}
}
@ -73,9 +70,9 @@ fun ClickableHorizontalPagerIndicator(
pageCount: Int,
modifier: Modifier = Modifier,
pageIndexMapping: (Int) -> Int = { it },
activeColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
inactiveColor: Color = activeColor.copy(ContentAlpha.disabled),
indicatorWidth: Dp = 8.dp,
activeColor: Color = Color.White,
inactiveColor: Color = LocalColors.current.disabled,
indicatorWidth: Dp = LocalDimensions.current.xxsSpacing,
indicatorHeight: Dp = indicatorWidth,
spacing: Dp = indicatorWidth,
indicatorShape: Shape = CircleShape,
@ -115,9 +112,9 @@ private fun HorizontalPagerIndicator(
pageCount: Int,
modifier: Modifier = Modifier,
pageIndexMapping: (Int) -> Int = { it },
activeColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
inactiveColor: Color = activeColor.copy(ContentAlpha.disabled),
indicatorWidth: Dp = 8.dp,
activeColor: Color = Color.White,
inactiveColor: Color = LocalColors.current.disabled,
indicatorWidth: Dp = LocalDimensions.current.xxsSpacing,
indicatorHeight: Dp = indicatorWidth,
spacing: Dp = indicatorWidth,
indicatorShape: Shape = CircleShape,

View File

@ -7,13 +7,13 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
@ -24,14 +24,14 @@ import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.ButtonColors
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.RadioButton
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.Card
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
@ -52,6 +52,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
@ -61,14 +62,15 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.runIf
import org.thoughtcrime.securesms.components.ProfilePictureView
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.OptionsCard
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.divider
import org.thoughtcrime.securesms.ui.color.radioButtonColors
import org.thoughtcrime.securesms.ui.color.transparentButtonColors
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.OptionsCardData
import org.thoughtcrime.securesms.ui.components.SmallCircularProgressIndicator
import org.thoughtcrime.securesms.ui.components.TitledRadioButton
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.transparentButtonColors
import kotlin.math.min
import kotlin.math.roundToInt
@ -92,18 +94,25 @@ data class RadioOption<T>(
)
@Composable
fun <T> OptionsCard(card: OptionsCard<T>, callbacks: Callbacks<T>) {
Text(
card.title(),
style = base
)
CellNoMargin {
LazyColumn(
modifier = Modifier.heightIn(max = 5000.dp)
) {
itemsIndexed(card.options) { i, it ->
if (i != 0) Divider()
TitledRadioButton(it) { callbacks.setValue(it.value) }
fun <T> OptionsCard(card: OptionsCardData<T>, callbacks: Callbacks<T>) {
Column {
Text(
modifier = Modifier.padding(start = LocalDimensions.current.smallSpacing),
text = card.title(),
style = LocalType.current.base,
color = LocalColors.current.textSecondary
)
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
CellNoMargin {
LazyColumn(
modifier = Modifier.heightIn(max = 5000.dp)
) {
itemsIndexed(card.options) { i, it ->
if (i != 0) Divider()
TitledRadioButton(option = it) { callbacks.setValue(it.value) }
}
}
}
}
@ -117,7 +126,10 @@ fun LargeItemButtonWithDrawable(
colors: ButtonColors = transparentButtonColors(),
onClick: () -> Unit
) {
ItemButtonWithDrawable(textId, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight), h8, colors, onClick)
ItemButtonWithDrawable(
textId, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight),
LocalType.current.h8, colors, onClick
)
}
@Composable
@ -125,7 +137,7 @@ fun ItemButtonWithDrawable(
@StringRes textId: Int,
@DrawableRes icon: Int,
modifier: Modifier = Modifier,
textStyle: TextStyle = xl,
textStyle: TextStyle = LocalType.current.xl,
colors: ButtonColors = transparentButtonColors(),
onClick: () -> Unit
) {
@ -155,7 +167,10 @@ fun LargeItemButton(
colors: ButtonColors = transparentButtonColors(),
onClick: () -> Unit
) {
ItemButton(textId, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight), h8, colors, onClick)
ItemButton(
textId, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight),
LocalType.current.h8, colors, onClick
)
}
/**
@ -166,7 +181,7 @@ fun ItemButton(
@StringRes textId: Int,
@DrawableRes icon: Int,
modifier: Modifier = Modifier,
textStyle: TextStyle = xl,
textStyle: TextStyle = LocalType.current.xl,
colors: ButtonColors = transparentButtonColors(),
onClick: () -> Unit
) {
@ -196,7 +211,7 @@ fun ItemButton(
text: String,
icon: @Composable BoxScope.() -> Unit,
modifier: Modifier = Modifier,
textStyle: TextStyle = xl,
textStyle: TextStyle = LocalType.current.xl,
colors: ButtonColors = transparentButtonColors(),
onClick: () -> Unit
) {
@ -208,27 +223,42 @@ fun ItemButton(
) {
Box(
modifier = Modifier
.width(80.dp)
.width(50.dp)
.wrapContentHeight()
.align(Alignment.CenterVertically)
) {
icon()
}
Spacer(modifier = Modifier.width(LocalDimensions.current.smallSpacing))
Text(
text,
Modifier
.fillMaxWidth()
.padding(vertical = LocalDimensions.current.xsItemSpacing)
.padding(vertical = LocalDimensions.current.xsSpacing)
.align(Alignment.CenterVertically),
style = textStyle
)
}
}
@Preview
@Composable
fun PrewviewItemButton() {
PreviewTheme {
ItemButton(
textId = R.string.activity_create_group_title,
icon = R.drawable.ic_group,
onClick = {}
)
}
}
@Composable
fun Cell(
padding: Dp = 0.dp,
margin: Dp = LocalDimensions.current.margin,
margin: Dp = LocalDimensions.current.spacing,
content: @Composable () -> Unit
) {
CellWithPaddingAndMargin(padding, margin) { content() }
@ -240,64 +270,22 @@ fun CellNoMargin(content: @Composable () -> Unit) {
@Composable
fun CellWithPaddingAndMargin(
padding: Dp = LocalDimensions.current.smallMargin,
margin: Dp = LocalDimensions.current.margin,
padding: Dp = LocalDimensions.current.spacing,
margin: Dp = LocalDimensions.current.spacing,
content: @Composable () -> Unit
) {
Card(
backgroundColor = LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.medium,
elevation = 0.dp,
Box(
modifier = Modifier
.padding(horizontal = margin)
.background(color = LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small)
.wrapContentHeight()
.fillMaxWidth()
.padding(horizontal = margin),
.fillMaxWidth(),
) {
Box(Modifier.padding(padding)) { content() }
}
}
@Composable
fun <T> TitledRadioButton(option: RadioOption<T>, onClick: () -> Unit) {
val color = if (option.enabled) LocalColors.current.text else LocalColors.current.disabled
Row(
horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallItemSpacing),
modifier = Modifier
.runIf(option.enabled) { clickable { if (!option.selected) onClick() } }
.heightIn(min = 60.dp)
.padding(horizontal = LocalDimensions.current.margin)
.contentDescription(option.contentDescription)
) {
Column(modifier = Modifier
.weight(1f)
.align(Alignment.CenterVertically)) {
Column {
Text(
text = option.title(),
style = large,
color = color
)
option.subtitle?.let {
Text(
text = it(),
style = extraSmall,
color = color
)
}
}
}
RadioButton(
selected = option.selected,
onClick = null,
modifier = Modifier
.height(26.dp)
.align(Alignment.CenterVertically),
enabled = option.enabled,
colors = LocalColors.current.radioButtonColors()
)
}
}
@Composable
fun Modifier.contentDescription(text: GetString?): Modifier {
return text?.let {
@ -357,10 +345,10 @@ fun Modifier.fadingEdges(
@Composable
fun Divider(modifier: Modifier = Modifier, startIndent: Dp = 0.dp) {
androidx.compose.material.Divider(
modifier = modifier.padding(horizontal = LocalDimensions.current.xsMargin),
color = LocalColors.current.divider,
startIndent = startIndent
HorizontalDivider(
modifier = modifier.padding(horizontal = LocalDimensions.current.smallSpacing)
.padding(start = startIndent),
color = LocalColors.current.borders,
)
}
@ -392,7 +380,7 @@ fun ProgressArc(progress: Float, modifier: Modifier = Modifier) {
"${text}%",
color = Color.White,
modifier = Modifier.align(Alignment.Center),
style = h2
style = LocalType.current.h2
)
}
}

View File

@ -1,32 +0,0 @@
package org.thoughtcrime.securesms.ui
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
val LocalDimensions = staticCompositionLocalOf { Dimensions() }
data class Dimensions(
val xxxsItemSpacing: Dp = 4.dp,
val xxsItemSpacing: Dp = 8.dp,
val xsItemSpacing: Dp = 12.dp,
val smallItemSpacing: Dp = 16.dp,
val itemSpacing: Dp = 24.dp,
val xxxsMargin: Dp = 8.dp,
val xxsMargin: Dp = 12.dp,
val xsMargin: Dp = 16.dp,
val smallMargin: Dp = 24.dp,
val margin: Dp = 32.dp,
val onboardingMargin: Dp = 36.dp,
val largeMargin: Dp = 64.dp,
val homeEmptyViewMargin: Dp = 50.dp,
val dividerIndent: Dp = 80.dp,
val appBarHeight: Dp = 64.dp,
val minScrollableViewHeight: Dp = 200.dp,
val minLargeItemButtonHeight: Dp = 60.dp,
val indicatorHeight: Dp = 4.dp,
val borderStroke: Dp = 1.dp
)

View File

@ -1,59 +0,0 @@
package org.thoughtcrime.securesms.ui
import androidx.compose.material.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontFamily.Companion.Monospace
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
fun boldStyle(size: TextUnit) = TextStyle.Default.copy(
fontSize = size,
lineHeight = size * 1.2,
fontWeight = FontWeight.Bold,
)
fun defaultStyle(size: TextUnit, fontFamily: FontFamily? = TextStyle.Default.fontFamily) = TextStyle.Default.copy(
fontSize = size,
lineHeight = size * 1.2,
fontFamily = fontFamily
)
val xl = defaultStyle(18.sp)
val large = defaultStyle(16.sp)
val largeBold = boldStyle(16.sp)
val base = defaultStyle(14.sp)
val baseBold = boldStyle(14.sp)
val baseMonospace = defaultStyle(14.sp, fontFamily = Monospace)
val small = defaultStyle(12.sp)
val smallBold = boldStyle(12.sp)
val smallMonospace = defaultStyle(12.sp, fontFamily = Monospace)
val extraSmall = defaultStyle(11.sp)
val extraSmallBold = boldStyle(11.sp)
val extraSmallMonospace = defaultStyle(11.sp, fontFamily = Monospace)
val fine = defaultStyle(9.sp)
val h1 = boldStyle(36.sp)
val h2 = boldStyle(32.sp)
val h3 = boldStyle(29.sp)
val h4 = boldStyle(26.sp)
val h5 = boldStyle(23.sp)
val h6 = boldStyle(20.sp)
val h7 = boldStyle(18.sp)
val h8 = boldStyle(16.sp)
val h9 = boldStyle(14.sp)
val sessionTypography = Typography(
h1 = h1,
h2 = h2,
h3 = h3,
h4 = h4,
h5 = h5,
h6 = h6,
)

View File

@ -5,6 +5,7 @@ import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import org.thoughtcrime.securesms.ui.theme.SessionMaterialTheme
fun Activity.setComposeContent(content: @Composable () -> Unit) {
ComposeView(this)

View File

@ -1,233 +0,0 @@
package org.thoughtcrime.securesms.ui.color
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.RadioButtonDefaults
import androidx.compose.material.TabRowDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.primarySurface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.base
val LocalColors = staticCompositionLocalOf<Colors> { ClassicDark() }
interface Colors {
val isLight: Boolean
val primary: Color
val danger: Color
val disabled: Color
val background: Color
val backgroundSecondary: Color
val text: Color
val textSecondary: Color
val borders: Color
val textBubbleSent: Color
val backgroundBubbleReceived: Color
val textBubbleReceived: Color
val backgroundBubbleSent: Color get() = primary
val qrCodeContent: Color
val qrCodeBackground: Color
val primaryButtonFill: Color
val primaryButtonFillText: Color
}
fun Colors.text(isError: Boolean): Color = if (isError) danger else text
fun Colors.textSecondary(isError: Boolean): Color = if (isError) danger else textSecondary
fun Colors.borders(isError: Boolean): Color = if (isError) danger else borders
val Colors.textSelectionColors get() = TextSelectionColors(
handleColor = primary,
backgroundColor = primary.copy(alpha = 0.5f)
)
data class ClassicDark(override val primary: Color = primaryGreen): Colors {
override val isLight = false
override val danger = dangerDark
override val disabled = disabledDark
override val background = classicDark0
override val backgroundSecondary = classicDark1
override val text = classicDark6
override val textSecondary = classicDark5
override val borders = classicDark3
override val textBubbleSent = Color.Black
override val backgroundBubbleReceived = classicDark2
override val textBubbleReceived = Color.White
override val qrCodeContent = background
override val qrCodeBackground = text
override val primaryButtonFill = primary
override val primaryButtonFillText = Color.Black
}
data class ClassicLight(override val primary: Color = primaryGreen): Colors {
override val isLight = true
override val danger = dangerLight
override val disabled = disabledLight
override val background = classicLight6
override val backgroundSecondary = classicLight5
override val text = classicLight0
override val textSecondary = classicLight1
override val borders = classicLight3
override val textBubbleSent = Color.Black
override val backgroundBubbleReceived = classicLight4
override val textBubbleReceived = classicLight4
override val qrCodeContent = text
override val qrCodeBackground = backgroundSecondary
override val primaryButtonFill = text
override val primaryButtonFillText = Color.White
}
data class OceanDark(override val primary: Color = primaryBlue): Colors {
override val isLight = false
override val danger = dangerDark
override val disabled = disabledDark
override val background = oceanDark2
override val backgroundSecondary = oceanDark1
override val text = oceanDark7
override val textSecondary = oceanDark5
override val borders = oceanDark4
override val textBubbleSent = Color.Black
override val backgroundBubbleReceived = oceanDark4
override val textBubbleReceived = oceanDark4
override val qrCodeContent = background
override val qrCodeBackground = text
override val primaryButtonFill = primary
override val primaryButtonFillText = Color.Black
}
data class OceanLight(override val primary: Color = primaryBlue): Colors {
override val isLight = true
override val danger = dangerLight
override val disabled = disabledLight
override val background = oceanLight7
override val backgroundSecondary = oceanLight6
override val text = oceanLight1
override val textSecondary = oceanLight2
override val borders = oceanLight3
override val textBubbleSent = oceanLight1
override val backgroundBubbleReceived = oceanLight4
override val textBubbleReceived = oceanLight1
override val qrCodeContent = text
override val qrCodeBackground = backgroundSecondary
override val primaryButtonFill = text
override val primaryButtonFillText = Color.White
}
@Composable
fun Colors(name: String, colors: List<Color>) {
Column {
colors.forEachIndexed { i, it ->
Box(Modifier.background(it)) {
Text("$name: $i")
}
}
}
}
@Preview
@Composable
fun PreviewThemeColors(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
) {
PreviewTheme(colors) { ThemeColors() }
}
@Composable
private fun ThemeColors() {
Column {
Box(Modifier.background(MaterialTheme.colors.primary)) {
Text("primary", style = base)
}
Box(Modifier.background(MaterialTheme.colors.primaryVariant)) {
Text("primaryVariant", style = base)
}
Box(Modifier.background(MaterialTheme.colors.secondary)) {
Text("secondary", style = base)
}
Box(Modifier.background(MaterialTheme.colors.secondaryVariant)) {
Text("secondaryVariant", style = base)
}
Box(Modifier.background(MaterialTheme.colors.surface)) {
Text("surface", style = base)
}
Box(Modifier.background(MaterialTheme.colors.primarySurface)) {
Text("primarySurface", style = base)
}
Box(Modifier.background(MaterialTheme.colors.background)) {
Text("background", style = base)
}
Box(Modifier.background(MaterialTheme.colors.error)) {
Text("error", style = base)
}
}
}
@Composable
fun Colors.outlinedTextFieldColors(
isError: Boolean
) = TextFieldDefaults.outlinedTextFieldColors(
textColor = if (isError) danger else text,
cursorColor = if (isError) danger else text,
focusedBorderColor = borders,
unfocusedBorderColor = borders,
placeholderColor = if (isError) danger else textSecondary
)
val Colors.divider get() = text.copy(alpha = TabRowDefaults.DividerOpacity)
@Composable
fun Colors.radioButtonColors() = RadioButtonDefaults.colors(
selectedColor = primary,
unselectedColor = text,
disabledColor = disabled
)
@Composable
fun transparentButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent)
@Composable
fun destructiveButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent, contentColor = LocalColors.current.danger)
/**
* This class holds two instances of [Colors], [light] representing the [Colors] to use when the system is in a
* light theme, and [dark] representing the [Colors] to use when the system is in a dark theme.
*
* If the user has [followSystemSettings] turned on then [light] should be equal to [dark].
*/
data class LightDarkColors(
val light: Colors,
val dark: Colors
) {
@Composable
fun colors() = if (light == dark || isSystemInDarkTheme()) dark else light
}
/**
* Courtesy constructor that sets [light] and [dark] based on properties.
*/
fun LightDarkColors(isClassic: Boolean, isLight: Boolean, followSystemSettings: Boolean, primaryOrUnspecified: Color): LightDarkColors {
val primary = primaryOrUnspecified.takeOrElse { if (isClassic) primaryGreen else primaryBlue }
val light = when {
isLight || followSystemSettings -> if (isClassic) ClassicLight(primary) else OceanLight(primary)
else -> if (isClassic) ClassicDark(primary) else OceanDark(primary)
}
val dark = when {
isLight && !followSystemSettings -> if (isClassic) ClassicLight(primary) else OceanLight(primary)
else -> if (isClassic) ClassicDark(primary) else OceanDark(primary)
}
return LightDarkColors(light, dark)
}

View File

@ -1,34 +0,0 @@
package org.thoughtcrime.securesms.ui.color
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.TextSecurePreferences.Companion.BLUE_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_DARK
import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_LIGHT
import org.session.libsession.utilities.TextSecurePreferences.Companion.GREEN_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.OCEAN_LIGHT
import org.session.libsession.utilities.TextSecurePreferences.Companion.ORANGE_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.PINK_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.PURPLE_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.RED_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.YELLOW_ACCENT
/**
* Retrieve the current [Colors] from [TextSecurePreferences] and current system settings.
*/
@Composable
fun TextSecurePreferences.colors(): Colors = lightDarkColors().colors()
private fun TextSecurePreferences.lightDarkColors() = LightDarkColors(isClassic(), isLight(), getFollowSystemSettings(), primaryColor())
private fun TextSecurePreferences.isLight(): Boolean = getThemeStyle() in setOf(CLASSIC_LIGHT, OCEAN_LIGHT)
private fun TextSecurePreferences.isClassic(): Boolean = getThemeStyle() in setOf(CLASSIC_DARK, CLASSIC_LIGHT)
private fun TextSecurePreferences.primaryColor(): Color = when(getSelectedAccentColor()) {
GREEN_ACCENT -> primaryGreen
BLUE_ACCENT -> primaryBlue
PURPLE_ACCENT -> primaryPurple
PINK_ACCENT -> primaryPink
RED_ACCENT -> primaryRed
ORANGE_ACCENT -> primaryOrange
YELLOW_ACCENT -> primaryYellow
else -> Color.Unspecified
}

View File

@ -5,9 +5,9 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -15,16 +15,16 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
@Preview
@Composable
fun AppBarPreview(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
AppBar(title = "Title", {}, {})
@ -42,7 +42,7 @@ fun AppBar(title: String, onClose: () -> Unit = {}, onBack: (() -> Unit)? = null
}
}
Spacer(modifier = Modifier.weight(1f))
Text(text = title, style = h4)
Text(text = title, style = LocalType.current.h4)
Spacer(modifier = Modifier.weight(1f))
Box(contentAlignment = Alignment.Center, modifier = Modifier.size(LocalDimensions.current.appBarHeight)) {
IconButton(onClick = onClose) {

View File

@ -1,12 +1,12 @@
package org.thoughtcrime.securesms.ui.components
import androidx.compose.foundation.border
import androidx.compose.material.MaterialTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.SolidColor
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalColors
@Composable
fun Modifier.border() = this.border(

View File

@ -16,8 +16,8 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ButtonColors
import androidx.compose.material.Text
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -37,13 +37,14 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filter
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LaunchedEffectAsync
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.baseBold
import org.thoughtcrime.securesms.ui.buttonShape
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
import org.thoughtcrime.securesms.ui.theme.bold
import org.thoughtcrime.securesms.ui.theme.buttonShape
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
@ -65,16 +66,16 @@ fun Button(
content: @Composable RowScope.() -> Unit
) {
style.applyButtonConstraints {
androidx.compose.material.Button(
onClick,
modifier.heightIn(min = style.minHeight),
enabled,
interactionSource,
androidx.compose.material3.Button(
onClick = onClick,
modifier = modifier.heightIn(min = style.minHeight),
enabled = enabled,
interactionSource = interactionSource,
elevation = null,
shape,
border,
colors,
contentPadding
shape = shape,
border = border,
colors = colors,
contentPadding = contentPadding
) {
// Button sets LocalTextStyle, so text style is applied inside to override that.
style.applyTextConstraints {
@ -129,11 +130,11 @@ fun Button(
Button(text, onClick, ButtonType.Outline(LocalColors.current.primaryButtonFill), modifier, enabled)
}
@Composable fun PrimaryOutlineButton(onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, content: @Composable RowScope.() -> Unit) {
@Composable fun PrimaryOutlineButton(modifier: Modifier = Modifier, enabled: Boolean = true, onClick: () -> Unit, content: @Composable RowScope.() -> Unit) {
Button(onClick, ButtonType.Outline(LocalColors.current.primaryButtonFill), modifier, enabled, content = content)
}
@Composable fun SlimOutlineButton(onClick: () -> Unit, modifier: Modifier = Modifier, color: Color = LocalColors.current.text, enabled: Boolean = true, content: @Composable RowScope.() -> Unit) {
@Composable fun SlimOutlineButton(modifier: Modifier = Modifier, color: Color = LocalColors.current.text, enabled: Boolean = true, onClick: () -> Unit, content: @Composable RowScope.() -> Unit) {
Button(onClick, ButtonType.Outline(color), modifier, enabled, ButtonStyle.Slim, content = content)
}
@ -257,7 +258,7 @@ fun BorderlessButtonWithIcon(
text: String,
@DrawableRes iconRes: Int,
modifier: Modifier = Modifier,
style: TextStyle = baseBold,
style: TextStyle = LocalType.current.base.bold(),
color: Color = LocalColors.current.text,
onClick: () -> Unit
) {
@ -292,7 +293,7 @@ val MutableInteractionSource.releases
@Preview
@Composable
private fun VariousButtons(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
FlowRow(

View File

@ -1,21 +1,20 @@
package org.thoughtcrime.securesms.ui.components
import android.annotation.SuppressLint
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.material.LocalTextStyle
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.material3.LocalTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import org.thoughtcrime.securesms.ui.baseBold
import org.thoughtcrime.securesms.ui.extraSmall
import org.thoughtcrime.securesms.ui.extraSmallBold
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.bold
interface ButtonStyle {
@OptIn(ExperimentalMaterialApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("ComposableNaming")
@Composable fun applyButtonConstraints(content: @Composable () -> Unit) {
CompositionLocalProvider(
@ -27,26 +26,34 @@ interface ButtonStyle {
@SuppressLint("ComposableNaming")
@Composable fun applyTextConstraints(content: @Composable () -> Unit) {
CompositionLocalProvider(
LocalTextStyle provides textStyle,
LocalTextStyle provides textStyle(),
content = content
)
}
val textStyle: TextStyle
@Composable
fun textStyle() : TextStyle
val minHeight: Dp
object Large: ButtonStyle {
override val textStyle = baseBold.copy(textAlign = TextAlign.Center)
@Composable
override fun textStyle() = LocalType.current.base.bold()
.copy(textAlign = TextAlign.Center)
override val minHeight = 41.dp
}
object Slim: ButtonStyle {
override val textStyle = extraSmallBold.copy(textAlign = TextAlign.Center)
@Composable
override fun textStyle() = LocalType.current.extraSmall.bold()
.copy(textAlign = TextAlign.Center)
override val minHeight = 29.dp
}
object Borderless: ButtonStyle {
override val textStyle = extraSmall.copy(textAlign = TextAlign.Center)
@Composable
override fun textStyle() = LocalType.current.extraSmall
.copy(textAlign = TextAlign.Center)
override val minHeight = 37.dp
}
}

View File

@ -2,13 +2,13 @@ package org.thoughtcrime.securesms.ui.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
private val disabledBorder @Composable get() = BorderStroke(
width = LocalDimensions.current.borderStroke,
@ -35,9 +35,9 @@ interface ButtonType {
@Composable
override fun buttonColors() = ButtonDefaults.buttonColors(
contentColor = contentColor,
backgroundColor = Color.Unspecified,
containerColor = Color.Transparent,
disabledContentColor = LocalColors.current.disabled,
disabledBackgroundColor = Color.Unspecified
disabledContainerColor = Color.Transparent
)
}
@ -47,9 +47,9 @@ interface ButtonType {
@Composable
override fun buttonColors() = ButtonDefaults.buttonColors(
contentColor = LocalColors.current.background,
backgroundColor = LocalColors.current.text,
containerColor = LocalColors.current.text,
disabledContentColor = LocalColors.current.disabled,
disabledBackgroundColor = Color.Unspecified
disabledContainerColor = Color.Transparent
)
}
@ -59,9 +59,9 @@ interface ButtonType {
@Composable
override fun buttonColors() = ButtonDefaults.buttonColors(
contentColor = LocalColors.current.primaryButtonFillText,
backgroundColor = LocalColors.current.primaryButtonFill,
containerColor = LocalColors.current.primaryButtonFill,
disabledContentColor = LocalColors.current.disabled,
disabledBackgroundColor = Color.Unspecified
disabledContainerColor = Color.Transparent
)
}
@ -73,8 +73,9 @@ interface ButtonType {
@Composable
override fun buttonColors() = ButtonDefaults.outlinedButtonColors(
contentColor = color,
backgroundColor = Color.Transparent,
disabledContentColor = LocalColors.current.disabled
containerColor = Color.Transparent,
disabledContentColor = LocalColors.current.disabled,
disabledContainerColor = Color.Transparent
)
}
}

View File

@ -1,7 +1,7 @@
package org.thoughtcrime.securesms.ui.components
import androidx.compose.foundation.layout.size
import androidx.compose.material.LocalContentColor
import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -9,7 +9,7 @@ import androidx.compose.ui.unit.dp
@Composable
fun CircularProgressIndicator(color: Color = LocalContentColor.current) {
androidx.compose.material.CircularProgressIndicator(
androidx.compose.material3.CircularProgressIndicator(
modifier = Modifier.size(40.dp),
color = color,
strokeWidth = 2.dp
@ -18,7 +18,7 @@ fun CircularProgressIndicator(color: Color = LocalContentColor.current) {
@Composable
fun SmallCircularProgressIndicator(color: Color = LocalContentColor.current) {
androidx.compose.material.CircularProgressIndicator(
androidx.compose.material3.CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = color,
strokeWidth = 2.dp

View File

@ -22,11 +22,11 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Scaffold
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarHost
import androidx.compose.material.Text
import androidx.compose.material.rememberScaffoldState
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Snackbar
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@ -56,10 +56,9 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.xl
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import java.util.concurrent.Executors
private const val TAG = "NewMessageFragment"
@ -78,7 +77,6 @@ fun MaybeScanQrCode(
Box(
modifier = Modifier
.fillMaxSize()
.background(LocalColors.current.background)
) {
LocalSoftwareKeyboardController.current?.hide()
@ -94,10 +92,10 @@ fun MaybeScanQrCode(
) {
Text(
stringResource(R.string.activity_link_camera_permission_permanently_denied_configure_in_settings),
style = base,
style = LocalType.current.base,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.size(LocalDimensions.current.itemSpacing))
Spacer(modifier = Modifier.size(LocalDimensions.current.spacing))
OutlineButton(
stringResource(R.string.sessionSettings),
modifier = Modifier.align(Alignment.CenterHorizontally),
@ -107,14 +105,14 @@ fun MaybeScanQrCode(
} else {
Column(
modifier = Modifier
.background(color = LocalColors.current.backgroundSecondary)
.fillMaxSize()
.padding(LocalDimensions.current.largeMargin),
.padding(LocalDimensions.current.xlargeSpacing),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.weight(1f))
Text(stringResource(R.string.fragment_scan_qr_code_camera_access_explanation), style = xl, textAlign = TextAlign.Center)
Spacer(modifier = Modifier.height(LocalDimensions.current.itemSpacing))
Text(stringResource(R.string.fragment_scan_qr_code_camera_access_explanation),
style = LocalType.current.xl, textAlign = TextAlign.Center)
Spacer(modifier = Modifier.height(LocalDimensions.current.spacing))
PrimaryOutlineButton(
stringResource(R.string.cameraGrantAccess),
modifier = Modifier.fillMaxWidth(),
@ -158,13 +156,12 @@ fun ScanQrCode(errors: Flow<String>, onScan: (String) -> Unit) {
}
}
val scaffoldState = rememberScaffoldState()
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
LaunchedEffect(Unit) {
errors.collect { error ->
scaffoldState.snackbarHostState
snackbarHostState
.takeIf { it.currentSnackbarData == null }
?.run {
scope.launch {
@ -175,22 +172,21 @@ fun ScanQrCode(errors: Flow<String>, onScan: (String) -> Unit) {
// Don't use debounce() because many QR scans can come through each second,
// and each scan could restart the timer which could mean no scan gets
// through until the user stops scanning; quite perplexing.
showSnackbar(message = error)
snackbarHostState.showSnackbar(message = error)
}
}
}
}
Scaffold(
scaffoldState = scaffoldState,
snackbarHost = {
SnackbarHost(
hostState = scaffoldState.snackbarHostState,
modifier = Modifier.padding(LocalDimensions.current.smallItemSpacing)
hostState = snackbarHostState,
modifier = Modifier.padding(LocalDimensions.current.smallSpacing)
) { data ->
Snackbar(
snackbarData = data,
modifier = Modifier.padding(LocalDimensions.current.smallItemSpacing)
modifier = Modifier.padding(LocalDimensions.current.smallSpacing)
)
}
}
@ -204,7 +200,7 @@ fun ScanQrCode(errors: Flow<String>, onScan: (String) -> Unit) {
Box(
Modifier
.aspectRatio(1f)
.padding(LocalDimensions.current.itemSpacing)
.padding(LocalDimensions.current.spacing)
.clip(shape = RoundedCornerShape(26.dp))
.background(Color(0x33ffffff))
.align(Alignment.Center)

View File

@ -10,8 +10,8 @@ import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -32,15 +32,15 @@ import androidx.compose.ui.unit.dp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.util.QRCodeUtilities
@Composable
fun QrImage(
string: String?,
modifier: Modifier = Modifier,
contentPadding: Dp = LocalDimensions.current.smallItemSpacing,
contentPadding: Dp = LocalDimensions.current.smallSpacing,
icon: Int = R.drawable.session_shield
) {
var bitmap: Bitmap? by remember {
@ -56,10 +56,9 @@ fun QrImage(
}
}
Card(
backgroundColor = LocalColors.current.qrCodeBackground,
elevation = 0.dp,
modifier = modifier
Box(
modifier = modifier.background(color = LocalColors.current.qrCodeBackground,
shape = MaterialTheme.shapes.small)
) { Content(bitmap, icon, Modifier.padding(contentPadding), backgroundColor = LocalColors.current.qrCodeBackground) }
}

View File

@ -1,40 +1,58 @@
package org.thoughtcrime.securesms.ui.components
import android.content.ContentProvider
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.TextButton
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.transparentButtonColors
import network.loki.messenger.libsession_util.util.ExpiryMode
import org.thoughtcrime.securesms.conversation.disappearingmessages.ExpiryType
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.RadioOption
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.sessionTypography
import org.thoughtcrime.securesms.ui.theme.textEnabled
import org.thoughtcrime.securesms.ui.theme.transparentButtonColors
import kotlin.time.Duration.Companion.days
@Composable
fun RadioButton(
onClick: () -> Unit = {},
modifier: Modifier = Modifier,
checked: Boolean = false,
selected: Boolean = false,
enabled: Boolean = true,
contentPadding: PaddingValues = PaddingValues(),
content: @Composable RowScope.() -> Unit = {}
) {
@ -42,20 +60,22 @@ fun RadioButton(
modifier = modifier
.fillMaxWidth()
.selectable(
selected = checked,
selected = selected,
enabled = true,
role = Role.RadioButton,
onClick = onClick
),
enabled = enabled,
colors = transparentButtonColors(),
onClick = onClick,
shape = RectangleShape,
contentPadding = contentPadding
) {
content()
Spacer(modifier = Modifier.width(20.dp))
RadioButtonIndicator(
checked = checked,
selected = selected && enabled, // disabled radio shouldn't be selected
modifier = Modifier
.size(22.dp)
.align(Alignment.CenterVertically)
@ -65,12 +85,12 @@ fun RadioButton(
@Composable
private fun RadioButtonIndicator(
checked: Boolean,
selected: Boolean,
modifier: Modifier
) {
Box(modifier = modifier) {
AnimatedVisibility(
checked,
selected,
modifier = Modifier
.padding(2.5.dp)
.clip(CircleShape),
@ -91,9 +111,93 @@ private fun RadioButtonIndicator(
.aspectRatio(1f)
.border(
width = LocalDimensions.current.borderStroke,
color = LocalColors.current.text,
color = LocalContentColor.current,
shape = CircleShape
)
) {}
}
}
@Composable
fun <T> TitledRadioButton(
modifier: Modifier = Modifier,
option: RadioOption<T>,
onClick: () -> Unit
) {
RadioButton(
modifier = modifier.heightIn(min = 60.dp)
.contentDescription(option.contentDescription),
onClick = onClick,
selected = option.selected,
enabled = option.enabled,
contentPadding = PaddingValues(horizontal = LocalDimensions.current.spacing),
content = {
Column(
modifier = Modifier
.weight(1f)
.align(Alignment.CenterVertically)
) {
Column {
Text(
text = option.title(),
style = LocalType.current.large
)
option.subtitle?.let {
Text(
text = it(),
style = LocalType.current.extraSmall
)
}
}
}
}
)
}
@Preview
@Composable
fun PreviewTextRadioButton() {
PreviewTheme {
TitledRadioButton(
option = RadioOption<ExpiryMode>(
value = ExpiryType.AFTER_SEND.mode(7.days),
title = GetString(7.days),
subtitle = GetString("This is a subtitle"),
enabled = true,
selected = true
)
) {}
}
}
@Preview
@Composable
fun PreviewDisabledTextRadioButton() {
PreviewTheme {
TitledRadioButton(
option = RadioOption<ExpiryMode>(
value = ExpiryType.AFTER_SEND.mode(7.days),
title = GetString(7.days),
subtitle = GetString("This is a subtitle"),
enabled = false,
selected = true
)
) {}
}
}
@Preview
@Composable
fun PreviewDeselectedTextRadioButton() {
PreviewTheme {
TitledRadioButton(
option = RadioOption<ExpiryMode>(
value = ExpiryType.AFTER_SEND.mode(7.days),
title = GetString(7.days),
subtitle = GetString("This is a subtitle"),
enabled = true,
selected = false
)
) {}
}
}

View File

@ -1,15 +1,15 @@
package org.thoughtcrime.securesms.ui.components
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.Tab
import androidx.compose.material.TabRow
import androidx.compose.material.TabRowDefaults
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material.Text
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
@ -19,13 +19,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.color.divider
import org.thoughtcrime.securesms.ui.h8
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
import org.thoughtcrime.securesms.ui.theme.ThemeColors
private val TITLES = listOf(R.string.sessionRecoveryPassword, R.string.qrScan)
@ -33,32 +32,30 @@ private val TITLES = listOf(R.string.sessionRecoveryPassword, R.string.qrScan)
@Composable
fun SessionTabRow(pagerState: PagerState, titles: List<Int>) {
TabRow(
backgroundColor = Color.Unspecified,
containerColor = Color.Unspecified,
selectedTabIndex = pagerState.currentPage,
contentColor = LocalColors.current.text,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
TabRowDefaults.SecondaryIndicator(
Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]),
color = LocalColors.current.primary,
height = LocalDimensions.current.indicatorHeight
)
},
divider = { TabRowDefaults.Divider(color = LocalColors.current.divider) },
modifier = Modifier
.height(48.dp)
.background(color = Color.Unspecified)
divider = { HorizontalDivider(color = LocalColors.current.borders) }
) {
val animationScope = rememberCoroutineScope()
titles.forEachIndexed { i, it ->
Tab(
i == pagerState.currentPage,
modifier = Modifier.heightIn(min = 48.dp),
selected = i == pagerState.currentPage,
onClick = { animationScope.launch { pagerState.animateScrollToPage(i) } },
selectedContentColor = LocalColors.current.text,
unselectedContentColor = LocalColors.current.text,
) {
Text(
stringResource(id = it),
style = h8
text = stringResource(id = it),
style = LocalType.current.h8
)
}
}
@ -69,7 +66,7 @@ fun SessionTabRow(pagerState: PagerState, titles: List<Int>) {
@androidx.compose.ui.tooling.preview.Preview
@Composable
fun PreviewSessionTabRow(
@PreviewParameter(SessionColorsParameterProvider::class) colors: Colors
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) {
val pagerState = rememberPagerState { TITLES.size }

View File

@ -17,9 +17,9 @@ import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -37,15 +37,15 @@ import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.baseBold
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.borders
import org.thoughtcrime.securesms.ui.color.text
import org.thoughtcrime.securesms.ui.color.textSecondary
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.borders
import org.thoughtcrime.securesms.ui.theme.text
import org.thoughtcrime.securesms.ui.theme.textSecondary
import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.theme.LocalType
import org.thoughtcrime.securesms.ui.theme.bold
@Preview
@Composable
@ -85,7 +85,7 @@ fun SessionOutlinedTextField(
modifier: Modifier = Modifier,
contentDescription: String? = null,
onChange: (String) -> Unit = {},
textStyle: TextStyle = base,
textStyle: TextStyle = LocalType.current.base,
placeholder: String = "",
onContinue: () -> Unit = {},
error: String? = null,
@ -106,7 +106,7 @@ fun SessionOutlinedTextField(
if (text.isEmpty()) {
Text(
text = placeholder,
style = base,
style = LocalType.current.base,
color = LocalColors.current.textSecondary(isTextErrorColor),
modifier = Modifier.wrapContentSize()
.align(Alignment.CenterStart)
@ -130,13 +130,13 @@ fun SessionOutlinedTextField(
)
}
error?.let {
Spacer(modifier = Modifier.height(LocalDimensions.current.xsItemSpacing))
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
Text(
it,
modifier = Modifier.fillMaxWidth()
.contentDescription(R.string.AccessibilityId_error_message),
textAlign = TextAlign.Center,
style = baseBold,
style = LocalType.current.base.bold(),
color = LocalColors.current.danger
)
}
@ -148,7 +148,7 @@ fun AnnotatedTextWithIcon(
text: String,
@DrawableRes iconRes: Int,
modifier: Modifier = Modifier,
style: TextStyle = base,
style: TextStyle = LocalType.current.base,
color: Color = Color.Unspecified,
iconSize: TextUnit = 12.sp
) {

View File

@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.ui.color
package org.thoughtcrime.securesms.ui.theme
import androidx.compose.ui.graphics.Color

View File

@ -0,0 +1,24 @@
package org.thoughtcrime.securesms.ui.theme
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
val LocalDimensions = staticCompositionLocalOf { Dimensions() }
data class Dimensions(
val xxxsSpacing: Dp = 4.dp,
val xxsSpacing: Dp = 8.dp,
val xsSpacing: Dp = 12.dp,
val smallSpacing: Dp = 16.dp,
val spacing: Dp = 24.dp,
val mediumSpacing: Dp = 36.dp,
val xlargeSpacing: Dp = 64.dp,
val dividerIndent: Dp = 60.dp,
val appBarHeight: Dp = 64.dp,
val minLargeItemButtonHeight: Dp = 60.dp,
val indicatorHeight: Dp = 4.dp,
val borderStroke: Dp = 1.dp
)

View File

@ -0,0 +1,145 @@
package org.thoughtcrime.securesms.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
fun TextStyle.bold() = TextStyle.Default.copy(
fontWeight = FontWeight.Bold
)
fun TextStyle.monospace() = TextStyle.Default.copy(
fontFamily = FontFamily.Monospace
)
val sessionTypography = SessionTypography()
data class SessionTypography(
// Body
val xl: TextStyle = TextStyle(
fontSize = 18.sp,
lineHeight = 21.6.sp,
fontWeight = FontWeight.Normal
),
val large: TextStyle = TextStyle(
fontSize = 16.sp,
lineHeight = 19.2.sp,
fontWeight = FontWeight.Normal
),
val base: TextStyle = TextStyle(
fontSize = 14.sp,
lineHeight = 16.8.sp,
fontWeight = FontWeight.Normal
),
val small: TextStyle = TextStyle(
fontSize = 12.sp,
lineHeight = 14.4.sp,
fontWeight = FontWeight.Normal
),
val extraSmall: TextStyle = TextStyle(
fontSize = 11.sp,
lineHeight = 13.2.sp,
fontWeight = FontWeight.Normal
),
val fine: TextStyle = TextStyle(
fontSize = 9.sp,
lineHeight = 10.8.sp,
fontWeight = FontWeight.Normal
),
// Headings
val h1: TextStyle = TextStyle(
fontSize = 36.sp,
lineHeight = 43.2.sp,
fontWeight = FontWeight.Bold
),
val h2: TextStyle = TextStyle(
fontSize = 32.sp,
lineHeight = 38.4.sp,
fontWeight = FontWeight.Bold
),
val h3: TextStyle = TextStyle(
fontSize = 29.sp,
lineHeight = 34.8.sp,
fontWeight = FontWeight.Bold
),
val h4: TextStyle = TextStyle(
fontSize = 26.sp,
lineHeight = 31.2.sp,
fontWeight = FontWeight.Bold
),
val h5: TextStyle = TextStyle(
fontSize = 23.sp,
lineHeight = 27.6.sp,
fontWeight = FontWeight.Bold
),
val h6: TextStyle = TextStyle(
fontSize = 20.sp,
lineHeight = 24.sp,
fontWeight = FontWeight.Bold
),
val h7: TextStyle = TextStyle(
fontSize = 18.sp,
lineHeight = 21.6.sp,
fontWeight = FontWeight.Bold
),
val h8: TextStyle = TextStyle(
fontSize = 16.sp,
lineHeight = 19.2.sp,
fontWeight = FontWeight.Bold
),
val h9: TextStyle = TextStyle(
fontSize = 14.sp,
lineHeight = 16.8.sp,
fontWeight = FontWeight.Bold
)
) {
// An opinionated override of Material's defaults
@Composable
fun asMaterialTypography() = Typography(
// Display
displayLarge = h1,
displayMedium = h1,
displaySmall = h1,
// Headline
headlineLarge = h2,
headlineMedium = h3,
headlineSmall = h4,
// Title
titleLarge = h5,
titleMedium = h6,
titleSmall = h7,
// Body
bodyLarge = large,
bodyMedium = base,
bodySmall = small,
// Label
labelLarge = extraSmall,
labelMedium = fine,
labelSmall = fine
)
}

View File

@ -0,0 +1,10 @@
package org.thoughtcrime.securesms.ui.theme
/**
* This class holds two instances of [ThemeColors], [light] representing the [ThemeColors] to use when the system is in a
* light theme, and [dark] representing the [ThemeColors] to use when the system is in a dark theme.
*/
data class ThemeColorSet(
val light: ThemeColors,
val dark: ThemeColors
)

View File

@ -0,0 +1,206 @@
package org.thoughtcrime.securesms.ui.theme
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
interface ThemeColors {
// properties to override for each theme
val isLight: Boolean
val primary: Color
val danger: Color
val disabled: Color
val background: Color
val backgroundSecondary: Color
val text: Color
val textSecondary: Color
val borders: Color
val textBubbleSent: Color
val backgroundBubbleReceived: Color
val textBubbleReceived: Color
val qrCodeContent: Color
val qrCodeBackground: Color
val primaryButtonFill: Color
val primaryButtonFillText: Color
}
// extra functions and properties that work for all themes
val ThemeColors.textSelectionColors
get() = TextSelectionColors(
handleColor = primary,
backgroundColor = primary.copy(alpha = 0.5f)
)
fun ThemeColors.text(isError: Boolean): Color = if (isError) danger else text
fun ThemeColors.textSecondary(isError: Boolean): Color = if (isError) danger else textSecondary
fun ThemeColors.textEnabled(enabled: Boolean) = if (enabled) text else disabled
fun ThemeColors.borders(isError: Boolean): Color = if (isError) danger else borders
fun ThemeColors.toMaterialColors() = if (isLight) {
lightColorScheme(
primary = background,
secondary = backgroundSecondary,
tertiary = backgroundSecondary,
onPrimary = text,
onSecondary = text,
onTertiary = text,
background = background,
surface = background,
surfaceVariant = background,
onBackground = text,
onSurface = text,
scrim = blackAlpha40,
outline = text,
outlineVariant = text
)
} else {
darkColorScheme(
primary = background,
secondary = backgroundSecondary,
tertiary = backgroundSecondary,
onPrimary = text,
onSecondary = text,
onTertiary = text,
background = background,
surface = background,
surfaceVariant = background,
onBackground = text,
onSurface = text,
scrim = blackAlpha40,
outline = text,
outlineVariant = text
)
}
@Composable
fun transparentButtonColors() = ButtonDefaults.buttonColors(
containerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
disabledContentColor = LocalColors.current.disabled
)
@Composable
fun dangerButtonColors() = ButtonDefaults.buttonColors(
containerColor = Color.Transparent,
contentColor = LocalColors.current.danger
)
// Our themes
data class ClassicDark(override val primary: Color = primaryGreen) : ThemeColors {
override val isLight = false
override val danger = dangerDark
override val disabled = disabledDark
override val background = classicDark0
override val backgroundSecondary = classicDark1
override val text = classicDark6
override val textSecondary = classicDark5
override val borders = classicDark3
override val textBubbleSent = Color.Black
override val backgroundBubbleReceived = classicDark2
override val textBubbleReceived = Color.White
override val qrCodeContent = background
override val qrCodeBackground = text
override val primaryButtonFill = primary
override val primaryButtonFillText = Color.Black
}
data class ClassicLight(override val primary: Color = primaryGreen) : ThemeColors {
override val isLight = true
override val danger = dangerLight
override val disabled = disabledLight
override val background = classicLight6
override val backgroundSecondary = classicLight5
override val text = classicLight0
override val textSecondary = classicLight1
override val borders = classicLight3
override val textBubbleSent = text
override val backgroundBubbleReceived = classicLight4
override val textBubbleReceived = classicLight4
override val qrCodeContent = text
override val qrCodeBackground = backgroundSecondary
override val primaryButtonFill = text
override val primaryButtonFillText = Color.White
}
data class OceanDark(override val primary: Color = primaryBlue) : ThemeColors {
override val isLight = false
override val danger = dangerDark
override val disabled = disabledDark
override val background = oceanDark2
override val backgroundSecondary = oceanDark1
override val text = oceanDark7
override val textSecondary = oceanDark5
override val borders = oceanDark4
override val textBubbleSent = Color.Black
override val backgroundBubbleReceived = oceanDark4
override val textBubbleReceived = oceanDark4
override val qrCodeContent = background
override val qrCodeBackground = text
override val primaryButtonFill = primary
override val primaryButtonFillText = Color.Black
}
data class OceanLight(override val primary: Color = primaryBlue) : ThemeColors {
override val isLight = true
override val danger = dangerLight
override val disabled = disabledLight
override val background = oceanLight7
override val backgroundSecondary = oceanLight6
override val text = oceanLight1
override val textSecondary = oceanLight2
override val borders = oceanLight3
override val textBubbleSent = text
override val backgroundBubbleReceived = oceanLight4
override val textBubbleReceived = oceanLight1
override val qrCodeContent = text
override val qrCodeBackground = backgroundSecondary
override val primaryButtonFill = text
override val primaryButtonFillText = Color.White
}
@Preview
@Composable
fun PreviewThemeColors(
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
) {
PreviewTheme(colors) { ThemeColors() }
}
@Composable
private fun ThemeColors() {
Column {
Box(Modifier.background(LocalColors.current.primary)) {
Text("primary", style = LocalType.current.base)
}
Box(Modifier.background(LocalColors.current.background)) {
Text("background", style = LocalType.current.base)
}
Box(Modifier.background(LocalColors.current.backgroundSecondary)) {
Text("backgroundSecondary", style = LocalType.current.base)
}
Box(Modifier.background(LocalColors.current.text)) {
Text("text", style = LocalType.current.base)
}
Box(Modifier.background(LocalColors.current.textSecondary)) {
Text("textSecondary", style = LocalType.current.base)
}
Box(Modifier.background(LocalColors.current.danger)) {
Text("danger", style = LocalType.current.base)
}
Box(Modifier.background(LocalColors.current.borders)) {
Text("border", style = LocalType.current.base)
}
}
}

View File

@ -0,0 +1,65 @@
package org.thoughtcrime.securesms.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.TextSecurePreferences.Companion.BLUE_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.ORANGE_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.PINK_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.PURPLE_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.RED_ACCENT
import org.session.libsession.utilities.TextSecurePreferences.Companion.YELLOW_ACCENT
/**
* Returns the compose theme based on saved preferences
* Some behaviour is hardcoded to cater for legacy usage of people with themes already set
* But future themes will be picked and set directly from the "Appearance" screen
*/
@Composable
fun TextSecurePreferences.getComposeTheme(): ThemeColors {
val selectedTheme = getThemeStyle()
// get the chosen primary color from the preferences
val selectedPrimary = primaryColor()
// create a theme set with the appropriate primary
val colorSet = when(selectedTheme){
TextSecurePreferences.OCEAN_DARK,
TextSecurePreferences.OCEAN_LIGHT -> ThemeColorSet(
light = OceanLight(selectedPrimary),
dark = OceanDark(selectedPrimary)
)
else -> ThemeColorSet(
light = ClassicLight(selectedPrimary),
dark = ClassicDark(selectedPrimary)
)
}
// deliver the right set from the light/dark mode chosen
val theme = when{
getFollowSystemSettings() -> if(isSystemInDarkTheme()) colorSet.dark else colorSet.light
selectedTheme == TextSecurePreferences.CLASSIC_LIGHT ||
selectedTheme == TextSecurePreferences.OCEAN_LIGHT -> colorSet.light
else -> colorSet.dark
}
return theme
}
fun TextSecurePreferences.primaryColor(): Color = when(getSelectedAccentColor()) {
BLUE_ACCENT -> primaryBlue
PURPLE_ACCENT -> primaryPurple
PINK_ACCENT -> primaryPink
RED_ACCENT -> primaryRed
ORANGE_ACCENT -> primaryOrange
YELLOW_ACCENT -> primaryYellow
else -> primaryGreen
}

View File

@ -1,28 +1,26 @@
package org.thoughtcrime.securesms.ui
package org.thoughtcrime.securesms.ui.theme
import android.content.Context
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Shapes
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Shapes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import org.session.libsession.utilities.AppTextSecurePreferences
import org.thoughtcrime.securesms.ui.color.ClassicDark
import org.thoughtcrime.securesms.ui.color.ClassicLight
import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.OceanDark
import org.thoughtcrime.securesms.ui.color.OceanLight
import org.thoughtcrime.securesms.ui.color.colors
import org.thoughtcrime.securesms.ui.color.textSelectionColors
// Globally accessible composition local objects
val LocalColors = compositionLocalOf <ThemeColors> { ClassicDark() }
val LocalType = compositionLocalOf { sessionTypography }
var selectedTheme: ThemeColors? = null
/**
* Apply a Material2 compose theme based on user selections in SharedPreferences.
@ -31,24 +29,33 @@ import org.thoughtcrime.securesms.ui.color.textSelectionColors
fun SessionMaterialTheme(
content: @Composable () -> Unit
) {
SessionMaterialTheme(LocalContext.current.colors()) { content() }
// set the theme data if it hasn't been done yet
if(selectedTheme == null) {
// Some values can be set from the preferences, and if not should fallback to a default value
val context = LocalContext.current
val preferences = AppTextSecurePreferences(context)
selectedTheme = preferences.getComposeTheme()
}
SessionMaterialTheme(colors = selectedTheme ?: ClassicDark()) { content() }
}
/**
* Apply a given [Colors], and our typography and shapes as a Material 2 Compose Theme.
* Apply a given [ThemeColors], and our typography and shapes as a Material 2 Compose Theme.
**/
@Composable
fun SessionMaterialTheme(
colors: Colors,
colors: ThemeColors,
content: @Composable () -> Unit
) {
MaterialTheme(
colors = colors.toMaterialColors(),
typography = sessionTypography,
colorScheme = colors.toMaterialColors(),
typography = sessionTypography.asMaterialTypography(),
shapes = sessionShapes,
) {
CompositionLocalProvider(
LocalColors provides colors,
LocalType provides sessionTypography,
LocalContentColor provides colors.text,
LocalTextSelectionColors provides colors.textSelectionColors,
) {
@ -57,24 +64,6 @@ fun SessionMaterialTheme(
}
}
private fun Colors.toMaterialColors() = androidx.compose.material.Colors(
primary = background,
primaryVariant = backgroundSecondary,
secondary = background,
secondaryVariant = background,
background = background,
surface = background,
error = danger,
onPrimary = text,
onSecondary = text,
onBackground = text,
onSurface = text,
onError = text,
isLight = isLight
)
@Composable private fun Context.colors() = AppTextSecurePreferences(this).colors()
val pillShape = RoundedCornerShape(percent = 50)
val buttonShape = pillShape
@ -88,7 +77,7 @@ val sessionShapes = Shapes(
*/
@Composable
fun PreviewTheme(
colors: Colors = LocalColors.current,
colors: ThemeColors = LocalColors.current,
content: @Composable () -> Unit
) {
SessionMaterialTheme(colors) {
@ -98,6 +87,7 @@ fun PreviewTheme(
}
}
class SessionColorsParameterProvider : PreviewParameterProvider<Colors> {
// used for previews
class SessionColorsParameterProvider : PreviewParameterProvider<ThemeColors> {
override val values = sequenceOf(ClassicDark(), ClassicLight(), OceanDark(), OceanLight())
}

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="?android:textColorTertiary"/>
<item android:color="@color/destructive"/>
<item android:color="?danger"/>
</selector>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/destructive" android:state_selected="true"/>
<item android:color="?danger" android:state_selected="true"/>
<item android:color="@color/call_action_button" android:state_selected="false"/>
</selector>

View File

@ -3,9 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/destructive" />
<solid android:color="?danger" />
<corners android:radius="@dimen/dialog_button_corner_radius" />
<stroke android:width="@dimen/border_thickness" android:color="@color/destructive" />
<stroke android:width="@dimen/border_thickness" android:color="?danger" />
</shape>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/button_destructive">
android:color="@color/button_danger">
<item>
<shape android:shape="rectangle">
<solid android:color="?colorPrimary"/>
<corners android:radius="@dimen/medium_button_corner_radius" />
<stroke
android:color="@color/button_destructive"
android:color="@color/button_danger"
android:width="@dimen/border_thickness" />
</shape>
</item>

View File

@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="25dp"
android:height="26dp"
android:viewportWidth="25"
android:viewportHeight="26">
<path
android:pathData="M19.907,7.674H19.907H4.54H4.54C4.317,7.674 4.095,7.719 3.888,7.806L3.888,7.806C3.681,7.893 3.491,8.023 3.334,8.189C3.176,8.355 3.054,8.554 2.978,8.775L3.922,9.097L2.978,8.775C2.903,8.996 2.877,9.231 2.904,9.465L2.904,9.465L2.904,9.469L4.555,23.412C4.555,23.413 4.555,23.413 4.555,23.414C4.603,23.823 4.807,24.189 5.111,24.447C5.415,24.705 5.798,24.84 6.187,24.84H6.188H18.26H18.26C18.649,24.84 19.032,24.705 19.336,24.447C19.64,24.189 19.844,23.823 19.892,23.414C19.892,23.413 19.892,23.413 19.892,23.412L21.543,9.469L21.544,9.465C21.57,9.231 21.544,8.996 21.469,8.775L21.469,8.775C21.393,8.554 21.271,8.355 21.113,8.189C20.956,8.023 20.766,7.893 20.559,7.806L20.17,8.728L20.559,7.806C20.352,7.719 20.13,7.674 19.907,7.674ZM21.412,1.84H3.031C2.045,1.84 1.149,2.609 1.149,3.674V5.828C1.149,6.893 2.045,7.662 3.031,7.662H21.412C22.398,7.662 23.294,6.893 23.294,5.828V3.674C23.294,2.609 22.398,1.84 21.412,1.84Z"
android:strokeWidth="2"
android:fillColor="#FF3A3A"
android:strokeColor="?backgroundSecondary"/>
</vector>

View File

@ -3,7 +3,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/destructive">
android:tint="?danger">
<path
android:fillColor="@android:color/white"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?conversation_menu_background_color" />
<corners android:radius="12dp" />
</shape>

View File

@ -39,7 +39,7 @@
/>
<TextView
style="@style/Widget.Session.Button.Common.DestructiveOutline"
style="@style/Widget.Session.Button.Common.DangerOutline"
android:paddingHorizontal="@dimen/large_spacing"
android:paddingVertical="@dimen/small_spacing"
android:text="@string/ConversationActivity_unblock"

View File

@ -228,7 +228,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
android:background="@color/destructive"
android:background="?danger"
android:visibility="gone"
tools:visibility="visible">
@ -300,7 +300,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/AccessibilityId_block_message_request_button"
android:textColor="@color/destructive"
android:textColor="?danger"
android:paddingHorizontal="@dimen/massive_spacing"
android:paddingVertical="@dimen/small_spacing"
android:textSize="@dimen/text_size"
@ -334,7 +334,7 @@
<Button
android:id="@+id/declineMessageRequestButton"
style="@style/Widget.Session.Button.Common.DestructiveOutline"
style="@style/Widget.Session.Button.Common.DangerOutline"
android:contentDescription="@string/AccessibilityId_decline_message_request_button"
android:layout_width="0dp"
android:layout_height="@dimen/medium_button_height"

View File

@ -51,7 +51,7 @@
<Button
android:contentDescription="@string/AccessibilityId_clear_all_message_requests"
android:id="@+id/clearAllMessageRequestsButton"
style="@style/Widget.Session.Button.Common.DestructiveOutline"
style="@style/Widget.Session.Button.Common.DangerOutline"
android:layout_width="196dp"
android:layout_height="@dimen/medium_button_height"
android:layout_alignParentBottom="true"

View File

@ -175,7 +175,7 @@
android:src="@drawable/ic_baseline_call_end_24"
android:padding="@dimen/medium_spacing"
android:foregroundTint="@color/call_action_foreground"
android:backgroundTint="@color/destructive"
android:backgroundTint="?danger"
android:layout_width="@dimen/large_button_height"
android:layout_height="@dimen/large_button_height"
app:layout_constraintBottom_toBottomOf="parent"
@ -265,7 +265,7 @@
android:src="@drawable/ic_baseline_call_end_24"
android:padding="@dimen/medium_spacing"
android:foregroundTint="@color/call_action_foreground"
android:backgroundTint="@color/destructive"
android:backgroundTint="?danger"
android:layout_width="@dimen/large_button_height"
android:layout_height="@dimen/large_button_height"
android:layout_marginBottom="@dimen/very_large_spacing"

View File

@ -9,7 +9,7 @@
android:layout_marginHorizontal="@dimen/large_spacing"
android:layout_marginVertical="@dimen/medium_spacing"
android:text="@string/blocked_contacts_title"
android:textColor="@color/destructive"
android:textColor="?danger"
android:textSize="16sp"
android:textStyle="bold"
/>

View File

@ -44,7 +44,7 @@
android:orientation="horizontal">
<Button
style="@style/Widget.Session.Button.Dialog.DestructiveText"
style="@style/Widget.Session.Button.Dialog.DangerText"
android:id="@+id/clearAllDataButton"
android:layout_width="0dp"
android:layout_height="@dimen/dialog_button_height"

View File

@ -43,7 +43,7 @@
android:text="@string/cancel" />
<Button
style="@style/Widget.Session.Button.Dialog.DestructiveText"
style="@style/Widget.Session.Button.Dialog.DangerText"
android:id="@+id/sendSeedButton"
android:layout_width="0dp"
android:layout_height="@dimen/dialog_button_height"

View File

@ -62,7 +62,7 @@
<TextView
style="@style/Widget.Session.Button.Common.ProminentFilled"
android:backgroundTint="@color/destructive"
android:backgroundTint="?danger"
android:layout_marginHorizontal="@dimen/small_spacing"
android:id="@+id/declineButton"
android:layout_width="wrap_content"

View File

@ -5,7 +5,7 @@
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?conversation_menu_background_color">
android:background="@drawable/sheet_rounded_bg">
<TextView
android:id="@+id/titleText"

View File

@ -14,14 +14,14 @@
android:contentDescription="@string/AccessibilityId_delete_just_for_me"
style="@style/BottomSheetActionItem"
android:text="@string/delete_message_for_me"
android:textColor="@color/destructive"/>
android:textColor="?danger"/>
<TextView
android:id="@+id/deleteForEveryoneTextView"
android:contentDescription="@string/delete_message_for_everyone"
style="@style/BottomSheetActionItem"
android:text="@string/delete_message_for_everyone"
android:textColor="@color/destructive"/>
android:textColor="?danger"/>
<TextView
android:id="@+id/cancelTextView"

View File

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?conversation_menu_background_color">
android:background="@drawable/sheet_rounded_bg">
<TextView
android:id="@+id/titleText"

View File

@ -46,7 +46,7 @@
/>
<TextView
android:textColor="@color/destructive"
android:textColor="?danger"
android:id="@+id/cancelButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -4,7 +4,7 @@
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?conversation_menu_background_color">
android:background="@drawable/sheet_rounded_bg">
<TextView
android:id="@+id/titleText"

View File

@ -13,13 +13,13 @@
android:layout_width="13dp"
android:layout_height="13dp"
android:src="@drawable/ic_baseline_block_24"
app:tint="@color/destructive" />
app:tint="?danger" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="@color/destructive"
android:textColor="?danger"
android:textSize="16sp"
android:text="@string/recipient_preferences__block"
/>

View File

@ -31,7 +31,7 @@
android:layout_height="wrap_content"/>
<TextView
android:text="@string/message_requests_clear_all"
android:textColor="@color/destructive"
android:textColor="?danger"
android:visibility="gone"
android:id="@+id/header_view_clear_all"
android:layout_width="wrap_content"

View File

@ -62,6 +62,7 @@
android:textColor="?message_received_text_color"
android:textAlignment="center"
android:layout_gravity="center"
android:gravity="center"
tools:text="You missed a call"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -35,7 +35,7 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/destructive" />
android:backgroundTint="?danger" />
<TextView
android:id="@+id/recordingViewDurationTextView"
@ -121,7 +121,7 @@
android:alpha="0.5"
android:layout_centerInParent="true"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/destructive" />
android:backgroundTint="?danger" />
</RelativeLayout>
@ -136,7 +136,7 @@
android:layout_marginEnd="-8dp"
android:layout_marginBottom="0dp"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/destructive" >
android:backgroundTint="?danger" >
<ImageView
android:id="@+id/recordButtonOverlayImageView"

View File

@ -32,6 +32,7 @@
<attr name="onLightCell" format="reference|color"/>
<attr name="accentColor" format="reference|color"/>
<attr name="danger" format="reference|color"/>
<attr name="backgroundSecondary" format="reference|color"/>
<attr name="prominentButtonColor" format="reference|color"/>
<attr name="elementBorderColor" format="reference|color"/>

View File

@ -1,6 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<color name="destructive">#FF453A</color>
<color name="unimportant">#D8D8D8</color>
<color name="profile_picture_background">#353535</color>
<color name="action_bar_background">#161616</color>

View File

@ -108,9 +108,9 @@
<item name="android:textColor">?android:textColorPrimary</item>
</style>
<style name="Widget.Session.Button.Common.DestructiveOutline">
<item name="android:background">@drawable/destructive_outline_button_medium_background</item>
<item name="android:textColor">@color/button_destructive</item>
<style name="Widget.Session.Button.Common.DangerOutline">
<item name="android:background">@drawable/danger_outline_button_medium_background</item>
<item name="android:textColor">@color/button_danger</item>
</style>
<style name="Widget.Session.Button.Dialog" parent="">
@ -125,9 +125,9 @@
<item name="android:background">@drawable/unimportant_dialog_text_button_background</item>
</style>
<style name="Widget.Session.Button.Dialog.DestructiveText">
<item name="android:background">@drawable/destructive_dialog_text_button_background</item>
<item name="android:textColor">@color/destructive</item>
<style name="Widget.Session.Button.Dialog.DangerText">
<item name="android:background">@drawable/danger_dialog_text_button_background</item>
<item name="android:textColor">?danger</item>
</style>
<style name="Widget.Session.EditText.Compose" parent="@style/Signal.Text.Body">

View File

@ -58,7 +58,7 @@
<item name="prominentButtonColor">?colorAccent</item>
<item name="attachment_document_icon_small">@drawable/ic_document_small_dark</item>
<item name="attachment_document_icon_large">@drawable/ic_document_large_dark</item>
<item name="colorError">@color/destructive</item>
<item name="colorError">?danger</item>
</style>
<!-- This should be the default theme for the application. -->
@ -318,6 +318,7 @@
<item name="backgroundSecondary">@color/classic_dark_1</item>
<item name="colorControlNormal">?android:textColorPrimary</item>
<item name="colorControlActivated">?colorAccent</item>
<item name="danger">@color/danger_dark</item>
<item name="android:textColorPrimary">@color/classic_dark_6</item>
<item name="android:textColorSecondary">?android:textColorPrimary</item>
<item name="android:textColorTertiary">@color/classic_dark_5</item>
@ -399,6 +400,7 @@
<item name="colorPrimaryDark">@color/classic_light_6</item>
<item name="colorControlNormal">?android:textColorPrimary</item>
<item name="colorControlActivated">?colorAccent</item>
<item name="danger">@color/danger_light</item>
<item name="android:textColorPrimary">@color/classic_light_0</item>
<item name="android:textColorSecondary">@color/classic_light_1</item>
<item name="android:textColorTertiary">@color/classic_light_1</item>
@ -488,6 +490,7 @@
<item name="backgroundSecondary">@color/ocean_dark_1</item>
<item name="colorControlNormal">@color/ocean_dark_7</item>
<item name="colorControlActivated">?colorAccent</item>
<item name="danger">@color/danger_dark</item>
<item name="android:textColorPrimary">@color/ocean_dark_7</item>
<item name="android:textColorSecondary">@color/ocean_dark_5</item>
<item name="android:textColorTertiary">@color/ocean_dark_5</item>
@ -574,6 +577,7 @@
<item name="backgroundSecondary">@color/ocean_light_6</item>
<item name="colorControlNormal">@color/ocean_light_1</item>
<item name="colorControlActivated">?colorAccent</item>
<item name="danger">@color/danger_light</item>
<item name="android:textColorPrimary">@color/ocean_light_1</item>
<item name="android:textColorSecondary">@color/ocean_light_2</item>
<item name="android:textColorTertiary">@color/ocean_light_2</item>
@ -686,6 +690,7 @@
<item name="actionBarStyle">@style/Widget.Session.ActionBar</item>
<item name="prominentButtonColor">?colorAccent</item>
<item name="elementBorderColor">@color/classic_dark_3</item>
<item name="danger">@color/danger_dark</item>
<!-- Home screen -->
<item name="searchBackgroundColor">#1B1B1B</item>

View File

@ -25,7 +25,7 @@ import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.guava.Optional
import org.thoughtcrime.securesms.MainCoroutineRule
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.ExpiryRadioOption
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.OptionsCard
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.OptionsCardData
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.UiState
import org.thoughtcrime.securesms.database.GroupDatabase
import org.thoughtcrime.securesms.database.Storage
@ -87,7 +87,7 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
typeOption(ExpiryMode.NONE, selected = true),
timeOption(ExpiryType.AFTER_SEND, 12.hours),
@ -126,7 +126,7 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
typeOption(ExpiryMode.NONE, selected = false),
timeOption(ExpiryType.LEGACY, 12.hours),
@ -165,7 +165,7 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
typeOption(ExpiryMode.NONE, selected = true),
timeOption(ExpiryType.AFTER_SEND, 12.hours),
@ -205,7 +205,7 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
typeOption(ExpiryMode.NONE, enabled = false, selected = true),
timeOption(ExpiryType.AFTER_SEND, 12.hours, enabled = false),
@ -247,7 +247,7 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_delete_type,
typeOption(ExpiryMode.NONE, selected = true),
typeOption(12.hours, ExpiryType.AFTER_READ),
@ -286,13 +286,13 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_delete_type,
typeOption(ExpiryMode.NONE),
typeOption(time, ExpiryType.AFTER_READ),
typeOption(time, ExpiryType.AFTER_SEND, selected = true)
),
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
timeOption(ExpiryType.AFTER_SEND, 12.hours, selected = true),
timeOption(ExpiryType.AFTER_SEND, 1.days),
@ -332,14 +332,14 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_delete_type,
typeOption(ExpiryMode.NONE),
typeOption(time, ExpiryType.LEGACY, selected = true),
typeOption(12.hours, ExpiryType.AFTER_READ, enabled = false),
typeOption(1.days, ExpiryType.AFTER_SEND, enabled = false)
),
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
timeOption(ExpiryType.LEGACY, 12.hours, selected = true),
timeOption(ExpiryType.LEGACY, 1.days),
@ -379,13 +379,13 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_delete_type,
typeOption(ExpiryMode.NONE),
typeOption(12.hours, ExpiryType.AFTER_READ),
typeOption(time, ExpiryType.AFTER_SEND, selected = true)
),
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
timeOption(ExpiryType.AFTER_SEND, 12.hours),
timeOption(ExpiryType.AFTER_SEND, 1.days, selected = true),
@ -426,13 +426,13 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_delete_type,
typeOption(ExpiryMode.NONE),
typeOption(1.days, ExpiryType.AFTER_READ, selected = true),
typeOption(time, ExpiryType.AFTER_SEND)
),
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
timeOption(ExpiryType.AFTER_READ, 5.minutes),
timeOption(ExpiryType.AFTER_READ, 1.hours),
@ -479,13 +479,13 @@ class DisappearingMessagesViewModelTest {
viewModel.uiState.value
).isEqualTo(
UiState(
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_delete_type,
typeOption(ExpiryMode.NONE),
typeOption(12.hours, ExpiryType.AFTER_READ),
typeOption(1.days, ExpiryType.AFTER_SEND, selected = true)
),
OptionsCard(
OptionsCardData(
R.string.activity_disappearing_messages_timer,
timeOption(ExpiryType.AFTER_SEND, 12.hours),
timeOption(ExpiryType.AFTER_SEND, 1.days, selected = true),

View File

@ -1,6 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<color name="destructive">#FF453A</color>
<color name="unimportant">#D8D8D8</color>
<color name="profile_picture_background">#353535</color>
<color name="cell_background">#1B1B1B</color>