From 0824713ac5220c1e807b8a34daea5778bf099ad6 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jul 2023 00:12:42 +0930 Subject: [PATCH] Fix theming and polish --- .../conversation/v2/MessageDetailActivity.kt | 511 ++++++++++-------- .../org/thoughtcrime/securesms/ui/Colors.kt | 61 ++- .../thoughtcrime/securesms/ui/Components.kt | 51 +- .../org/thoughtcrime/securesms/ui/Themes.kt | 53 +- app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/themes.xml | 2 - 6 files changed, 408 insertions(+), 274 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt index f95f25719..46eeb4ecc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt @@ -13,9 +13,12 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState @@ -31,9 +34,11 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -55,8 +60,8 @@ import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAt import org.thoughtcrime.securesms.MediaPreviewActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.database.Storage +import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.mms.ImageSlide import org.thoughtcrime.securesms.mms.Slide import org.thoughtcrime.securesms.ui.AppTheme import org.thoughtcrime.securesms.ui.Avatar @@ -68,6 +73,7 @@ import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin import org.thoughtcrime.securesms.ui.Divider import org.thoughtcrime.securesms.ui.HorizontalPagerIndicator import org.thoughtcrime.securesms.ui.ItemButton +import org.thoughtcrime.securesms.ui.Theme import org.thoughtcrime.securesms.ui.blackAlpha40 import org.thoughtcrime.securesms.ui.colorDestructive import org.thoughtcrime.securesms.ui.destructiveButtonColors @@ -118,27 +124,32 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() { @Composable private fun MessageDetailsScreen() { val details by viewModel.details.observeAsState(MessageDetails()) - MessageDetails( - details, - onReply = { setResultAndFinish(ON_REPLY) }, - onResend = { setResultAndFinish(ON_RESEND) }, - onDelete = { setResultAndFinish(ON_DELETE) }, - onClickImage = { slide -> - // only open to downloaded images - if (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED) { - // Restart download here (on IO thread) - (slide.asAttachment() as? DatabaseAttachment)?.let { attachment -> - onAttachmentNeedsDownload(attachment.attachmentId.rowId, details.mmsRecord!!.getId()) + val threadDb = DatabaseComponent.get(this@MessageDetailActivity).threadDatabase() + AppTheme { + MessageDetails( + threadDb = threadDb, + messageDetails = details, + onReply = { setResultAndFinish(ON_REPLY) }, + onResend = { setResultAndFinish(ON_RESEND) }, + onDelete = { setResultAndFinish(ON_DELETE) }, + onClickImage = { slide -> + // only open to downloaded images + if (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED) { + // Restart download here (on IO thread) + (slide.asAttachment() as? DatabaseAttachment)?.let { attachment -> + onAttachmentNeedsDownload(attachment.attachmentId.rowId, details.mmsRecord!!.getId()) + } } - } - if (!slide.isInProgress) MediaPreviewActivity.getPreviewIntent( - this, - slide, - details.mmsRecord, - DatabaseComponent.get(this).threadDatabase().getRecipientForThreadId(details.mmsRecord!!.threadId), - ).let(::startActivity) - } - ) + if (!slide.isInProgress) MediaPreviewActivity.getPreviewIntent( + this, + slide, + details.mmsRecord, + threadDb.getRecipientForThreadId(details.mmsRecord!!.threadId), + ).let(::startActivity) + }, + onAttachmentNeedsDownload = ::onAttachmentNeedsDownload, + ) + } } private fun setResultAndFinish(code: Int) { @@ -149,254 +160,276 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() { finish() } - @Preview - @Composable - fun PreviewMessageDetails() { - MessageDetails( - MessageDetails( - attachments = listOf(), - sent = TitledText("Sent:", "6:12 AM Tue, 09/08/2022"), - received = TitledText("Received:", "6:12 AM Tue, 09/08/2022"), - error = TitledText("Error:", "Message failed to send"), - senderInfo = TitledText("Connor", "d4f1g54sdf5g1d5f4g65ds4564df65f4g65d54gdfsg"), - ) - ) - } - private fun onAttachmentNeedsDownload(attachmentId: Long, mmsId: Long) { lifecycleScope.launch(Dispatchers.IO) { JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId)) } } - @SuppressLint("ClickableViewAccessibility") - @Composable - fun MessageDetails( - messageDetails: MessageDetails, - onReply: () -> Unit = {}, - onResend: () -> Unit = {}, - onDelete: () -> Unit = {}, - onClickImage: (Slide) -> Unit = {}, - ) { - AppTheme { - Column( - modifier = Modifier.verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - messageDetails.record?.let { message -> - AndroidView( - modifier = Modifier.padding(horizontal = 32.dp), - factory = { - ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(it)).mainContainerConstraint.apply { - bind( - message, - thread = DatabaseComponent.get(this@MessageDetailActivity).threadDatabase().getRecipientForThreadId(message.threadId)!!, - onAttachmentNeedsDownload = ::onAttachmentNeedsDownload, - suppressThumbnails = true - ) +} - setOnTouchListener { _, event -> - if (event.actionMasked == ACTION_UP) onContentClick(event) - true - } - } - } - ) - } - Attachments(messageDetails.attachments) { onClickImage(it) } - MetadataCell(messageDetails) - Buttons( - messageDetails.error != null, - onReply, - onResend, - onDelete, - ) - } - } +@Composable +fun PreviewMessageDetails() { + AppTheme { + MessageDetails( + messageDetails = MessageDetails( + attachments = listOf(), + sent = TitledText("Sent:", "6:12 AM Tue, 09/08/2022"), + received = TitledText("Received:", "6:12 AM Tue, 09/08/2022"), + error = TitledText("Error:", "Message failed to send"), + senderInfo = TitledText("Connor", "d4f1g54sdf5g1d5f4g65ds4564df65f4g65d54"), + ) + ) } +} - @Composable - fun MetadataCell( - messageDetails: MessageDetails, +@SuppressLint("ClickableViewAccessibility") +@Composable +fun MessageDetails( + threadDb: ThreadDatabase? = null, + messageDetails: MessageDetails, + onReply: () -> Unit = {}, + onResend: (() -> Unit)? = null, + onDelete: () -> Unit = {}, + onClickImage: (Slide) -> Unit = {}, + onAttachmentNeedsDownload: (Long, Long) -> Unit = { _, _ -> } +) { + Column( + modifier = Modifier + .verticalScroll(rememberScrollState()) + .padding(vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) ) { - messageDetails.apply { - if (sent != null || received != null || senderInfo != null) CellWithPaddingAndMargin { - Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { - sent?.let { TitledText(it) } - received?.let { TitledText(it) } - error?.let { TitledErrorText(it) } - senderInfo?.let { - TitledView("From:") { - Row { - sender?.let { Avatar(it) } - TitledMonospaceText(it) - } + messageDetails.record?.let { message -> + AndroidView( + modifier = Modifier.padding(horizontal = 32.dp), + factory = { + ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(it)).mainContainerConstraint.apply { + bind( + message, + thread = threadDb?.getRecipientForThreadId(message.threadId)!!, + onAttachmentNeedsDownload = onAttachmentNeedsDownload, + suppressThumbnails = true + ) + + setOnTouchListener { _, event -> + if (event.actionMasked == ACTION_UP) onContentClick(event) + true + } + } + } + ) + } + Carousel(messageDetails.attachments) { onClickImage(it) } + MetadataCell(messageDetails) + Buttons( + onReply, + onResend, + onDelete, + ) + } +} + +@Composable +fun MetadataCell( + messageDetails: MessageDetails, +) { + messageDetails.apply { + if (sent != null || received != null || senderInfo != null) CellWithPaddingAndMargin { + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + sent?.let { TitledText(it) } + received?.let { TitledText(it) } + error?.let { TitledErrorText(it) } + senderInfo?.let { + TitledView(stringResource(id = R.string.message_details_header__from)) { + Row { + sender?.let { Avatar(it) } + TitledMonospaceText(it) } } } } } } +} - @Composable - fun Buttons( - hasError: Boolean, - onReply: () -> Unit = {}, - onResend: () -> Unit = {}, - onDelete: () -> Unit = {}, - ) { - Cell { - Column { +@Composable +fun Buttons( + onReply: () -> Unit = {}, + onResend: (() -> Unit)? = null, + onDelete: () -> Unit = {}, +) { + Cell { + Column { + ItemButton( + stringResource(id = R.string.reply), + R.drawable.ic_message_details__reply, + onClick = onReply + ) + Divider() + onResend?.let { ItemButton( - "Reply", - R.drawable.ic_message_details__reply, - onClick = onReply + stringResource(id = R.string.resend), + R.drawable.ic_message_details__refresh, + onClick = it ) Divider() - if (hasError) { - ItemButton( - "Resend", - R.drawable.ic_message_details__refresh, - onClick = onResend - ) - Divider() - } - ItemButton( - "Delete", - R.drawable.ic_message_details__trash, - colors = destructiveButtonColors(), - onClick = onDelete - ) } - } - } - - @Composable - fun Attachments(attachments: List, onClick: (Slide) -> Unit) { - when(attachments.firstOrNull()?.slide) { - is ImageSlide -> Carousel(attachments, onClick) - } - } - - @OptIn(ExperimentalFoundationApi::class) - @Composable - fun Carousel(attachments: List, onClick: (Slide) -> Unit) { - val imageAttachments = attachments.filter { it.slide.hasImage() } - val pagerState = rememberPagerState { imageAttachments.size } - - Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { - Row { - CarouselPrevButton(pagerState) - Box(modifier = Modifier.weight(1f)) { - CellPager(pagerState, imageAttachments, onClick) - HorizontalPagerIndicator(pagerState) - ExpandButton( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(8.dp) - ) { onClick(imageAttachments[pagerState.currentPage].slide) } - } - CarouselNextButton(pagerState) - } - FileDetails(attachments, pagerState) - } - } - - @OptIn( - ExperimentalFoundationApi::class, - ExperimentalGlideComposeApi::class - ) - @Composable - private fun CellPager( - pagerState: PagerState, - imageAttachments: List, - onClick: (Slide) -> Unit - ) { - CellNoMargin { - HorizontalPager(state = pagerState) { i -> - val slide = imageAttachments[i].slide - GlideImage( - contentScale = ContentScale.Crop, - modifier = Modifier - .aspectRatio(1f) - .clickable { onClick(slide) }, - model = slide.uri, - contentDescription = slide.fileName.orNull() ?: "image" - ) - } - } - } - - @Composable - fun ExpandButton(modifier: Modifier, onClick: () -> Unit) { - Surface( - shape = CircleShape, - color = blackAlpha40, - modifier = modifier - ) { - Icon( - painter = painterResource(id = R.drawable.ic_expand), - contentDescription = "", - modifier = Modifier.clickable { onClick() } + ItemButton( + stringResource(id = R.string.delete), + R.drawable.ic_message_details__trash, + colors = destructiveButtonColors(), + onClick = onDelete ) } } +} - @OptIn(ExperimentalFoundationApi::class, ExperimentalLayoutApi::class) - @Composable - fun FileDetails(attachments: List, pagerState: PagerState) { - attachments[pagerState.currentPage].fileDetails.takeIf { it.isNotEmpty() }?.let { - CellWithPaddingAndMargin { - FlowRow( - verticalArrangement = Arrangement.spacedBy(16.dp), - maxItemsInEachRow = 2 - ) { - it.forEach { TitledText(it, Modifier.weight(1f)) } - } +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun Carousel(attachments: List, onClick: (Slide) -> Unit) { + val imageAttachments = attachments.filter { it.hasImage() }.takeIf { it.isNotEmpty() } ?: return + val pagerState = rememberPagerState { imageAttachments.size } + + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + Row { + CarouselPrevButton(pagerState) + Box(modifier = Modifier.weight(1f)) { + CellCarousel(pagerState, imageAttachments, onClick) + HorizontalPagerIndicator(pagerState) + ExpandButton( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(8.dp) + ) { onClick(imageAttachments[pagerState.currentPage].slide) } + } + CarouselNextButton(pagerState) + } + FileDetails(attachments, pagerState) + } +} + +@OptIn( + ExperimentalFoundationApi::class, + ExperimentalGlideComposeApi::class +) +@Composable +private fun CellCarousel( + pagerState: PagerState, + imageAttachments: List, + onClick: (Slide) -> Unit +) { + CellNoMargin { + HorizontalPager(state = pagerState) { i -> + val slide = imageAttachments[i].slide + GlideImage( + contentScale = ContentScale.Crop, + modifier = Modifier + .aspectRatio(1f) + .clickable { onClick(slide) }, + model = slide.uri, + contentDescription = slide.fileName.orNull() ?: stringResource(id = R.string.image) + ) + } + } +} + +@Composable +fun ExpandButton(modifier: Modifier = Modifier, onClick: () -> Unit) { + Surface( + shape = CircleShape, + color = blackAlpha40, + modifier = modifier, + contentColor = Color.White, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_expand), + contentDescription = "", + modifier = Modifier.clickable { onClick() }, + ) + } +} + +@Preview +@Composable +fun PreviewFileDetails() { + Theme(R.style.Ocean_Dark) { + FileDetails( + fileDetails = listOf( + TitledText("File Id:", "Screen Shot 2023-07-06 at 11.35.50 am.png"), + TitledText("File Type:", "image/png"), + TitledText("File Size:", "195.6kB"), + TitledText("Resolution:", "342x312"), + ) + ) + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun FileDetails(attachments: List, pagerState: PagerState) { + FileDetails(attachments[pagerState.currentPage].fileDetails) +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun FileDetails(fileDetails: List) { + if (fileDetails.isEmpty()) return + + CellWithPaddingAndMargin { + FlowRow(verticalArrangement = Arrangement.spacedBy(16.dp)) { + fileDetails.forEach { + TitledText( + it, + modifier = Modifier + .widthIn(min = 100.dp) // set minimum width + .width(IntrinsicSize.Max) // make the text as wide as necessary + .weight(1f) // space evenly + ) } } } +} - @Composable - fun TitledErrorText(titledText: TitledText, modifier: Modifier = Modifier) { - TitledText( - titledText, - modifier = modifier, - valueStyle = LocalTextStyle.current.copy(color = colorDestructive) - ) - } +@Composable +fun TitledErrorText(titledText: TitledText, modifier: Modifier = Modifier) { + TitledText( + titledText, + modifier = modifier, + valueStyle = LocalTextStyle.current.copy(color = colorDestructive) + ) +} - @Composable - fun TitledMonospaceText(titledText: TitledText, modifier: Modifier = Modifier) { - TitledText( - titledText, - modifier = modifier, - valueStyle = LocalTextStyle.current.copy(fontFamily = FontFamily.Monospace) - ) - } +@Composable +fun TitledMonospaceText(titledText: TitledText, modifier: Modifier = Modifier) { + TitledText( + titledText, + modifier = modifier, + valueStyle = LocalTextStyle.current.copy(fontFamily = FontFamily.Monospace) + ) +} - @Composable - fun TitledText( - titledText: TitledText, - modifier: Modifier = Modifier, - valueStyle: TextStyle = LocalTextStyle.current - ) { - Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(4.dp)) { - Title(titledText.title) - Text(titledText.value, style = valueStyle) - } - } - - @Composable - fun TitledView(title: String, modifier: Modifier = Modifier, content: @Composable () -> Unit) { - Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(4.dp)) { - Title(title) - content() - } - } - - @Composable - fun Title(text: String) { - Text(text, fontWeight = FontWeight.Bold) +@Composable +fun TitledText( + titledText: TitledText, + modifier: Modifier = Modifier, + valueStyle: TextStyle = LocalTextStyle.current +) { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(4.dp)) { + Title(titledText.title) + Text(titledText.value, style = valueStyle) } } + +@Composable +fun TitledView(title: String, modifier: Modifier = Modifier, content: @Composable () -> Unit) { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(4.dp)) { + Title(title) + content() + } +} + +@Composable +fun Title(text: String, modifier: Modifier = Modifier) { + Text(text, modifier = modifier, fontWeight = FontWeight.Bold) +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt index cace0c6af..d63b46d8d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt @@ -1,27 +1,60 @@ package org.thoughtcrime.securesms.ui import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Colors +import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color val colorDestructive = Color(0xffFF453A) -val classicDark0 = Color(0xff111111) +const val classicDark0 = 0xff111111 +const val classicDark1 = 0xff1B1B1B +const val classicDark2 = 0xff2D2D2D +const val classicDark3 = 0xff414141 +const val classicDark4 = 0xff767676 +const val classicDark5 = 0xffA1A2A1 +const val classicDark6 = 0xffFFFFFF -val classicDark1 = Color(0xff1B1B1B) -val classicDark2 = Color(0xff2D2D2D) -val classicDark3 = Color(0xff414141) -val classicDark4 = Color(0xff767676) -val classicDark5 = Color(0xffA1A2A1) -val classicDark6 = Color(0xffFFFFFF) -val classicLight0 = Color(0xff000000) -val classicLight1 = Color(0xff6D6D6D) -val classicLight2 = Color(0xffA1A2A1) -val classicLight3 = Color(0xffDFDFDF) -val classicLight4 = Color(0xffF0F0F0) -val classicLight5 = Color(0xffF9F9F9) -val classicLight6 = Color(0xffFFFFFF) + +const val classicLight0 = 0xff000000 +const val classicLight1 = 0xff6D6D6D +const val classicLight2 = 0xffA1A2A1 +const val classicLight3 = 0xffDFDFDF +const val classicLight4 = 0xffF0F0F0 +const val classicLight5 = 0xffF9F9F9 +const val classicLight6 = 0xffFFFFFF + +const val oceanDark0 = 0xff000000 +const val oceanDark1 = 0xff1A1C28 +const val oceanDark2 = 0xff252735 +const val oceanDark3 = 0xff2B2D40 +const val oceanDark4 = 0xff3D4A5D +const val oceanDark5 = 0xffA6A9CE +const val oceanDark6 = 0xff5CAACC +const val oceanDark7 = 0xffFFFFFF + +const val oceanLight0 = 0xff000000 +const val oceanLight1 = 0xff19345D +const val oceanLight2 = 0xff6A6E90 +const val oceanLight3 = 0xff5CAACC +const val oceanLight4 = 0xffB3EDF2 +const val oceanLight5 = 0xffE7F3F4 +const val oceanLight6 = 0xffECFAFB +const val oceanLight7 = 0xffFCFFFF + +val ocean_accent = Color(0xff57C9FA) + +val oceanLights = arrayOf(oceanLight0, oceanLight1, oceanLight2, oceanLight3, oceanLight4, oceanLight5, oceanLight6, oceanLight7) +val oceanDarks = arrayOf(oceanDark0, oceanDark1, oceanDark2, oceanDark3, oceanDark4, oceanDark5, oceanDark6, oceanDark7) +val classicLights = arrayOf(classicLight0, classicLight1, classicLight2, classicLight3, classicLight4, classicLight5, classicLight6) +val classicDarks = arrayOf(classicDark0, classicDark1, classicDark2, classicDark3, classicDark4, classicDark5, classicDark6) + +val oceanLightColors = oceanLights.map(::Color) +val oceanDarkColors = oceanDarks.map(::Color) +val classicLightColors = classicLights.map(::Color) +val classicDarkColors = classicDarks.map(::Color) val blackAlpha40 = Color.Black.copy(alpha = 0.4f) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt index b7684a22f..8589f3e7e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt @@ -1,32 +1,50 @@ package org.thoughtcrime.securesms.ui import androidx.annotation.DrawableRes +import androidx.appcompat.view.ContextThemeWrapper import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.FlowRowScope +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridScope +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ButtonColors import androidx.compose.material.Card +import androidx.compose.material.Colors 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.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -36,6 +54,13 @@ import kotlinx.coroutines.launch import network.loki.messenger.R import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.components.ProfilePictureView +import kotlin.math.roundToInt + +private val Colors.cellColors: Colors + @Composable + get() = MaterialTheme.colors.copy( + surface = LocalExtraColors.current.settingsBackground, + ) @Composable fun ItemButton( @@ -80,17 +105,18 @@ fun CellWithPaddingAndMargin( margin: Dp = 32.dp, content: @Composable () -> Unit ) { - Card( - shape = RoundedCornerShape(16.dp), - elevation = 0.dp, - modifier = Modifier - .wrapContentHeight() - .fillMaxWidth() - .padding(horizontal = margin), - backgroundColor = LocalExtraColors.current.settingsBackground, - // probably wrong - contentColor = MaterialTheme.colors.onSurface - ) { Box(Modifier.padding(padding)) { content() } } + MaterialTheme(colors = MaterialTheme.colors.cellColors) { + Card( + shape = RoundedCornerShape(16.dp), + elevation = 0.dp, + modifier = Modifier + .wrapContentHeight() + .fillMaxWidth() + .padding(horizontal = margin), + ) { + Box(Modifier.padding(padding)) { content() } + } + } } @OptIn(ExperimentalFoundationApi::class) @@ -108,7 +134,7 @@ fun BoxScope.HorizontalPagerIndicator(pagerState: PagerState) { pagerState = pagerState, pageCount = pagerState.pageCount, activeColor = Color.White, - inactiveColor = classicDark5) + inactiveColor = classicDarkColors[5]) } } } @@ -154,7 +180,6 @@ fun RowScope.CarouselButton( fun Divider() { androidx.compose.material.Divider( modifier = Modifier.padding(horizontal = 16.dp), - color = LocalExtraColors.current.divider ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt index 88916e03e..59402b681 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt @@ -2,25 +2,36 @@ package org.thoughtcrime.securesms.ui import android.content.Context import androidx.annotation.AttrRes +import androidx.annotation.StyleRes +import androidx.appcompat.view.ContextThemeWrapper +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.google.accompanist.themeadapter.appcompat.AppCompatTheme import com.google.android.material.color.MaterialColors import network.loki.messenger.R +import org.thoughtcrime.securesms.conversation.v2.PreviewMessageDetails val LocalExtraColors = staticCompositionLocalOf { error("No Custom Attribute value provided") } data class ExtraColors( - val cell: Color, - val divider: Color, val settingsBackground: Color, ) -fun Context.getColorFromTheme(@AttrRes attr: Int, defaultValue: Int = 0x0): Color = +fun Context.getColorFromTheme(@AttrRes attr: Int, defaultValue: Int = 0x0): Color = try { MaterialColors.getColor(this, attr, defaultValue).let(::Color) +} catch (e: Exception) { + colorDestructive +} @Composable fun AppTheme( @@ -28,9 +39,7 @@ fun AppTheme( ) { val extraColors = LocalContext.current.run { ExtraColors( - cell = getColorFromTheme(R.attr.colorCellBackground), - divider = getColorFromTheme(R.attr.dividerHorizontal).copy(alpha = 0.15f), - settingsBackground = getColorFromTheme(R.attr.colorSettingsBackground) + settingsBackground = getColorFromTheme(R.attr.colorSettingsBackground), ) } @@ -40,3 +49,35 @@ fun AppTheme( } } } + +@Preview +@Composable +fun PreviewMessageDetails( + @PreviewParameter(ThemeResPreviewParameterProvider::class) themeResId: Int +) { + Theme(themeResId) { + Box(modifier = Modifier.background(color = MaterialTheme.colors.background)) { + PreviewMessageDetails() + } + } +} + +@Composable +fun Theme(@StyleRes themeResId: Int, content: @Composable () -> Unit) { + CompositionLocalProvider( + LocalContext provides ContextThemeWrapper(LocalContext.current, themeResId) + ) { + AppTheme { + content() + } + } +} + +class ThemeResPreviewParameterProvider : PreviewParameterProvider { + override val values = sequenceOf( + R.style.Classic_Dark, + R.style.Classic_Light, + R.style.Ocean_Dark, + R.style.Ocean_Light, + ) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d7948c4f2..1c718932f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,9 +4,12 @@ Yes No Delete + Resend + Reply Ban Please wait… Save + Image Note to Self Version %s @@ -516,6 +519,7 @@ To: From: With: + Create passphrase Select contacts diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index bc8563850..ad03b3e38 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -490,7 +490,6 @@ ?android:textColorPrimary @color/ocean_dark_5 ?colorPrimary - @color/default_background_start @color/navigation_bar ?colorPrimary ?colorPrimaryDark @@ -575,7 +574,6 @@ @color/ocean_light_6 @color/ocean_light_navigation_bar ?colorPrimary - @color/default_background_start @color/ocean_light_7 @color/ocean_light_6 @color/ocean_light_5