Skip to content
Snippets Groups Projects
Verified Commit 1f9308d1 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

feat: implement basic theming and message rendering

parent 47583974
Branches
Tags
No related merge requests found
Showing
with 674 additions and 245 deletions
......@@ -68,6 +68,7 @@ dependencies {
implementation(libs.androidx.compose.compiler)
implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.compose.material)
implementation(libs.androidx.compose.material.icons)
implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.compose.ui)
......
......@@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface
import androidx.compose.ui.Modifier
import de.justjanne.quasseldroid.service.QuasselBackend
import de.justjanne.quasseldroid.ui.theme.QuasseldroidTheme
import de.justjanne.quasseldroid.ui.theme.QuasselTheme
class MainActivity : ComponentActivity() {
private val backend = QuasselBackend()
......@@ -16,7 +16,7 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
backend.onCreate(this)
setContent {
QuasseldroidTheme {
QuasselTheme {
Surface(modifier = Modifier.fillMaxSize()) {
QuasseldroidRouter(backend = backend)
}
......
package de.justjanne.quasseldroid.model
enum class SecurityLevel {
SECURE,
UNVERIFIED,
INSECURE
}
package de.justjanne.quasseldroid.sample
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import de.justjanne.quasseldroid.model.SecurityLevel
class SampleSecurityLevelProvider: PreviewParameterProvider<SecurityLevel> {
override val values = sequenceOf(
SecurityLevel.SECURE,
SecurityLevel.UNVERIFIED,
SecurityLevel.INSECURE,
)
}
......@@ -6,20 +6,20 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import de.charlex.compose.HtmlText
import de.justjanne.libquassel.protocol.models.ConnectedClient
import de.justjanne.quasseldroid.R
import de.justjanne.quasseldroid.model.SecurityLevel
import de.justjanne.quasseldroid.sample.SampleConnectedClientProvider
import de.justjanne.quasseldroid.ui.theme.Insecure
import de.justjanne.quasseldroid.ui.theme.Secure
import de.justjanne.quasseldroid.ui.theme.Typography
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter
......@@ -34,23 +34,19 @@ fun ConnectedClientCard(
client: ConnectedClient,
modifier: Modifier = Modifier
) {
val secureResource = painterResource(
if (client.secure) R.drawable.ic_lock
else R.drawable.ic_no_encryption
)
val tint = if (client.secure) Secure else Insecure
Card(modifier = modifier) {
Row(modifier = Modifier.padding(16.dp)) {
Column(modifier = Modifier.weight(1.0f)) {
HtmlText(
text = client.version,
style = Typography.body1
style = Typography.body1,
overflow = TextOverflow.Ellipsis
)
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
client.remoteAddress,
style = Typography.body2
style = Typography.body2,
overflow = TextOverflow.Ellipsis
)
Text(
client.connectedSince
......@@ -59,8 +55,9 @@ fun ConnectedClientCard(
style = Typography.body2
)
}
}
Spacer(modifier = Modifier.width(16.dp))
Icon(secureResource, tint = tint, contentDescription = "")
SecurityIcon(level = if (client.secure) SecurityLevel.SECURE else SecurityLevel.INSECURE)
}
}
}
package de.justjanne.quasseldroid.ui.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.justjanne.libquassel.protocol.models.Message
import de.justjanne.libquassel.protocol.util.irc.HostmaskHelper
import de.justjanne.quasseldroid.ui.icons.AvatarIcon
import de.justjanne.quasseldroid.ui.routes.SampleMessageProvider
import de.justjanne.quasseldroid.ui.theme.QuasselTheme
import de.justjanne.quasseldroid.ui.theme.Typography
import irc.SenderColorUtil
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.format.FormatStyle
private val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
@Preview(name = "Message", showBackground = true)
@Composable
fun MessageView(
@PreviewParameter(SampleMessageProvider::class)
message: Message
) {
MessageBaseView(message, false, 32.dp) {
Text(
message.content,
style = Typography.body2,
)
}
}
@Composable
fun MessageBaseView(
message: Message,
followUp: Boolean,
avatarSize: Dp,
content: @Composable () -> Unit
) {
val nick = HostmaskHelper.nick(message.sender)
val senderColor = QuasselTheme.sender.colors[SenderColorUtil.senderColor(nick)]
Row {
if (!followUp) {
AvatarIcon(nick, null, modifier = Modifier.padding(2.dp))
Spacer(Modifier.width(4.dp))
} else {
Spacer(Modifier.width(avatarSize + 8.dp))
}
Column {
if (!followUp) {
Row {
Text(
message.senderPrefixes,
style = Typography.body2,
fontWeight = FontWeight.Bold,
)
Text(
nick,
style = Typography.body2,
fontWeight = FontWeight.Bold,
color = senderColor,
)
Spacer(Modifier.width(4.dp))
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
message.realName,
modifier = Modifier.weight(1.0f),
style = Typography.body2,
overflow = TextOverflow.Ellipsis,
)
}
}
}
Row {
Box(modifier = Modifier.weight(1.0f)) {
content()
}
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
message.time
.atZone(ZoneId.systemDefault())
.format(formatter),
style = Typography.body2,
fontSize = 12.sp,
modifier = Modifier.align(Alignment.Bottom)
)
}
}
}
}
}
......@@ -10,6 +10,9 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.TextFieldColors
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
......@@ -21,8 +24,16 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import de.justjanne.quasseldroid.R
@Preview(name = "PasswordTextField", showBackground = true)
@Composable
private fun PasswordTextFieldPreview() {
val (password, setPassword) = remember { mutableStateOf(TextFieldValue("password")) }
PasswordTextField(password, setPassword)
}
@Composable
fun PasswordTextField(
value: TextFieldValue,
......@@ -47,10 +58,9 @@ fun PasswordTextField(
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
val (showPassword, setShowPassword) = remember { mutableStateOf(false) }
val painter = painterResource(
if (showPassword) R.drawable.ic_eye_off
else R.drawable.ic_eye
)
val icon =
if (showPassword) Icons.Filled.VisibilityOff
else Icons.Filled.Visibility
OutlinedTextField(
value,
......@@ -64,7 +74,7 @@ fun PasswordTextField(
leadingIcon,
{
IconButton(onClick = { setShowPassword(!showPassword) }) {
Icon(painter = painter, contentDescription = "")
Icon(imageVector = icon, contentDescription = "")
}
trailingIcon?.invoke()
},
......@@ -105,10 +115,9 @@ fun PasswordTextField(
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
val (showPassword, setShowPassword) = remember { mutableStateOf(false) }
val painter = painterResource(
if (showPassword) R.drawable.ic_eye_off
else R.drawable.ic_eye
)
val icon =
if (showPassword) Icons.Filled.VisibilityOff
else Icons.Filled.Visibility
OutlinedTextField(
value,
......@@ -122,7 +131,7 @@ fun PasswordTextField(
leadingIcon,
{
IconButton(onClick = { setShowPassword(!showPassword) }) {
Icon(painter = painter, contentDescription = "")
Icon(imageVector = icon, contentDescription = "")
}
trailingIcon?.invoke()
},
......
package de.justjanne.quasseldroid.ui.icons
import android.graphics.Bitmap
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ContentAlpha
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import de.justjanne.quasseldroid.ui.theme.QuasselTheme
import irc.SenderColorUtil
import java.util.*
@Preview
@Composable
private fun AvatarIconPreview() {
AvatarIcon("justJanne", null)
}
@Composable
fun AvatarIcon(
nick: String,
avatar: Bitmap?,
modifier: Modifier = Modifier,
size: Dp = 32.dp
) {
val senderColor = QuasselTheme.sender.colors[SenderColorUtil.senderColor(nick)]
val initial = nick.asSequence().map { it.uppercase(Locale.ENGLISH) }.first()
val fontSize = with(LocalDensity.current) { (size.toPx() * 0.67f).toSp() }
Surface(
shape = RoundedCornerShape(2.dp),
color = senderColor,
modifier = modifier.size(size)
) {
Box {
Text(
text = initial,
color = MaterialTheme.colors.background.copy(alpha = ContentAlpha.medium),
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.align(Alignment.Center),
fontSize = fontSize,
)
}
}
}
package de.justjanne.quasseldroid.ui.components
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.LockOpen
import androidx.compose.material.icons.filled.NoEncryption
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import de.justjanne.quasseldroid.model.SecurityLevel
import de.justjanne.quasseldroid.sample.SampleSecurityLevelProvider
import de.justjanne.quasseldroid.ui.theme.QuasselTheme
@Preview(name = "Security Icon", showBackground = true)
@Composable
fun SecurityIcon(
@PreviewParameter(SampleSecurityLevelProvider::class)
level: SecurityLevel
) {
val vector = when (level) {
SecurityLevel.SECURE -> Icons.Filled.Lock
SecurityLevel.UNVERIFIED -> Icons.Filled.LockOpen
SecurityLevel.INSECURE -> Icons.Filled.NoEncryption
}
val color = when (level) {
SecurityLevel.SECURE -> QuasselTheme.security.secure
SecurityLevel.UNVERIFIED -> QuasselTheme.security.unverified
SecurityLevel.INSECURE -> QuasselTheme.security.insecure
}
Icon(imageVector = vector, contentDescription = level.name, tint = color)
}
package de.justjanne.quasseldroid.ui.routes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Button
......@@ -11,39 +8,17 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import de.justjanne.bitflags.of
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.Message
import de.justjanne.libquassel.protocol.models.flags.BufferType
import de.justjanne.libquassel.protocol.models.flags.MessageFlag
import de.justjanne.libquassel.protocol.models.flags.MessageType
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.MsgId
import de.justjanne.libquassel.protocol.models.ids.NetworkId
import de.justjanne.libquassel.protocol.util.flatMap
import de.justjanne.libquassel.protocol.util.irc.HostmaskHelper
import de.justjanne.quasseldroid.service.QuasselBackend
import de.justjanne.quasseldroid.ui.theme.SenderColors
import de.justjanne.quasseldroid.ui.theme.Typography
import irc.SenderColorUtil
import de.justjanne.quasseldroid.ui.components.MessageView
import de.justjanne.quasseldroid.util.mapNullable
import de.justjanne.quasseldroid.util.rememberFlow
import de.justjanne.quasseldroid.util.saver.BufferIdSaver
import kotlinx.coroutines.flow.map
import org.threeten.bp.Instant
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.format.FormatStyle
@Composable
fun HomeRoute(backend: QuasselBackend, navController: NavController) {
......@@ -96,125 +71,3 @@ fun HomeRoute(backend: QuasselBackend, navController: NavController) {
}
private val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
@Preview(name = "Message", showBackground = true)
@Composable
fun MessageView(
@PreviewParameter(SampleMessageProvider::class)
message: Message
) {
val nick = HostmaskHelper.nick(message.sender)
val senderColor = SenderColors[SenderColorUtil.senderColor(nick)]
Column {
Row {
Text(
message.senderPrefixes,
style = Typography.body2,
fontWeight = FontWeight.Bold
)
Text(
nick,
style = Typography.body2,
fontWeight = FontWeight.Bold,
color = senderColor
)
Spacer(Modifier.width(4.dp))
Text(
message.realName,
modifier = Modifier.weight(1.0f),
style = Typography.body2,
color = Color(0x8A000000)
)
}
Row {
Text(
message.content,
modifier = Modifier.weight(1.0f),
style = Typography.body2
)
Text(
message.time
.atZone(ZoneId.systemDefault())
.format(formatter),
style = Typography.body2,
color = Color(0x8A000000),
fontSize = 12.sp
)
}
}
}
class SampleMessageProvider : PreviewParameterProvider<Message> {
override val values = sequenceOf(
Message(
messageId = MsgId(108062924),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T18:24:48.891Z"),
type = MessageType.of(MessageType.Quit),
sender = "CrazyBonz!~CrazyBonz@user/CrazyBonz",
senderPrefixes = "",
avatarUrl = "",
realName = "CrazyBonz",
content = "#quasseldroid",
flag = MessageFlag.of()
),
Message(
messageId = MsgId(108063975),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T19:56:01.588Z"),
type = MessageType.of(MessageType.Plain),
sender = "winch!~AdminUser@185.14.29.13",
senderPrefixes = "",
avatarUrl = "",
realName = "Wincher,,,",
content = "Can i script some actions like in mIRC?",
flag = MessageFlag.of()
),
Message(
messageId = MsgId(108064014),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T20:06:39.159Z"),
type = MessageType.of(MessageType.Quit),
sender = "mavhq!~quassel@mapp-14-b2-v4wan-161519-cust401.vm15.cable.virginm.net",
senderPrefixes = "",
avatarUrl = "",
realName = "mavhc",
content = "Quit: http://quassel-irc.org - Chat comfortably. Anywhere.",
flag = MessageFlag.of()
),
Message(
messageId = MsgId(108064022),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T20:07:13.45Z"),
type = MessageType.of(MessageType.Join),
sender = "mavhq!~quassel@mapp-14-b2-v4wan-161519-cust401.vm15.cable.virginm.net",
senderPrefixes = "",
avatarUrl = "",
realName = "mavhc",
content = "#quasseldroid",
flag = MessageFlag.of()
)
)
}
package de.justjanne.quasseldroid.ui.routes
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import de.justjanne.bitflags.of
import de.justjanne.libquassel.protocol.models.BufferInfo
import de.justjanne.libquassel.protocol.models.Message
import de.justjanne.libquassel.protocol.models.flags.BufferType
import de.justjanne.libquassel.protocol.models.flags.MessageFlag
import de.justjanne.libquassel.protocol.models.flags.MessageType
import de.justjanne.libquassel.protocol.models.ids.BufferId
import de.justjanne.libquassel.protocol.models.ids.MsgId
import de.justjanne.libquassel.protocol.models.ids.NetworkId
import org.threeten.bp.Instant
class SampleMessageProvider : PreviewParameterProvider<Message> {
override val values = sequenceOf(
Message(
messageId = MsgId(108062924),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T18:24:48.891Z"),
type = MessageType.of(MessageType.Quit),
sender = "CrazyBonz!~CrazyBonz@user/CrazyBonz",
senderPrefixes = "",
avatarUrl = "",
realName = "CrazyBonz",
content = "#quasseldroid",
flag = MessageFlag.of()
),
Message(
messageId = MsgId(108063975),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T19:56:01.588Z"),
type = MessageType.of(MessageType.Plain),
sender = "winch!~AdminUser@185.14.29.13",
senderPrefixes = "",
avatarUrl = "",
realName = "Wincher,,,",
content = "Can i script some actions like in mIRC?",
flag = MessageFlag.of()
),
Message(
messageId = MsgId(108064014),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T20:06:39.159Z"),
type = MessageType.of(MessageType.Quit),
sender = "mavhq!~quassel@mapp-14-b2-v4wan-161519-cust401.vm15.cable.virginm.net",
senderPrefixes = "",
avatarUrl = "",
realName = "mavhc",
content = "Quit: http://quassel-irc.org - Chat comfortably. Anywhere.",
flag = MessageFlag.of()
),
Message(
messageId = MsgId(108064022),
bufferInfo = BufferInfo(
bufferId = BufferId(3746),
bufferName = "#quasseldroid",
networkId = NetworkId(4),
type = BufferType.of(BufferType.Channel)
),
time = Instant.parse("2022-02-20T20:07:13.45Z"),
type = MessageType.of(MessageType.Join),
sender = "mavhq!~quassel@mapp-14-b2-v4wan-161519-cust401.vm15.cable.virginm.net",
senderPrefixes = "",
avatarUrl = "",
realName = "mavhc",
content = "#quasseldroid",
flag = MessageFlag.of()
)
)
}
package de.justjanne.quasseldroid.ui.theme
import androidx.compose.ui.graphics.Color
val Primary = Color(0xFF0a70c0)
val PrimaryDark = Color(0xFF105a94)
val Accent = Color(0xFFffaf3b)
val Secure = Color(0xFF4CAF50)
val PartiallySecure = Color(0xFFFFC107)
val Insecure = Color(0xFFD32F2F)
val SenderColors = listOf(
Color(0xFF_b80a73),
Color(0xFF_814dd5),
Color(0xFF_9f0b0b),
Color(0xFF_139f2f),
Color(0xFF_4e9c9f),
Color(0xFF_8b4a9f),
Color(0xFF_9f8669),
Color(0xFF_2b6b9f),
Color(0xFF_e00d8f),
Color(0xFF_995bfd),
Color(0xFF_c70e0e),
Color(0xFF_18c73e),
Color(0xFF_61c6c7),
Color(0xFF_af5ec7),
Color(0xFF_c7a782),
Color(0xFF_3684c7),
)
package de.justjanne.quasseldroid.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.Colors
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import de.justjanne.quasseldroid.ui.theme.quassel.ActivityColors
import de.justjanne.quasseldroid.ui.theme.quassel.ChatColors
import de.justjanne.quasseldroid.ui.theme.quassel.LocalActivityColors
import de.justjanne.quasseldroid.ui.theme.quassel.LocalChatColors
import de.justjanne.quasseldroid.ui.theme.quassel.LocalMircColors
import de.justjanne.quasseldroid.ui.theme.quassel.LocalSecurityColors
import de.justjanne.quasseldroid.ui.theme.quassel.LocalSenderColors
import de.justjanne.quasseldroid.ui.theme.quassel.MircColors
import de.justjanne.quasseldroid.ui.theme.quassel.SecurityColors
import de.justjanne.quasseldroid.ui.theme.quassel.SenderColors
import de.justjanne.quasseldroid.ui.theme.quassel.UiColors
private val DarkColorPalette = darkColors(
primary = Primary,
primaryVariant = PrimaryDark,
secondary = Accent
@Composable
fun QuasselTheme(
dark: Boolean = isSystemInDarkTheme(),
ui: UiColors = UiColors.Default,
chat: ChatColors = ChatColors.Default,
activity: ActivityColors = ActivityColors.Default,
security: SecurityColors = SecurityColors.Default,
sender: SenderColors = SenderColors.Default,
mirc: MircColors = MircColors.Default,
content: @Composable () -> Unit
) {
MaterialTheme(
colors = buildColors(dark, ui),
typography = Typography,
shapes = Shapes
) {
CompositionLocalProvider(
LocalChatColors provides chat,
LocalActivityColors provides activity,
LocalSecurityColors provides security,
LocalSenderColors provides sender,
LocalMircColors provides mirc,
content = content
)
}
}
private val LightColorPalette = lightColors(
primary = Primary,
primaryVariant = PrimaryDark,
secondary = Accent
/* Other default colors to override
background = Color.White,
surface = Color.White,
onPrimary = Color.White,
onSecondary = Color.Black,
onBackground = Color.Black,
onSurface = Color.Black,
*/
private fun buildColors(dark: Boolean, ui: UiColors): Colors = if (dark) {
darkColors(
primary = ui.primary,
primaryVariant = ui.primaryVariant,
secondary = ui.secondary,
)
@Composable
fun QuasseldroidTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
lightColors(
primary = ui.primary,
primaryVariant = ui.primaryVariant,
secondary = ui.secondary,
)
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
object QuasselTheme {
val chat: ChatColors
@Composable get() = LocalChatColors.current
val activity: ActivityColors
@Composable get() = LocalActivityColors.current
val security: SecurityColors
@Composable get() = LocalSecurityColors.current
val sender: SenderColors
@Composable get() = LocalSenderColors.current
val mirc: MircColors
@Composable get() = LocalMircColors.current
}
package de.justjanne.quasseldroid.ui.theme.quassel
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
val LocalActivityColors = compositionLocalOf { ActivityColors.Default }
@Immutable
data class ActivityColors(
val activity: Color,
val message: Color,
val highlight: Color,
val notification: Color,
) {
companion object {
val Default = ActivityColors(
activity = Color(0xffafb42b),
message = Color(0xff1976d2),
highlight = Color(0xffffab00),
notification = Color(0xffd32f2f),
)
}
}
package de.justjanne.quasseldroid.ui.theme.quassel
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
val LocalChatColors = compositionLocalOf { ChatColors.Default }
@Immutable
data class ChatColors(
val action: Color,
val onAction: Color,
val notice: Color,
val onNotice: Color,
val highlight: Color,
val onHighlight: Color,
val error: Color,
val onError: Color,
) {
companion object {
val Default = ChatColors(
action = Color(0x00000000),
onAction = Color(0xff01579b),
notice = Color(0x00000000),
onNotice = Color(0xffb56a00),
highlight = Color(0x40ffaf3b),
onHighlight = Color(0xde000000),
error = Color(0x00000000),
onError = Color(0xffb71c1c),
)
}
}
package de.justjanne.quasseldroid.ui.theme.quassel
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
val LocalMircColors = compositionLocalOf { MircColors.Default }
@Immutable
data class MircColors(
val colors: List<Color>,
) {
companion object {
val Default = MircColors(
colors = listOf(
Color(0xffffffff),
Color(0xff000000),
Color(0xff000080),
Color(0xff008000),
Color(0xffff0000),
Color(0xff800000),
Color(0xff800080),
Color(0xffffa500),
Color(0xffffff00),
Color(0xff00ff00),
Color(0xff008080),
Color(0xff00ffff),
Color(0xff4169e1),
Color(0xffff00ff),
Color(0xff808080),
Color(0xffc0c0c0),
Color(0xff470000),
Color(0xff740000),
Color(0xffb50000),
Color(0xffff0000),
Color(0xffff5959),
Color(0xffff9c9c),
Color(0xff472100),
Color(0xff743a00),
Color(0xffb56300),
Color(0xffff8c00),
Color(0xffffb459),
Color(0xffffd39c),
Color(0xff474700),
Color(0xff747400),
Color(0xffb5b500),
Color(0xffffff00),
Color(0xffffff71),
Color(0xffffff9c),
Color(0xff324700),
Color(0xff517400),
Color(0xff7db500),
Color(0xffb2ff00),
Color(0xffcfff60),
Color(0xffe2ff9c),
Color(0xff004700),
Color(0xff007400),
Color(0xff00b500),
Color(0xff00ff00),
Color(0xff6fff6f),
Color(0xff9cff9c),
Color(0xff00472c),
Color(0xff007449),
Color(0xff00b571),
Color(0xff00ffa0),
Color(0xff65ffc9),
Color(0xff9cffdb),
Color(0xff004747),
Color(0xff007474),
Color(0xff00b5b5),
Color(0xff00ffff),
Color(0xff6dffff),
Color(0xff9cffff),
Color(0xff002747),
Color(0xff004074),
Color(0xff0063b5),
Color(0xff008cff),
Color(0xff59b4ff),
Color(0xff9cd3ff),
Color(0xff000047),
Color(0xff000074),
Color(0xff0000b5),
Color(0xff0000ff),
Color(0xff5959ff),
Color(0xff9c9cff),
Color(0xff2e0047),
Color(0xff4b0074),
Color(0xff7500b5),
Color(0xffa500ff),
Color(0xffc459ff),
Color(0xffdc9cff),
Color(0xff470047),
Color(0xff740074),
Color(0xffb500b5),
Color(0xffff00ff),
Color(0xffff66ff),
Color(0xffff9cff),
Color(0xff47002a),
Color(0xff740045),
Color(0xffb5006b),
Color(0xffff0098),
Color(0xffff59bc),
Color(0xffff94d3),
Color(0xff000000),
Color(0xff131313),
Color(0xff282828),
Color(0xff363636),
Color(0xff4d4d4d),
Color(0xff656565),
Color(0xff818181),
Color(0xff9f9f9f),
Color(0xffbcbcbc),
Color(0xffe2e2e2),
Color(0xffffffff),
)
)
}
}
package de.justjanne.quasseldroid.ui.theme.quassel
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
val LocalSecurityColors = compositionLocalOf { SecurityColors.Default }
@Immutable
data class SecurityColors(
val secure: Color,
val unverified: Color,
val insecure: Color,
) {
companion object {
val Default = SecurityColors(
secure = Color(0xff4caf50),
unverified = Color(0xffffc107),
insecure = Color(0xffd32f2f),
)
}
}
package de.justjanne.quasseldroid.ui.theme.quassel
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
val LocalSenderColors = compositionLocalOf { SenderColors.Default }
@Immutable
data class SenderColors(
val colors: List<Color>,
) {
companion object {
val Default = SenderColors(
colors = listOf(
Color(0xfff44336),
Color(0xff2196f3),
Color(0xff7cb342),
Color(0xff7b1fa2),
Color(0xffda8e00),
Color(0xff4caf50),
Color(0xff3f51b5),
Color(0xffe91e63),
Color(0xffb94600),
Color(0xff9e9d24),
Color(0xff558b2f),
Color(0xff009688),
Color(0xff0277bd),
Color(0xff00838f),
Color(0xff9c27b0),
Color(0xffc51162),
)
)
}
}
package de.justjanne.quasseldroid.ui.theme.quassel
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
@Immutable
data class UiColors(
val primary: Color,
val primaryVariant: Color,
val secondary: Color,
) {
companion object {
val Default = UiColors(
primary = Color(0xff0a70c0),
primaryVariant = Color(0xff105a94),
secondary = Color(0xffffaf3b),
)
}
}
......@@ -19,6 +19,7 @@ androidx-compose-animation = { module = "androidx.compose.animation:animation",
androidx-compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "androidx-compose" }
androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "androidx-compose" }
androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-compose" }
androidx-compose-material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "androidx-compose" }
androidx-compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "androidx-compose" }
androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "androidx-compose" }
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "androidx-compose" }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment