mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-28 15:10:46 +00:00
Fix theming and polish
This commit is contained in:
parent
bbc9cdfeeb
commit
0824713ac5
@ -13,9 +13,12 @@ import androidx.compose.foundation.layout.Box
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.padding
|
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.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.PagerState
|
import androidx.compose.foundation.pager.PagerState
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
@ -31,9 +34,11 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
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.MediaPreviewActivity
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.database.Storage
|
import org.thoughtcrime.securesms.database.Storage
|
||||||
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||||
import org.thoughtcrime.securesms.mms.ImageSlide
|
|
||||||
import org.thoughtcrime.securesms.mms.Slide
|
import org.thoughtcrime.securesms.mms.Slide
|
||||||
import org.thoughtcrime.securesms.ui.AppTheme
|
import org.thoughtcrime.securesms.ui.AppTheme
|
||||||
import org.thoughtcrime.securesms.ui.Avatar
|
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.Divider
|
||||||
import org.thoughtcrime.securesms.ui.HorizontalPagerIndicator
|
import org.thoughtcrime.securesms.ui.HorizontalPagerIndicator
|
||||||
import org.thoughtcrime.securesms.ui.ItemButton
|
import org.thoughtcrime.securesms.ui.ItemButton
|
||||||
|
import org.thoughtcrime.securesms.ui.Theme
|
||||||
import org.thoughtcrime.securesms.ui.blackAlpha40
|
import org.thoughtcrime.securesms.ui.blackAlpha40
|
||||||
import org.thoughtcrime.securesms.ui.colorDestructive
|
import org.thoughtcrime.securesms.ui.colorDestructive
|
||||||
import org.thoughtcrime.securesms.ui.destructiveButtonColors
|
import org.thoughtcrime.securesms.ui.destructiveButtonColors
|
||||||
@ -118,8 +124,11 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun MessageDetailsScreen() {
|
private fun MessageDetailsScreen() {
|
||||||
val details by viewModel.details.observeAsState(MessageDetails())
|
val details by viewModel.details.observeAsState(MessageDetails())
|
||||||
|
val threadDb = DatabaseComponent.get(this@MessageDetailActivity).threadDatabase()
|
||||||
|
AppTheme {
|
||||||
MessageDetails(
|
MessageDetails(
|
||||||
details,
|
threadDb = threadDb,
|
||||||
|
messageDetails = details,
|
||||||
onReply = { setResultAndFinish(ON_REPLY) },
|
onReply = { setResultAndFinish(ON_REPLY) },
|
||||||
onResend = { setResultAndFinish(ON_RESEND) },
|
onResend = { setResultAndFinish(ON_RESEND) },
|
||||||
onDelete = { setResultAndFinish(ON_DELETE) },
|
onDelete = { setResultAndFinish(ON_DELETE) },
|
||||||
@ -135,11 +144,13 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
this,
|
this,
|
||||||
slide,
|
slide,
|
||||||
details.mmsRecord,
|
details.mmsRecord,
|
||||||
DatabaseComponent.get(this).threadDatabase().getRecipientForThreadId(details.mmsRecord!!.threadId),
|
threadDb.getRecipientForThreadId(details.mmsRecord!!.threadId),
|
||||||
).let(::startActivity)
|
).let(::startActivity)
|
||||||
}
|
},
|
||||||
|
onAttachmentNeedsDownload = ::onAttachmentNeedsDownload,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setResultAndFinish(code: Int) {
|
private fun setResultAndFinish(code: Int) {
|
||||||
Bundle().apply { putLong(MESSAGE_TIMESTAMP, timestamp) }
|
Bundle().apply { putLong(MESSAGE_TIMESTAMP, timestamp) }
|
||||||
@ -149,38 +160,44 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
finish()
|
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) {
|
private fun onAttachmentNeedsDownload(attachmentId: Long, mmsId: Long) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
|
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@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"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@Composable
|
@Composable
|
||||||
fun MessageDetails(
|
fun MessageDetails(
|
||||||
|
threadDb: ThreadDatabase? = null,
|
||||||
messageDetails: MessageDetails,
|
messageDetails: MessageDetails,
|
||||||
onReply: () -> Unit = {},
|
onReply: () -> Unit = {},
|
||||||
onResend: () -> Unit = {},
|
onResend: (() -> Unit)? = null,
|
||||||
onDelete: () -> Unit = {},
|
onDelete: () -> Unit = {},
|
||||||
onClickImage: (Slide) -> Unit = {},
|
onClickImage: (Slide) -> Unit = {},
|
||||||
|
onAttachmentNeedsDownload: (Long, Long) -> Unit = { _, _ -> }
|
||||||
) {
|
) {
|
||||||
AppTheme {
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(vertical = 16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
messageDetails.record?.let { message ->
|
messageDetails.record?.let { message ->
|
||||||
@ -190,8 +207,8 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(it)).mainContainerConstraint.apply {
|
ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(it)).mainContainerConstraint.apply {
|
||||||
bind(
|
bind(
|
||||||
message,
|
message,
|
||||||
thread = DatabaseComponent.get(this@MessageDetailActivity).threadDatabase().getRecipientForThreadId(message.threadId)!!,
|
thread = threadDb?.getRecipientForThreadId(message.threadId)!!,
|
||||||
onAttachmentNeedsDownload = ::onAttachmentNeedsDownload,
|
onAttachmentNeedsDownload = onAttachmentNeedsDownload,
|
||||||
suppressThumbnails = true
|
suppressThumbnails = true
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -203,17 +220,15 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Attachments(messageDetails.attachments) { onClickImage(it) }
|
Carousel(messageDetails.attachments) { onClickImage(it) }
|
||||||
MetadataCell(messageDetails)
|
MetadataCell(messageDetails)
|
||||||
Buttons(
|
Buttons(
|
||||||
messageDetails.error != null,
|
|
||||||
onReply,
|
onReply,
|
||||||
onResend,
|
onResend,
|
||||||
onDelete,
|
onDelete,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MetadataCell(
|
fun MetadataCell(
|
||||||
@ -226,7 +241,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
received?.let { TitledText(it) }
|
received?.let { TitledText(it) }
|
||||||
error?.let { TitledErrorText(it) }
|
error?.let { TitledErrorText(it) }
|
||||||
senderInfo?.let {
|
senderInfo?.let {
|
||||||
TitledView("From:") {
|
TitledView(stringResource(id = R.string.message_details_header__from)) {
|
||||||
Row {
|
Row {
|
||||||
sender?.let { Avatar(it) }
|
sender?.let { Avatar(it) }
|
||||||
TitledMonospaceText(it)
|
TitledMonospaceText(it)
|
||||||
@ -240,29 +255,28 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Buttons(
|
fun Buttons(
|
||||||
hasError: Boolean,
|
|
||||||
onReply: () -> Unit = {},
|
onReply: () -> Unit = {},
|
||||||
onResend: () -> Unit = {},
|
onResend: (() -> Unit)? = null,
|
||||||
onDelete: () -> Unit = {},
|
onDelete: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Cell {
|
Cell {
|
||||||
Column {
|
Column {
|
||||||
ItemButton(
|
ItemButton(
|
||||||
"Reply",
|
stringResource(id = R.string.reply),
|
||||||
R.drawable.ic_message_details__reply,
|
R.drawable.ic_message_details__reply,
|
||||||
onClick = onReply
|
onClick = onReply
|
||||||
)
|
)
|
||||||
Divider()
|
Divider()
|
||||||
if (hasError) {
|
onResend?.let {
|
||||||
ItemButton(
|
ItemButton(
|
||||||
"Resend",
|
stringResource(id = R.string.resend),
|
||||||
R.drawable.ic_message_details__refresh,
|
R.drawable.ic_message_details__refresh,
|
||||||
onClick = onResend
|
onClick = it
|
||||||
)
|
)
|
||||||
Divider()
|
Divider()
|
||||||
}
|
}
|
||||||
ItemButton(
|
ItemButton(
|
||||||
"Delete",
|
stringResource(id = R.string.delete),
|
||||||
R.drawable.ic_message_details__trash,
|
R.drawable.ic_message_details__trash,
|
||||||
colors = destructiveButtonColors(),
|
colors = destructiveButtonColors(),
|
||||||
onClick = onDelete
|
onClick = onDelete
|
||||||
@ -271,24 +285,17 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Attachments(attachments: List<Attachment>, onClick: (Slide) -> Unit) {
|
|
||||||
when(attachments.firstOrNull()?.slide) {
|
|
||||||
is ImageSlide -> Carousel(attachments, onClick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Carousel(attachments: List<Attachment>, onClick: (Slide) -> Unit) {
|
fun Carousel(attachments: List<Attachment>, onClick: (Slide) -> Unit) {
|
||||||
val imageAttachments = attachments.filter { it.slide.hasImage() }
|
val imageAttachments = attachments.filter { it.hasImage() }.takeIf { it.isNotEmpty() } ?: return
|
||||||
val pagerState = rememberPagerState { imageAttachments.size }
|
val pagerState = rememberPagerState { imageAttachments.size }
|
||||||
|
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
Row {
|
Row {
|
||||||
CarouselPrevButton(pagerState)
|
CarouselPrevButton(pagerState)
|
||||||
Box(modifier = Modifier.weight(1f)) {
|
Box(modifier = Modifier.weight(1f)) {
|
||||||
CellPager(pagerState, imageAttachments, onClick)
|
CellCarousel(pagerState, imageAttachments, onClick)
|
||||||
HorizontalPagerIndicator(pagerState)
|
HorizontalPagerIndicator(pagerState)
|
||||||
ExpandButton(
|
ExpandButton(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -307,7 +314,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
ExperimentalGlideComposeApi::class
|
ExperimentalGlideComposeApi::class
|
||||||
)
|
)
|
||||||
@Composable
|
@Composable
|
||||||
private fun CellPager(
|
private fun CellCarousel(
|
||||||
pagerState: PagerState,
|
pagerState: PagerState,
|
||||||
imageAttachments: List<Attachment>,
|
imageAttachments: List<Attachment>,
|
||||||
onClick: (Slide) -> Unit
|
onClick: (Slide) -> Unit
|
||||||
@ -321,37 +328,64 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.clickable { onClick(slide) },
|
.clickable { onClick(slide) },
|
||||||
model = slide.uri,
|
model = slide.uri,
|
||||||
contentDescription = slide.fileName.orNull() ?: "image"
|
contentDescription = slide.fileName.orNull() ?: stringResource(id = R.string.image)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ExpandButton(modifier: Modifier, onClick: () -> Unit) {
|
fun ExpandButton(modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||||
Surface(
|
Surface(
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
color = blackAlpha40,
|
color = blackAlpha40,
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
|
contentColor = Color.White,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_expand),
|
painter = painterResource(id = R.drawable.ic_expand),
|
||||||
contentDescription = "",
|
contentDescription = "",
|
||||||
modifier = Modifier.clickable { onClick() }
|
modifier = Modifier.clickable { onClick() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalLayoutApi::class)
|
@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
|
@Composable
|
||||||
fun FileDetails(attachments: List<Attachment>, pagerState: PagerState) {
|
fun FileDetails(attachments: List<Attachment>, pagerState: PagerState) {
|
||||||
attachments[pagerState.currentPage].fileDetails.takeIf { it.isNotEmpty() }?.let {
|
FileDetails(attachments[pagerState.currentPage].fileDetails)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun FileDetails(fileDetails: List<TitledText>) {
|
||||||
|
if (fileDetails.isEmpty()) return
|
||||||
|
|
||||||
CellWithPaddingAndMargin {
|
CellWithPaddingAndMargin {
|
||||||
FlowRow(
|
FlowRow(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
fileDetails.forEach {
|
||||||
maxItemsInEachRow = 2
|
TitledText(
|
||||||
) {
|
it,
|
||||||
it.forEach { TitledText(it, Modifier.weight(1f)) }
|
modifier = Modifier
|
||||||
|
.widthIn(min = 100.dp) // set minimum width
|
||||||
|
.width(IntrinsicSize.Max) // make the text as wide as necessary
|
||||||
|
.weight(1f) // space evenly
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,7 +430,6 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Title(text: String) {
|
fun Title(text: String, modifier: Modifier = Modifier) {
|
||||||
Text(text, fontWeight = FontWeight.Bold)
|
Text(text, modifier = modifier, fontWeight = FontWeight.Bold)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,60 @@
|
|||||||
package org.thoughtcrime.securesms.ui
|
package org.thoughtcrime.securesms.ui
|
||||||
|
|
||||||
import androidx.compose.material.ButtonDefaults
|
import androidx.compose.material.ButtonDefaults
|
||||||
|
import androidx.compose.material.Colors
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
val colorDestructive = Color(0xffFF453A)
|
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)
|
const val classicLight0 = 0xff000000
|
||||||
val classicLight2 = Color(0xffA1A2A1)
|
const val classicLight1 = 0xff6D6D6D
|
||||||
val classicLight3 = Color(0xffDFDFDF)
|
const val classicLight2 = 0xffA1A2A1
|
||||||
val classicLight4 = Color(0xffF0F0F0)
|
const val classicLight3 = 0xffDFDFDF
|
||||||
val classicLight5 = Color(0xffF9F9F9)
|
const val classicLight4 = 0xffF0F0F0
|
||||||
val classicLight6 = Color(0xffFFFFFF)
|
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)
|
val blackAlpha40 = Color.Black.copy(alpha = 0.4f)
|
||||||
|
|
||||||
|
@ -1,32 +1,50 @@
|
|||||||
package org.thoughtcrime.securesms.ui
|
package org.thoughtcrime.securesms.ui
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
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.Box
|
||||||
import androidx.compose.foundation.layout.BoxScope
|
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.RowScope
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
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.pager.PagerState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.ButtonColors
|
import androidx.compose.material.ButtonColors
|
||||||
import androidx.compose.material.Card
|
import androidx.compose.material.Card
|
||||||
|
import androidx.compose.material.Colors
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.IconButton
|
import androidx.compose.material.IconButton
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.TextButton
|
import androidx.compose.material.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
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.res.painterResource
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
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 network.loki.messenger.R
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.components.ProfilePictureView
|
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
|
@Composable
|
||||||
fun ItemButton(
|
fun ItemButton(
|
||||||
@ -80,6 +105,7 @@ fun CellWithPaddingAndMargin(
|
|||||||
margin: Dp = 32.dp,
|
margin: Dp = 32.dp,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
|
MaterialTheme(colors = MaterialTheme.colors.cellColors) {
|
||||||
Card(
|
Card(
|
||||||
shape = RoundedCornerShape(16.dp),
|
shape = RoundedCornerShape(16.dp),
|
||||||
elevation = 0.dp,
|
elevation = 0.dp,
|
||||||
@ -87,10 +113,10 @@ fun CellWithPaddingAndMargin(
|
|||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = margin),
|
.padding(horizontal = margin),
|
||||||
backgroundColor = LocalExtraColors.current.settingsBackground,
|
) {
|
||||||
// probably wrong
|
Box(Modifier.padding(padding)) { content() }
|
||||||
contentColor = MaterialTheme.colors.onSurface
|
}
|
||||||
) { Box(Modifier.padding(padding)) { content() } }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@ -108,7 +134,7 @@ fun BoxScope.HorizontalPagerIndicator(pagerState: PagerState) {
|
|||||||
pagerState = pagerState,
|
pagerState = pagerState,
|
||||||
pageCount = pagerState.pageCount,
|
pageCount = pagerState.pageCount,
|
||||||
activeColor = Color.White,
|
activeColor = Color.White,
|
||||||
inactiveColor = classicDark5)
|
inactiveColor = classicDarkColors[5])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,7 +180,6 @@ fun RowScope.CarouselButton(
|
|||||||
fun Divider() {
|
fun Divider() {
|
||||||
androidx.compose.material.Divider(
|
androidx.compose.material.Divider(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
color = LocalExtraColors.current.divider
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,25 +2,36 @@ package org.thoughtcrime.securesms.ui
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.AttrRes
|
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.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
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.accompanist.themeadapter.appcompat.AppCompatTheme
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.PreviewMessageDetails
|
||||||
|
|
||||||
val LocalExtraColors = staticCompositionLocalOf<ExtraColors> { error("No Custom Attribute value provided") }
|
val LocalExtraColors = staticCompositionLocalOf<ExtraColors> { error("No Custom Attribute value provided") }
|
||||||
|
|
||||||
data class ExtraColors(
|
data class ExtraColors(
|
||||||
val cell: Color,
|
|
||||||
val divider: Color,
|
|
||||||
val settingsBackground: 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)
|
MaterialColors.getColor(this, attr, defaultValue).let(::Color)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
colorDestructive
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppTheme(
|
fun AppTheme(
|
||||||
@ -28,9 +39,7 @@ fun AppTheme(
|
|||||||
) {
|
) {
|
||||||
val extraColors = LocalContext.current.run {
|
val extraColors = LocalContext.current.run {
|
||||||
ExtraColors(
|
ExtraColors(
|
||||||
cell = getColorFromTheme(R.attr.colorCellBackground),
|
settingsBackground = getColorFromTheme(R.attr.colorSettingsBackground),
|
||||||
divider = getColorFromTheme(R.attr.dividerHorizontal).copy(alpha = 0.15f),
|
|
||||||
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<Int> {
|
||||||
|
override val values = sequenceOf(
|
||||||
|
R.style.Classic_Dark,
|
||||||
|
R.style.Classic_Light,
|
||||||
|
R.style.Ocean_Dark,
|
||||||
|
R.style.Ocean_Light,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -4,9 +4,12 @@
|
|||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="delete">Delete</string>
|
<string name="delete">Delete</string>
|
||||||
|
<string name="resend">Resend</string>
|
||||||
|
<string name="reply">Reply</string>
|
||||||
<string name="ban">Ban</string>
|
<string name="ban">Ban</string>
|
||||||
<string name="please_wait">Please wait…</string>
|
<string name="please_wait">Please wait…</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
|
<string name="image">Image</string>
|
||||||
<string name="note_to_self">Note to Self</string>
|
<string name="note_to_self">Note to Self</string>
|
||||||
<string name="version_s">Version %s</string>
|
<string name="version_s">Version %s</string>
|
||||||
<!--Accessibility ID's-->
|
<!--Accessibility ID's-->
|
||||||
@ -516,6 +519,7 @@
|
|||||||
<string name="message_details_header__to">To:</string>
|
<string name="message_details_header__to">To:</string>
|
||||||
<string name="message_details_header__from">From:</string>
|
<string name="message_details_header__from">From:</string>
|
||||||
<string name="message_details_header__with">With:</string>
|
<string name="message_details_header__with">With:</string>
|
||||||
|
|
||||||
<!-- AndroidManifest.xml -->
|
<!-- AndroidManifest.xml -->
|
||||||
<string name="AndroidManifest__create_passphrase">Create passphrase</string>
|
<string name="AndroidManifest__create_passphrase">Create passphrase</string>
|
||||||
<string name="AndroidManifest__select_contacts">Select contacts</string>
|
<string name="AndroidManifest__select_contacts">Select contacts</string>
|
||||||
|
@ -490,7 +490,6 @@
|
|||||||
<item name="android:textColor">?android:textColorPrimary</item>
|
<item name="android:textColor">?android:textColorPrimary</item>
|
||||||
<item name="android:textColorHint">@color/ocean_dark_5</item>
|
<item name="android:textColorHint">@color/ocean_dark_5</item>
|
||||||
<item name="android:windowBackground">?colorPrimary</item>
|
<item name="android:windowBackground">?colorPrimary</item>
|
||||||
<item name="android:colorBackground">@color/default_background_start</item>
|
|
||||||
<item name="android:navigationBarColor">@color/navigation_bar</item>
|
<item name="android:navigationBarColor">@color/navigation_bar</item>
|
||||||
<item name="default_background_end">?colorPrimary</item>
|
<item name="default_background_end">?colorPrimary</item>
|
||||||
<item name="default_background_start">?colorPrimaryDark</item>
|
<item name="default_background_start">?colorPrimaryDark</item>
|
||||||
@ -575,7 +574,6 @@
|
|||||||
<item name="android:textColorHint">@color/ocean_light_6</item>
|
<item name="android:textColorHint">@color/ocean_light_6</item>
|
||||||
<item name="android:navigationBarColor">@color/ocean_light_navigation_bar</item>
|
<item name="android:navigationBarColor">@color/ocean_light_navigation_bar</item>
|
||||||
<item name="android:windowBackground">?colorPrimary</item>
|
<item name="android:windowBackground">?colorPrimary</item>
|
||||||
<item name="android:colorBackground">@color/default_background_start</item>
|
|
||||||
<item name="default_background_end">@color/ocean_light_7</item>
|
<item name="default_background_end">@color/ocean_light_7</item>
|
||||||
<item name="default_background_start">@color/ocean_light_6</item>
|
<item name="default_background_start">@color/ocean_light_6</item>
|
||||||
<item name="colorCellBackground">@color/ocean_light_5</item>
|
<item name="colorCellBackground">@color/ocean_light_5</item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user