fix: pull to refresh indicator in filtered contents (#856)

This commit is contained in:
Diego Beraldin 2024-05-16 19:11:24 +02:00 committed by GitHub
parent f9ed0337fc
commit 8c167c8975
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
505 changed files with 23792 additions and 20621 deletions

View File

@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
var loadingFinished = false var loadingFinished = false
installSplashScreen().setKeepOnScreenCondition { installSplashScreen().setKeepOnScreenCondition {
@ -27,7 +26,8 @@ class MainActivity : ComponentActivity() {
// manage exit confirmation // manage exit confirmation
val navigationCoordinator = getNavigationCoordinator() val navigationCoordinator = getNavigationCoordinator()
val backPressedCallback = object : OnBackPressedCallback(true) { val backPressedCallback =
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
// if in home, ask for confirmation // if in home, ask for confirmation
if (navigationCoordinator.currentSection.value == TabNavigationSection.Home) { if (navigationCoordinator.currentSection.value == TabNavigationSection.Home) {
@ -46,7 +46,8 @@ class MainActivity : ComponentActivity() {
} }
} }
// when back is detected and the confirmation callback is not active, terminate the activity // when back is detected and the confirmation callback is not active, terminate the activity
val finishBackPressedCallback = object : OnBackPressedCallback(false) { val finishBackPressedCallback =
object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
navigationCoordinator.setExitMessageVisible(false) navigationCoordinator.setExitMessageVisible(false)
finish() finish()
@ -75,13 +76,16 @@ class MainActivity : ComponentActivity() {
handleIntent(intent) handleIntent(intent)
} }
private fun handleIntent(intent: Intent?) = intent?.apply { private fun handleIntent(intent: Intent?) =
intent?.apply {
when (action) { when (action) {
Intent.ACTION_SEND -> intent.getStringExtra(Intent.EXTRA_TEXT)?.let { content -> Intent.ACTION_SEND ->
intent.getStringExtra(Intent.EXTRA_TEXT)?.let { content ->
handleCreatePost(content) handleCreatePost(content)
} }
else -> data.toString().takeUnless { it.isEmpty() }?.also { url -> else ->
data.toString().takeUnless { it.isEmpty() }?.also { url ->
handleDeeplink(url) handleDeeplink(url)
} }
} }
@ -94,7 +98,8 @@ class MainActivity : ComponentActivity() {
private fun handleCreatePost(content: String) { private fun handleCreatePost(content: String) {
val looksLikeAnUrl = Patterns.WEB_URL.matcher(content).matches() val looksLikeAnUrl = Patterns.WEB_URL.matcher(content).matches()
val event = if (looksLikeAnUrl) { val event =
if (looksLikeAnUrl) {
ComposeEvent.WithUrl(content) ComposeEvent.WithUrl(content)
} else { } else {
ComposeEvent.WithText(content) ComposeEvent.WithText(content)

View File

@ -24,7 +24,8 @@ class MainApplication : Application(), ImageLoaderFactory {
sharedHelperModule, sharedHelperModule,
) )
AppInfo.versionCode = buildString { AppInfo.versionCode =
buildString {
append(BuildConfig.VERSION_NAME) append(BuildConfig.VERSION_NAME)
append(" (") append(" (")
append(BuildConfig.VERSION_CODE) append(BuildConfig.VERSION_CODE)

View File

@ -5,11 +5,12 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvide
import org.koin.core.qualifier.named import org.koin.core.qualifier.named
import org.koin.dsl.module import org.koin.dsl.module
val coreApiModule = module { val coreApiModule =
module {
single<ServiceProvider>(named("default")) { single<ServiceProvider>(named("default")) {
DefaultServiceProvider() DefaultServiceProvider()
} }
single<ServiceProvider>(named("custom")) { single<ServiceProvider>(named("custom")) {
DefaultServiceProvider() DefaultServiceProvider()
} }
} }

View File

@ -21,7 +21,6 @@ import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
internal class DefaultServiceProvider : ServiceProvider { internal class DefaultServiceProvider : ServiceProvider {
companion object { companion object {
private const val DEFAULT_INSTANCE = "lemmy.world" private const val DEFAULT_INSTANCE = "lemmy.world"
private const val VERSION = "v3" private const val VERSION = "v3"
@ -74,7 +73,8 @@ internal class DefaultServiceProvider : ServiceProvider {
} }
private fun reinitialize() { private fun reinitialize() {
val client = HttpClient(factory) { val client =
HttpClient(factory) {
defaultRequest { defaultRequest {
url { url {
host = currentInstance host = currentInstance
@ -100,7 +100,8 @@ internal class DefaultServiceProvider : ServiceProvider {
) )
} }
} }
val ktorfit = Ktorfit.Builder() val ktorfit =
Ktorfit.Builder()
.baseUrl(baseUrl) .baseUrl(baseUrl)
.httpClient(client) .httpClient(client)
.build() .build()

View File

@ -3,8 +3,9 @@ package com.github.diegoberaldin.raccoonforlemmy.core.api.provider
import com.github.diegoberaldin.raccoonforlemmy.core.utils.debug.logDebug import com.github.diegoberaldin.raccoonforlemmy.core.utils.debug.logDebug
import io.ktor.client.plugins.logging.Logger import io.ktor.client.plugins.logging.Logger
internal val defaultLogger = object : Logger { internal val defaultLogger =
object : Logger {
override fun log(message: String) { override fun log(message: String) {
logDebug(message) logDebug(message)
} }
} }

View File

@ -11,7 +11,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.api.service.SiteService
import com.github.diegoberaldin.raccoonforlemmy.core.api.service.UserService import com.github.diegoberaldin.raccoonforlemmy.core.api.service.UserService
interface ServiceProvider { interface ServiceProvider {
val currentInstance: String val currentInstance: String
val auth: AuthService val auth: AuthService
val post: PostService val post: PostService

View File

@ -26,7 +26,6 @@ import de.jensklingenberg.ktorfit.http.PUT
import de.jensklingenberg.ktorfit.http.Query import de.jensklingenberg.ktorfit.http.Query
interface CommunityService { interface CommunityService {
@GET("community") @GET("community")
suspend fun get( suspend fun get(
@Header("Authorization") authHeader: String? = null, @Header("Authorization") authHeader: String? = null,

View File

@ -25,7 +25,6 @@ import de.jensklingenberg.ktorfit.http.PUT
import de.jensklingenberg.ktorfit.http.Query import de.jensklingenberg.ktorfit.http.Query
interface UserService { interface UserService {
@GET("user") @GET("user")
suspend fun getDetails( suspend fun getDetails(
@Header("Authorization") authHeader: String? = null, @Header("Authorization") authHeader: String? = null,

View File

@ -13,15 +13,20 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
class DefaultBarColorProvider : BarColorProvider { class DefaultBarColorProvider : BarColorProvider {
@Composable @Composable
override fun setBarColorAccordingToTheme(theme: UiTheme, barTheme: UiBarTheme) { override fun setBarColorAccordingToTheme(
theme: UiTheme,
barTheme: UiBarTheme,
) {
val view = LocalView.current val view = LocalView.current
LaunchedEffect(theme, barTheme) { LaunchedEffect(theme, barTheme) {
(view.context as? Activity)?.window?.apply { (view.context as? Activity)?.window?.apply {
val baseColor = when (theme) { val baseColor =
when (theme) {
UiTheme.Light -> Color.White UiTheme.Light -> Color.White
else -> Color.Black else -> Color.Black
} }
val barColor = when (barTheme) { val barColor =
when (barTheme) {
UiBarTheme.Opaque -> baseColor.copy(alpha = 0.25f) UiBarTheme.Opaque -> baseColor.copy(alpha = 0.25f)
UiBarTheme.Transparent -> baseColor.copy(alpha = 0.01f) UiBarTheme.Transparent -> baseColor.copy(alpha = 0.01f)
else -> baseColor else -> baseColor
@ -40,11 +45,13 @@ class DefaultBarColorProvider : BarColorProvider {
} }
WindowCompat.getInsetsController(this, decorView).apply { WindowCompat.getInsetsController(this, decorView).apply {
isAppearanceLightStatusBars = when (theme) { isAppearanceLightStatusBars =
when (theme) {
UiTheme.Light -> true UiTheme.Light -> true
else -> false else -> false
} }
isAppearanceLightNavigationBars = when (theme) { isAppearanceLightNavigationBars =
when (theme) {
UiTheme.Light -> true UiTheme.Light -> true
else -> false else -> false
} }

View File

@ -12,7 +12,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.materialkolor.dynamicColorScheme import com.materialkolor.dynamicColorScheme
internal class DefaultColorSchemeProvider(private val context: Context) : ColorSchemeProvider { internal class DefaultColorSchemeProvider(private val context: Context) : ColorSchemeProvider {
override val supportsDynamicColors: Boolean override val supportsDynamicColors: Boolean
@ChecksSdkIntAtLeast(31) @ChecksSdkIntAtLeast(31)
get() { get() {
@ -24,7 +23,8 @@ internal class DefaultColorSchemeProvider(private val context: Context) : ColorS
theme: UiTheme, theme: UiTheme,
dynamic: Boolean, dynamic: Boolean,
customSeed: Color?, customSeed: Color?,
): ColorScheme = when (theme) { ): ColorScheme =
when (theme) {
UiTheme.Dark -> { UiTheme.Dark -> {
when { when {
dynamic -> { dynamic -> {

View File

@ -13,7 +13,6 @@ import kotlin.test.assertNotEquals
import kotlin.test.assertNull import kotlin.test.assertNull
class DefaultThemeRepositoryTest { class DefaultThemeRepositoryTest {
@get:Rule @get:Rule
val dispatcherTestRule = DispatcherTestRule() val dispatcherTestRule = DispatcherTestRule()

View File

@ -6,62 +6,72 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface CommentBarTheme { sealed interface CommentBarTheme {
data object Green : CommentBarTheme data object Green : CommentBarTheme
data object Blue : CommentBarTheme data object Blue : CommentBarTheme
data object Red : CommentBarTheme data object Red : CommentBarTheme
data object Rainbow : CommentBarTheme data object Rainbow : CommentBarTheme
} }
fun Int?.toCommentBarTheme(): CommentBarTheme = when (this) { fun Int?.toCommentBarTheme(): CommentBarTheme =
when (this) {
3 -> CommentBarTheme.Rainbow 3 -> CommentBarTheme.Rainbow
2 -> CommentBarTheme.Red 2 -> CommentBarTheme.Red
1 -> CommentBarTheme.Green 1 -> CommentBarTheme.Green
else -> CommentBarTheme.Blue else -> CommentBarTheme.Blue
} }
fun CommentBarTheme.toInt(): Int = when (this) { fun CommentBarTheme.toInt(): Int =
when (this) {
CommentBarTheme.Rainbow -> 3 CommentBarTheme.Rainbow -> 3
CommentBarTheme.Red -> 2 CommentBarTheme.Red -> 2
CommentBarTheme.Green -> 1 CommentBarTheme.Green -> 1
CommentBarTheme.Blue -> 0 CommentBarTheme.Blue -> 0
} }
@Composable @Composable
fun CommentBarTheme?.toReadableName() = when (this) { fun CommentBarTheme?.toReadableName() =
when (this) {
CommentBarTheme.Rainbow -> LocalXmlStrings.current.settingsCommentBarThemeMulti CommentBarTheme.Rainbow -> LocalXmlStrings.current.settingsCommentBarThemeMulti
CommentBarTheme.Red -> LocalXmlStrings.current.settingsCommentBarThemeRed CommentBarTheme.Red -> LocalXmlStrings.current.settingsCommentBarThemeRed
CommentBarTheme.Green -> LocalXmlStrings.current.settingsCommentBarThemeGreen CommentBarTheme.Green -> LocalXmlStrings.current.settingsCommentBarThemeGreen
CommentBarTheme.Blue -> LocalXmlStrings.current.settingsCommentBarThemeBlue CommentBarTheme.Blue -> LocalXmlStrings.current.settingsCommentBarThemeBlue
else -> LocalXmlStrings.current.settingsColorCustom else -> LocalXmlStrings.current.settingsColorCustom
} }
fun CommentBarTheme?.toUpVoteColor(): Color = when (this) { fun CommentBarTheme?.toUpVoteColor(): Color =
when (this) {
CommentBarTheme.Rainbow -> Color(0xFF00FF00) CommentBarTheme.Rainbow -> Color(0xFF00FF00)
CommentBarTheme.Red -> Color(0xFFD00000) CommentBarTheme.Red -> Color(0xFFD00000)
CommentBarTheme.Green -> Color(0xFF52B788) CommentBarTheme.Green -> Color(0xFF52B788)
CommentBarTheme.Blue -> Color(0xFF014F86) CommentBarTheme.Blue -> Color(0xFF014F86)
else -> Color.Transparent else -> Color.Transparent
} }
fun CommentBarTheme?.toDownVoteColor(): Color = when (this) { fun CommentBarTheme?.toDownVoteColor(): Color =
when (this) {
CommentBarTheme.Rainbow -> Color(0xFFFF0000) CommentBarTheme.Rainbow -> Color(0xFFFF0000)
CommentBarTheme.Red -> Color(0xFF2FFFFF) CommentBarTheme.Red -> Color(0xFF2FFFFF)
CommentBarTheme.Green -> Color(0xFFAD4877) CommentBarTheme.Green -> Color(0xFFAD4877)
CommentBarTheme.Blue -> Color(0xFF9400D3) CommentBarTheme.Blue -> Color(0xFF9400D3)
else -> Color.Transparent else -> Color.Transparent
} }
fun CommentBarTheme?.toReplyColor(): Color = when (this) { fun CommentBarTheme?.toReplyColor(): Color =
when (this) {
CommentBarTheme.Rainbow -> Color(0xFFFF5722) CommentBarTheme.Rainbow -> Color(0xFFFF5722)
CommentBarTheme.Red -> Color(0xFF8BC34A) CommentBarTheme.Red -> Color(0xFF8BC34A)
CommentBarTheme.Green -> Color(0xFFFF9800) CommentBarTheme.Green -> Color(0xFFFF9800)
CommentBarTheme.Blue -> Color(0xFF388E3C) CommentBarTheme.Blue -> Color(0xFF388E3C)
else -> Color.Transparent else -> Color.Transparent
} }
fun CommentBarTheme?.toSaveColor(): Color = when (this) { fun CommentBarTheme?.toSaveColor(): Color =
when (this) {
CommentBarTheme.Rainbow -> Color(0xFFE040FB) CommentBarTheme.Rainbow -> Color(0xFFE040FB)
CommentBarTheme.Red -> Color(0xFFFFC107) CommentBarTheme.Red -> Color(0xFFFFC107)
CommentBarTheme.Green -> Color(0xFF388E3C) CommentBarTheme.Green -> Color(0xFF388E3C)
CommentBarTheme.Blue -> Color(0xFF7C4DFF) CommentBarTheme.Blue -> Color(0xFF7C4DFF)
else -> Color.Transparent else -> Color.Transparent
} }

View File

@ -5,16 +5,23 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface FontScale { sealed interface FontScale {
data object Largest : FontScale data object Largest : FontScale
data object Larger : FontScale data object Larger : FontScale
data object Large : FontScale data object Large : FontScale
data object Normal : FontScale data object Normal : FontScale
data object Small : FontScale data object Small : FontScale
data object Smaller : FontScale data object Smaller : FontScale
data object Smallest : FontScale data object Smallest : FontScale
} }
val FontScale.scaleFactor: Float val FontScale.scaleFactor: Float
get() = when (this) { get() =
when (this) {
FontScale.Largest -> ReferenceValues.largest FontScale.Largest -> ReferenceValues.largest
FontScale.Larger -> ReferenceValues.larger FontScale.Larger -> ReferenceValues.larger
FontScale.Large -> ReferenceValues.large FontScale.Large -> ReferenceValues.large
@ -25,7 +32,8 @@ val FontScale.scaleFactor: Float
} }
@Composable @Composable
fun FontScale.toReadableName(): String = when (this) { fun FontScale.toReadableName(): String =
when (this) {
FontScale.Largest -> LocalXmlStrings.current.settingsContentFontLargest FontScale.Largest -> LocalXmlStrings.current.settingsContentFontLargest
FontScale.Larger -> LocalXmlStrings.current.settingsContentFontLarger FontScale.Larger -> LocalXmlStrings.current.settingsContentFontLarger
FontScale.Large -> LocalXmlStrings.current.settingsContentFontLarge FontScale.Large -> LocalXmlStrings.current.settingsContentFontLarge
@ -33,9 +41,10 @@ fun FontScale.toReadableName(): String = when (this) {
FontScale.Small -> LocalXmlStrings.current.settingsContentFontSmall FontScale.Small -> LocalXmlStrings.current.settingsContentFontSmall
FontScale.Smaller -> LocalXmlStrings.current.settingsContentFontSmaller FontScale.Smaller -> LocalXmlStrings.current.settingsContentFontSmaller
FontScale.Smallest -> LocalXmlStrings.current.settingsContentFontSmallest FontScale.Smallest -> LocalXmlStrings.current.settingsContentFontSmallest
} }
fun Float.toFontScale(): FontScale = when (this) { fun Float.toFontScale(): FontScale =
when (this) {
ReferenceValues.largest -> FontScale.Largest ReferenceValues.largest -> FontScale.Largest
ReferenceValues.larger -> FontScale.Larger ReferenceValues.larger -> FontScale.Larger
ReferenceValues.large -> FontScale.Large ReferenceValues.large -> FontScale.Large
@ -43,7 +52,7 @@ fun Float.toFontScale(): FontScale = when (this) {
ReferenceValues.smaller -> FontScale.Smaller ReferenceValues.smaller -> FontScale.Smaller
ReferenceValues.smallest -> FontScale.Smallest ReferenceValues.smallest -> FontScale.Smallest
else -> FontScale.Normal else -> FontScale.Normal
} }
// log(2 + 0.1 * n) / log(2) // log(2 + 0.1 * n) / log(2)
private object ReferenceValues { private object ReferenceValues {

View File

@ -5,25 +5,30 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface PostLayout { sealed interface PostLayout {
data object Card : PostLayout data object Card : PostLayout
data object Compact : PostLayout data object Compact : PostLayout
data object Full : PostLayout data object Full : PostLayout
} }
@Composable @Composable
fun PostLayout.toReadableName(): String = when (this) { fun PostLayout.toReadableName(): String =
when (this) {
PostLayout.Full -> LocalXmlStrings.current.settingsPostLayoutFull PostLayout.Full -> LocalXmlStrings.current.settingsPostLayoutFull
PostLayout.Compact -> LocalXmlStrings.current.settingsPostLayoutCompact PostLayout.Compact -> LocalXmlStrings.current.settingsPostLayoutCompact
else -> LocalXmlStrings.current.settingsPostLayoutCard else -> LocalXmlStrings.current.settingsPostLayoutCard
} }
fun Int.toPostLayout(): PostLayout = when (this) { fun Int.toPostLayout(): PostLayout =
when (this) {
1 -> PostLayout.Compact 1 -> PostLayout.Compact
2 -> PostLayout.Full 2 -> PostLayout.Full
else -> PostLayout.Card else -> PostLayout.Card
} }
fun PostLayout.toInt(): Int = when (this) { fun PostLayout.toInt(): Int =
when (this) {
PostLayout.Full -> 2 PostLayout.Full -> 2
PostLayout.Compact -> 1 PostLayout.Compact -> 1
else -> 0 else -> 0
} }

View File

@ -5,19 +5,23 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface UiBarTheme { sealed interface UiBarTheme {
data object Solid : UiBarTheme data object Solid : UiBarTheme
data object Transparent : UiBarTheme data object Transparent : UiBarTheme
data object Opaque : UiBarTheme data object Opaque : UiBarTheme
} }
fun UiBarTheme?.toInt(): Int = when (this) { fun UiBarTheme?.toInt(): Int =
when (this) {
UiBarTheme.Transparent -> 2 UiBarTheme.Transparent -> 2
UiBarTheme.Opaque -> 1 UiBarTheme.Opaque -> 1
else -> 0 else -> 0
} }
@Composable @Composable
fun UiBarTheme?.toReadableName(): String = when (this) { fun UiBarTheme?.toReadableName(): String =
when (this) {
UiBarTheme.Transparent -> LocalXmlStrings.current.barThemeTransparent UiBarTheme.Transparent -> LocalXmlStrings.current.barThemeTransparent
UiBarTheme.Opaque -> LocalXmlStrings.current.barThemeOpaque UiBarTheme.Opaque -> LocalXmlStrings.current.barThemeOpaque
else -> "" else -> ""
} }

View File

@ -10,24 +10,27 @@ enum class UiFontFamily {
Poppins, Poppins,
} }
fun Int.toUiFontFamily() = when (this) { fun Int.toUiFontFamily() =
when (this) {
0 -> UiFontFamily.Poppins 0 -> UiFontFamily.Poppins
3 -> UiFontFamily.NotoSans 3 -> UiFontFamily.NotoSans
4 -> UiFontFamily.CharisSIL 4 -> UiFontFamily.CharisSIL
else -> UiFontFamily.Default else -> UiFontFamily.Default
} }
fun UiFontFamily.toInt() = when (this) { fun UiFontFamily.toInt() =
when (this) {
UiFontFamily.Poppins -> 0 UiFontFamily.Poppins -> 0
UiFontFamily.NotoSans -> 3 UiFontFamily.NotoSans -> 3
UiFontFamily.CharisSIL -> 4 UiFontFamily.CharisSIL -> 4
UiFontFamily.Default -> 7 UiFontFamily.Default -> 7
} }
@Composable @Composable
fun UiFontFamily.toReadableName() = when (this) { fun UiFontFamily.toReadableName() =
when (this) {
UiFontFamily.Poppins -> "Poppins" UiFontFamily.Poppins -> "Poppins"
UiFontFamily.NotoSans -> "Noto Sans" UiFontFamily.NotoSans -> "Noto Sans"
UiFontFamily.CharisSIL -> "Charis SIL" UiFontFamily.CharisSIL -> "Charis SIL"
UiFontFamily.Default -> LocalXmlStrings.current.settingsFontFamilyDefault UiFontFamily.Default -> LocalXmlStrings.current.settingsFontFamilyDefault
} }

View File

@ -10,34 +10,40 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface UiTheme { sealed interface UiTheme {
data object Light : UiTheme data object Light : UiTheme
data object Dark : UiTheme data object Dark : UiTheme
data object Black : UiTheme data object Black : UiTheme
} }
fun Int?.toUiTheme(): UiTheme? = when (this) { fun Int?.toUiTheme(): UiTheme? =
when (this) {
2 -> UiTheme.Black 2 -> UiTheme.Black
1 -> UiTheme.Dark 1 -> UiTheme.Dark
0 -> UiTheme.Light 0 -> UiTheme.Light
else -> null else -> null
} }
fun UiTheme?.toInt(): Int? = when (this) { fun UiTheme?.toInt(): Int? =
when (this) {
UiTheme.Black -> 2 UiTheme.Black -> 2
UiTheme.Dark -> 1 UiTheme.Dark -> 1
UiTheme.Light -> 0 UiTheme.Light -> 0
else -> null else -> null
} }
@Composable @Composable
fun UiTheme?.toReadableName(): String = when (this) { fun UiTheme?.toReadableName(): String =
when (this) {
UiTheme.Black -> LocalXmlStrings.current.settingsThemeBlack UiTheme.Black -> LocalXmlStrings.current.settingsThemeBlack
UiTheme.Dark -> LocalXmlStrings.current.settingsThemeDark UiTheme.Dark -> LocalXmlStrings.current.settingsThemeDark
UiTheme.Light -> LocalXmlStrings.current.settingsThemeLight UiTheme.Light -> LocalXmlStrings.current.settingsThemeLight
else -> LocalXmlStrings.current.settingsFontFamilyDefault else -> LocalXmlStrings.current.settingsFontFamilyDefault
} }
fun UiTheme.toIcon(): ImageVector = when (this) { fun UiTheme.toIcon(): ImageVector =
when (this) {
UiTheme.Black -> Icons.Default.DarkMode UiTheme.Black -> Icons.Default.DarkMode
UiTheme.Dark -> Icons.Outlined.DarkMode UiTheme.Dark -> Icons.Outlined.DarkMode
UiTheme.Light -> Icons.Default.LightMode UiTheme.Light -> Icons.Default.LightMode
} }

View File

@ -9,32 +9,38 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface VoteFormat { sealed interface VoteFormat {
data object Aggregated : VoteFormat data object Aggregated : VoteFormat
data object Separated : VoteFormat data object Separated : VoteFormat
data object Percentage : VoteFormat data object Percentage : VoteFormat
data object Hidden : VoteFormat data object Hidden : VoteFormat
} }
fun VoteFormat.toLong(): Long = when (this) { fun VoteFormat.toLong(): Long =
when (this) {
VoteFormat.Percentage -> 2L VoteFormat.Percentage -> 2L
VoteFormat.Separated -> 1L VoteFormat.Separated -> 1L
VoteFormat.Aggregated -> 0L VoteFormat.Aggregated -> 0L
VoteFormat.Hidden -> -1L VoteFormat.Hidden -> -1L
} }
fun Long.toVoteFormat(): VoteFormat = when (this) { fun Long.toVoteFormat(): VoteFormat =
when (this) {
2L -> VoteFormat.Percentage 2L -> VoteFormat.Percentage
1L -> VoteFormat.Separated 1L -> VoteFormat.Separated
-1L -> VoteFormat.Hidden -1L -> VoteFormat.Hidden
else -> VoteFormat.Aggregated else -> VoteFormat.Aggregated
} }
@Composable @Composable
fun VoteFormat.toReadableName(): String = when (this) { fun VoteFormat.toReadableName(): String =
when (this) {
VoteFormat.Percentage -> LocalXmlStrings.current.settingsVoteFormatPercentage VoteFormat.Percentage -> LocalXmlStrings.current.settingsVoteFormatPercentage
VoteFormat.Separated -> LocalXmlStrings.current.settingsVoteFormatSeparated VoteFormat.Separated -> LocalXmlStrings.current.settingsVoteFormatSeparated
VoteFormat.Hidden -> LocalXmlStrings.current.settingsVoteFormatHidden VoteFormat.Hidden -> LocalXmlStrings.current.settingsVoteFormatHidden
else -> LocalXmlStrings.current.settingsVoteFormatAggregated else -> LocalXmlStrings.current.settingsVoteFormatAggregated
} }
fun formatToReadableValue( fun formatToReadableValue(
voteFormat: VoteFormat, voteFormat: VoteFormat,
@ -45,7 +51,8 @@ fun formatToReadableValue(
downVoteColor: Color, downVoteColor: Color,
upVoted: Boolean = false, upVoted: Boolean = false,
downVoted: Boolean = false, downVoted: Boolean = false,
): AnnotatedString = buildAnnotatedString { ): AnnotatedString =
buildAnnotatedString {
when (voteFormat) { when (voteFormat) {
VoteFormat.Percentage -> { VoteFormat.Percentage -> {
val totalVotes = upVotes + downVotes val totalVotes = upVotes + downVotes
@ -107,4 +114,4 @@ fun formatToReadableValue(
} }
} }
} }
} }

View File

@ -5,8 +5,9 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository.Theme
import org.koin.core.module.dsl.singleOf import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module import org.koin.dsl.module
val coreAppearanceModule = module { val coreAppearanceModule =
module {
includes(nativeAppearanceModule) includes(nativeAppearanceModule)
singleOf<ThemeRepository>(::DefaultThemeRepository) singleOf<ThemeRepository>(::DefaultThemeRepository)
} }

View File

@ -6,6 +6,9 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ColorSchem
import org.koin.core.module.Module import org.koin.core.module.Module
expect val nativeAppearanceModule: Module expect val nativeAppearanceModule: Module
expect fun getThemeRepository(): ThemeRepository expect fun getThemeRepository(): ThemeRepository
expect fun getColorSchemeProvider(): ColorSchemeProvider expect fun getColorSchemeProvider(): ColorSchemeProvider
expect fun getBarColorProvider(): BarColorProvider expect fun getBarColorProvider(): BarColorProvider

View File

@ -9,7 +9,10 @@ data class ContentFontScales(
sealed interface ContentFontClass { sealed interface ContentFontClass {
data object Title : ContentFontClass data object Title : ContentFontClass
data object Body : ContentFontClass data object Body : ContentFontClass
data object Comment : ContentFontClass data object Comment : ContentFontClass
data object AncillaryText : ContentFontClass data object AncillaryText : ContentFontClass
} }

View File

@ -8,7 +8,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
internal class DefaultThemeRepository : ThemeRepository { internal class DefaultThemeRepository : ThemeRepository {
override val uiTheme = MutableStateFlow<UiTheme?>(null) override val uiTheme = MutableStateFlow<UiTheme?>(null)
override val uiFontFamily = MutableStateFlow(UiFontFamily.Poppins) override val uiFontFamily = MutableStateFlow(UiFontFamily.Poppins)
override val uiFontScale = MutableStateFlow(1f) override val uiFontScale = MutableStateFlow(1f)
@ -52,7 +51,10 @@ internal class DefaultThemeRepository : ThemeRepository {
dynamicColors.value = value dynamicColors.value = value
} }
override fun getCommentBarColor(depth: Int, commentBarTheme: CommentBarTheme): Color { override fun getCommentBarColor(
depth: Int,
commentBarTheme: CommentBarTheme,
): Color {
val colors = getCommentBarColors(commentBarTheme) val colors = getCommentBarColors(commentBarTheme)
if (colors.isEmpty()) { if (colors.isEmpty()) {
return Color.Transparent return Color.Transparent
@ -91,7 +93,8 @@ internal class DefaultThemeRepository : ThemeRepository {
override fun getCommentBarColors(commentBarTheme: CommentBarTheme): List<Color> = override fun getCommentBarColors(commentBarTheme: CommentBarTheme): List<Color> =
when (commentBarTheme) { when (commentBarTheme) {
CommentBarTheme.Green -> buildList { CommentBarTheme.Green ->
buildList {
this += Color(0xFF1B4332) this += Color(0xFF1B4332)
this += Color(0xFF2D6A4F) this += Color(0xFF2D6A4F)
this += Color(0xFF40916C) this += Color(0xFF40916C)
@ -100,7 +103,8 @@ internal class DefaultThemeRepository : ThemeRepository {
this += Color(0xFF95D5B2) this += Color(0xFF95D5B2)
} }
CommentBarTheme.Red -> buildList { CommentBarTheme.Red ->
buildList {
this += Color(0xFF6A040F) this += Color(0xFF6A040F)
this += Color(0xFF9D0208) this += Color(0xFF9D0208)
this += Color(0xFFD00000) this += Color(0xFFD00000)
@ -109,7 +113,8 @@ internal class DefaultThemeRepository : ThemeRepository {
this += Color(0xFFF48C06) this += Color(0xFFF48C06)
} }
CommentBarTheme.Blue -> buildList { CommentBarTheme.Blue ->
buildList {
this += Color(0xFF012A4A) this += Color(0xFF012A4A)
this += Color(0xFF013A63) this += Color(0xFF013A63)
this += Color(0xFF014F86) this += Color(0xFF014F86)
@ -118,7 +123,8 @@ internal class DefaultThemeRepository : ThemeRepository {
this += Color(0xFFA9D6E5) this += Color(0xFFA9D6E5)
} }
CommentBarTheme.Rainbow -> buildList { CommentBarTheme.Rainbow ->
buildList {
this += Color(0xFF9400D3) this += Color(0xFF9400D3)
this += Color(0xFF0000FF) this += Color(0xFF0000FF)
this += Color(0xFF00FF00) this += Color(0xFF00FF00)

View File

@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.StateFlow
@Stable @Stable
interface ThemeRepository { interface ThemeRepository {
val uiTheme: StateFlow<UiTheme?> val uiTheme: StateFlow<UiTheme?>
val uiFontFamily: StateFlow<UiFontFamily> val uiFontFamily: StateFlow<UiFontFamily>
val uiFontScale: StateFlow<Float> val uiFontScale: StateFlow<Float>
@ -40,7 +39,10 @@ interface ThemeRepository {
fun changeDynamicColors(value: Boolean) fun changeDynamicColors(value: Boolean)
fun getCommentBarColor(depth: Int, commentBarTheme: CommentBarTheme): Color fun getCommentBarColor(
depth: Int,
commentBarTheme: CommentBarTheme,
): Color
fun changeCustomSeedColor(color: Color?) fun changeCustomSeedColor(color: Color?)
@ -49,6 +51,7 @@ interface ThemeRepository {
fun changeDownVoteColor(color: Color?) fun changeDownVoteColor(color: Color?)
fun changeReplyColor(color: Color?) fun changeReplyColor(color: Color?)
fun changeSaveColor(color: Color?) fun changeSaveColor(color: Color?)
fun changePostLayout(value: PostLayout) fun changePostLayout(value: PostLayout)

View File

@ -18,20 +18,23 @@ fun AppTheme(
barTheme: UiBarTheme = UiBarTheme.Solid, barTheme: UiBarTheme = UiBarTheme.Solid,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
val repository = remember { val repository =
remember {
getThemeRepository() getThemeRepository()
} }
val themeState by repository.uiTheme.collectAsState() val themeState by repository.uiTheme.collectAsState()
val customSeedColor by repository.customSeedColor.collectAsState() val customSeedColor by repository.customSeedColor.collectAsState()
val defaultTheme = if (isSystemInDarkTheme()) { val defaultTheme =
if (isSystemInDarkTheme()) {
UiTheme.Dark UiTheme.Dark
} else { } else {
UiTheme.Light UiTheme.Light
} }
val colorSchemeProvider = remember { getColorSchemeProvider() } val colorSchemeProvider = remember { getColorSchemeProvider() }
val colorScheme = colorSchemeProvider.getColorScheme( val colorScheme =
colorSchemeProvider.getColorScheme(
theme = themeState ?: defaultTheme, theme = themeState ?: defaultTheme,
dynamic = useDynamicColors, dynamic = useDynamicColors,
customSeed = customSeedColor, customSeed = customSeedColor,

View File

@ -6,5 +6,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
interface BarColorProvider { interface BarColorProvider {
@Composable @Composable
fun setBarColorAccordingToTheme(theme: UiTheme, barTheme: UiBarTheme) fun setBarColorAccordingToTheme(
theme: UiTheme,
barTheme: UiBarTheme,
)
} }

View File

@ -7,7 +7,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
@Stable @Stable
interface ColorSchemeProvider { interface ColorSchemeProvider {
val supportsDynamicColors: Boolean val supportsDynamicColors: Boolean
fun getColorScheme( fun getColorScheme(
@ -17,7 +16,8 @@ interface ColorSchemeProvider {
): ColorScheme ): ColorScheme
} }
fun ColorScheme.blackify(): ColorScheme = copy( fun ColorScheme.blackify(): ColorScheme =
copy(
background = md_theme_black_background, background = md_theme_black_background,
onBackground = md_theme_black_onBackground, onBackground = md_theme_black_onBackground,
surface = md_theme_black_surface, surface = md_theme_black_surface,
@ -30,4 +30,4 @@ fun ColorScheme.blackify(): ColorScheme = copy(
onSecondaryContainer = md_theme_black_onSecondaryContainer, onSecondaryContainer = md_theme_black_onSecondaryContainer,
tertiaryContainer = md_theme_black_tertiaryContainer, tertiaryContainer = md_theme_black_tertiaryContainer,
onTertiaryContainer = md_theme_black_onTertiaryContainer, onTertiaryContainer = md_theme_black_onTertiaryContainer,
) )

View File

@ -3,7 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme
import androidx.compose.material3.darkColorScheme import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
internal val LightColors = lightColorScheme( internal val LightColors =
lightColorScheme(
primary = md_theme_light_primary, primary = md_theme_light_primary,
onPrimary = md_theme_light_onPrimary, onPrimary = md_theme_light_onPrimary,
primaryContainer = md_theme_light_primaryContainer, primaryContainer = md_theme_light_primaryContainer,
@ -33,9 +34,10 @@ internal val LightColors = lightColorScheme(
surfaceTint = md_theme_light_surfaceTint, surfaceTint = md_theme_light_surfaceTint,
outlineVariant = md_theme_light_outlineVariant, outlineVariant = md_theme_light_outlineVariant,
scrim = md_theme_light_scrim, scrim = md_theme_light_scrim,
) )
internal val DarkColors = darkColorScheme( internal val DarkColors =
darkColorScheme(
primary = md_theme_dark_primary, primary = md_theme_dark_primary,
onPrimary = md_theme_dark_onPrimary, onPrimary = md_theme_dark_onPrimary,
primaryContainer = md_theme_dark_primaryContainer, primaryContainer = md_theme_dark_primaryContainer,
@ -65,6 +67,6 @@ internal val DarkColors = darkColorScheme(
surfaceTint = md_theme_dark_surfaceTint, surfaceTint = md_theme_dark_surfaceTint,
outlineVariant = md_theme_dark_outlineVariant, outlineVariant = md_theme_dark_outlineVariant,
scrim = md_theme_dark_scrim, scrim = md_theme_dark_scrim,
) )
internal val BlackColors = DarkColors.blackify() internal val BlackColors = DarkColors.blackify()

View File

@ -17,7 +17,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.resources.di.getCoreResourc
@Composable @Composable
fun UiFontFamily.toTypography(): Typography { fun UiFontFamily.toTypography(): Typography {
val coreResources = remember { getCoreResources() } val coreResources = remember { getCoreResources() }
val fontFamily = when (this) { val fontFamily =
when (this) {
UiFontFamily.NotoSans -> coreResources.notoSans UiFontFamily.NotoSans -> coreResources.notoSans
UiFontFamily.CharisSIL -> coreResources.charisSil UiFontFamily.CharisSIL -> coreResources.charisSil
UiFontFamily.Poppins -> coreResources.poppins UiFontFamily.Poppins -> coreResources.poppins
@ -25,7 +26,8 @@ fun UiFontFamily.toTypography(): Typography {
} }
return Typography( return Typography(
// h1 // h1
displayLarge = TextStyle( displayLarge =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 57.sp, fontSize = 57.sp,
@ -33,7 +35,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 64.sp, lineHeight = 64.sp,
), ),
// h2 // h2
displayMedium = TextStyle( displayMedium =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 45.sp, fontSize = 45.sp,
@ -41,14 +44,16 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 52.sp, lineHeight = 52.sp,
), ),
// h3 // h3
displaySmall = TextStyle( displaySmall =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 36.sp, fontSize = 36.sp,
letterSpacing = 0.sp, letterSpacing = 0.sp,
lineHeight = 44.sp, lineHeight = 44.sp,
), ),
headlineLarge = TextStyle( headlineLarge =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 32.sp, fontSize = 32.sp,
@ -56,7 +61,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 40.sp, lineHeight = 40.sp,
), ),
// h4 // h4
headlineMedium = TextStyle( headlineMedium =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 28.sp, fontSize = 28.sp,
@ -64,7 +70,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 36.sp, lineHeight = 36.sp,
), ),
// h5 // h5
headlineSmall = TextStyle( headlineSmall =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 24.sp, fontSize = 24.sp,
@ -72,7 +79,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 23.sp, lineHeight = 23.sp,
), ),
// h6 // h6
titleLarge = TextStyle( titleLarge =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 22.sp, fontSize = 22.sp,
@ -80,7 +88,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 28.sp, lineHeight = 28.sp,
), ),
// subtitle1 // subtitle1
titleMedium = TextStyle( titleMedium =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
fontSize = 16.sp, fontSize = 16.sp,
@ -88,7 +97,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 24.sp, lineHeight = 24.sp,
), ),
// subtitle2 // subtitle2
titleSmall = TextStyle( titleSmall =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
fontSize = 14.sp, fontSize = 14.sp,
@ -96,7 +106,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 20.sp, lineHeight = 20.sp,
), ),
// body1 // body1
bodyLarge = TextStyle( bodyLarge =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 16.sp, fontSize = 16.sp,
@ -104,7 +115,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 24.sp, lineHeight = 24.sp,
), ),
// body2 // body2
bodyMedium = TextStyle( bodyMedium =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 14.sp, fontSize = 14.sp,
@ -112,7 +124,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 20.sp, lineHeight = 20.sp,
), ),
// caption // caption
bodySmall = TextStyle( bodySmall =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 12.sp, fontSize = 12.sp,
@ -120,14 +133,16 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 16.sp, lineHeight = 16.sp,
), ),
// button // button
labelLarge = TextStyle( labelLarge =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
fontSize = 14.sp, fontSize = 14.sp,
letterSpacing = (0.1).sp, letterSpacing = (0.1).sp,
lineHeight = 20.sp, lineHeight = 20.sp,
), ),
labelMedium = TextStyle( labelMedium =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
fontSize = 12.sp, fontSize = 12.sp,
@ -135,7 +150,8 @@ fun UiFontFamily.toTypography(): Typography {
lineHeight = 16.sp, lineHeight = 16.sp,
), ),
// overline // overline
labelSmall = TextStyle( labelSmall =
TextStyle(
fontFamily = fontFamily, fontFamily = fontFamily,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
fontSize = 11.sp, fontSize = 11.sp,

View File

@ -4,8 +4,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
internal val shapes = Shapes( internal val shapes =
Shapes(
small = RoundedCornerShape(4.dp), small = RoundedCornerShape(4.dp),
medium = RoundedCornerShape(4.dp), medium = RoundedCornerShape(4.dp),
large = RoundedCornerShape(0.dp), large = RoundedCornerShape(0.dp),
) )

View File

@ -11,19 +11,19 @@ import org.koin.dsl.module
actual fun getThemeRepository(): ThemeRepository = CoreAppearanceHelper.repository actual fun getThemeRepository(): ThemeRepository = CoreAppearanceHelper.repository
actual val nativeAppearanceModule = module { actual val nativeAppearanceModule =
module {
single<ColorSchemeProvider> { single<ColorSchemeProvider> {
DefaultColorSchemeProvider() DefaultColorSchemeProvider()
} }
single<BarColorProvider> { single<BarColorProvider> {
DefaultBarColorProvider() DefaultBarColorProvider()
} }
} }
actual fun getColorSchemeProvider(): ColorSchemeProvider = CoreAppearanceHelper.colorSchemeProvider actual fun getColorSchemeProvider(): ColorSchemeProvider = CoreAppearanceHelper.colorSchemeProvider
actual fun getBarColorProvider(): BarColorProvider = actual fun getBarColorProvider(): BarColorProvider = CoreAppearanceHelper.barColorProvider
CoreAppearanceHelper.barColorProvider
object CoreAppearanceHelper : KoinComponent { object CoreAppearanceHelper : KoinComponent {
internal val repository: ThemeRepository by inject() internal val repository: ThemeRepository by inject()

View File

@ -11,9 +11,13 @@ import platform.UIKit.setStatusBarStyle
class DefaultBarColorProvider : BarColorProvider { class DefaultBarColorProvider : BarColorProvider {
@Composable @Composable
override fun setBarColorAccordingToTheme(theme: UiTheme, transparent: UiBarTheme) { override fun setBarColorAccordingToTheme(
theme: UiTheme,
transparent: UiBarTheme,
) {
LaunchedEffect(theme) { LaunchedEffect(theme) {
val style = when { val style =
when {
theme == UiTheme.Light -> UIStatusBarStyleLightContent theme == UiTheme.Light -> UIStatusBarStyleLightContent
else -> UIStatusBarStyleDarkContent else -> UIStatusBarStyleDarkContent
} }

View File

@ -6,14 +6,14 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.materialkolor.dynamicColorScheme import com.materialkolor.dynamicColorScheme
internal class DefaultColorSchemeProvider : ColorSchemeProvider { internal class DefaultColorSchemeProvider : ColorSchemeProvider {
override val supportsDynamicColors = false override val supportsDynamicColors = false
override fun getColorScheme( override fun getColorScheme(
theme: UiTheme, theme: UiTheme,
dynamic: Boolean, dynamic: Boolean,
customSeed: Color?, customSeed: Color?,
): ColorScheme = when (theme) { ): ColorScheme =
when (theme) {
UiTheme.Dark -> { UiTheme.Dark -> {
if (customSeed != null) { if (customSeed != null) {
dynamicColorScheme(customSeed, true) dynamicColorScheme(customSeed, true)

View File

@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.update
abstract class DefaultMviModel<Intent, State, Effect>( abstract class DefaultMviModel<Intent, State, Effect>(
initialState: State, initialState: State,
) : MviModel<Intent, State, Effect> { ) : MviModel<Intent, State, Effect> {
override val uiState = MutableStateFlow(initialState) override val uiState = MutableStateFlow(initialState)
override val effects = MutableSharedFlow<Effect>() override val effects = MutableSharedFlow<Effect>()

View File

@ -7,7 +7,6 @@ import kotlinx.coroutines.flow.StateFlow
* Model contract for Model-View-Intent architecture. * Model contract for Model-View-Intent architecture.
*/ */
interface MviModel<Intent, State, Effect> { interface MviModel<Intent, State, Effect> {
/** /**
* Representation of the state holder's state for the view to consume. * Representation of the state holder's state for the view to consume.
*/ */

View File

@ -39,12 +39,18 @@ actual fun CustomWebView(
modifier = modifier, modifier = modifier,
factory = { context -> factory = { context ->
WebView(context).apply { WebView(context).apply {
layoutParams = ViewGroup.LayoutParams( layoutParams =
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
) )
webViewClient = object : WebViewClient() { webViewClient =
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) { object : WebViewClient() {
override fun onPageStarted(
view: WebView,
url: String?,
favicon: Bitmap?,
) {
navigator.canGoBack = view.canGoBack() navigator.canGoBack = view.canGoBack()
} }
} }
@ -52,7 +58,8 @@ actual fun CustomWebView(
setOnScrollChangeListener { _, scrollX, scrollY, oldScrollX, oldScrollY -> setOnScrollChangeListener { _, scrollX, scrollY, oldScrollX, oldScrollY ->
scrollConnection?.onPreScroll( scrollConnection?.onPreScroll(
available = Offset( available =
Offset(
x = (oldScrollX - scrollX) / density, x = (oldScrollX - scrollX) / density,
y = (oldScrollY - scrollY) / density, y = (oldScrollY - scrollY) / density,
), ),

View File

@ -29,16 +29,19 @@ actual fun VideoPlayer(
onPlaybackStarted: (() -> Unit)?, onPlaybackStarted: (() -> Unit)?,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val exoPlayer = remember { val exoPlayer =
remember {
ExoPlayer.Builder(context) ExoPlayer.Builder(context)
.build() .build()
.apply { .apply {
val defaultDataSourceFactory = DefaultDataSource.Factory(context) val defaultDataSourceFactory = DefaultDataSource.Factory(context)
val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory( val dataSourceFactory: DataSource.Factory =
DefaultDataSource.Factory(
context, context,
defaultDataSourceFactory, defaultDataSourceFactory,
) )
val source = ProgressiveMediaSource.Factory(dataSourceFactory) val source =
ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(url)) .createMediaSource(MediaItem.fromUri(url))
setMediaSource(source) setMediaSource(source)

View File

@ -31,7 +31,8 @@ fun BottomSheetHeader(
modifier = Modifier.padding(bottom = Spacing.xs), modifier = Modifier.padding(bottom = Spacing.xs),
) )
Text( Text(
modifier = Modifier.padding( modifier =
Modifier.padding(
top = Spacing.xs, top = Spacing.xs,
bottom = Spacing.xs, bottom = Spacing.xs,
), ),
@ -44,11 +45,10 @@ fun BottomSheetHeader(
} }
@Composable @Composable
private fun BottomSheetHandle( private fun BottomSheetHandle(modifier: Modifier = Modifier) {
modifier: Modifier = Modifier,
) {
Box( Box(
modifier = modifier.width(60.dp) modifier =
modifier.width(60.dp)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
bottom = Spacing.xxxs, bottom = Spacing.xxxs,

View File

@ -18,7 +18,8 @@ fun CustomizedContent(
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
val fontScale by themeRepository.contentFontScale.collectAsState() val fontScale by themeRepository.contentFontScale.collectAsState()
val uiFontScale by themeRepository.uiFontScale.collectAsState() val uiFontScale by themeRepository.uiFontScale.collectAsState()
val scaleFactor = when (contentClass) { val scaleFactor =
when (contentClass) {
ContentFontClass.Title -> fontScale.title ContentFontClass.Title -> fontScale.title
ContentFontClass.Body -> fontScale.body ContentFontClass.Body -> fontScale.body
ContentFontClass.Comment -> fontScale.comment ContentFontClass.Comment -> fontScale.comment
@ -26,7 +27,8 @@ fun CustomizedContent(
} * uiFontScale } * uiFontScale
CompositionLocalProvider( CompositionLocalProvider(
LocalDensity provides Density( LocalDensity provides
Density(
density = LocalDensity.current.density, density = LocalDensity.current.density,
fontScale = scaleFactor, fontScale = scaleFactor,
), ),

View File

@ -32,6 +32,7 @@ import kotlin.math.roundToInt
private sealed interface SlideAnchorPosition { private sealed interface SlideAnchorPosition {
data object Opened : SlideAnchorPosition data object Opened : SlideAnchorPosition
data object Closed : SlideAnchorPosition data object Closed : SlideAnchorPosition
} }
@ -46,10 +47,12 @@ fun DraggableSideMenu(
) { ) {
val density = LocalDensity.current val density = LocalDensity.current
val maxWidth = if (availableWidth.isSpecified) availableWidth * 0.85f else 500.dp val maxWidth = if (availableWidth.isSpecified) availableWidth * 0.85f else 500.dp
val draggableState = remember(availableWidth) { val draggableState =
remember(availableWidth) {
AnchoredDraggableState( AnchoredDraggableState(
initialValue = SlideAnchorPosition.Closed, initialValue = SlideAnchorPosition.Closed,
anchors = DraggableAnchors<SlideAnchorPosition> { anchors =
DraggableAnchors<SlideAnchorPosition> {
SlideAnchorPosition.Closed at with(density) { availableWidth.toPx() } SlideAnchorPosition.Closed at with(density) { availableWidth.toPx() }
SlideAnchorPosition.Opened at with(density) { (availableWidth - maxWidth).toPx() } SlideAnchorPosition.Opened at with(density) { (availableWidth - maxWidth).toPx() }
}, },
@ -60,7 +63,8 @@ fun DraggableSideMenu(
} }
LaunchedEffect(opened) { LaunchedEffect(opened) {
val target = if (opened) { val target =
if (opened) {
SlideAnchorPosition.Opened SlideAnchorPosition.Opened
} else { } else {
SlideAnchorPosition.Closed SlideAnchorPosition.Closed
@ -77,7 +81,8 @@ fun DraggableSideMenu(
} }
Box( Box(
modifier = modifier modifier =
modifier
.width(maxWidth) .width(maxWidth)
.fillMaxHeight() .fillMaxHeight()
.offset { .offset {

View File

@ -32,7 +32,8 @@ fun FeedbackButton(
animationSpec = spring(stiffness = StiffnessMediumLow), animationSpec = spring(stiffness = StiffnessMediumLow),
) )
Image( Image(
modifier = modifier modifier =
modifier
.scale(scale) .scale(scale)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
@ -48,7 +49,8 @@ fun FeedbackButton(
}, },
imageVector = imageVector, imageVector = imageVector,
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint( colorFilter =
ColorFilter.tint(
color = tintColor, color = tintColor,
), ),
) )

View File

@ -63,25 +63,29 @@ fun FloatingActionButtonMenu(
val dynamicColors by themeRepository.dynamicColors.collectAsState() val dynamicColors by themeRepository.dynamicColors.collectAsState()
var fabExpanded by remember { mutableStateOf(false) } var fabExpanded by remember { mutableStateOf(false) }
val fabRotation by animateFloatAsState(if (fabExpanded) 45f else 0f) val fabRotation by animateFloatAsState(if (fabExpanded) 45f else 0f)
val enterTransition = remember { val enterTransition =
remember {
fadeIn( fadeIn(
initialAlpha = 0.3f, initialAlpha = 0.3f,
animationSpec = tween(ANIMATION_DURATION, easing = FastOutSlowInEasing), animationSpec = tween(ANIMATION_DURATION, easing = FastOutSlowInEasing),
) )
} }
val exitTransition = remember { val exitTransition =
remember {
fadeOut( fadeOut(
animationSpec = tween(ANIMATION_DURATION, easing = FastOutSlowInEasing), animationSpec = tween(ANIMATION_DURATION, easing = FastOutSlowInEasing),
) )
} }
val numberOfItems by animateIntAsState( val numberOfItems by animateIntAsState(
targetValue = if (fabExpanded) items.size else 0, targetValue = if (fabExpanded) items.size else 0,
animationSpec = tween( animationSpec =
tween(
durationMillis = ANIMATION_DURATION * items.size, durationMillis = ANIMATION_DURATION * items.size,
easing = LinearEasing, easing = LinearEasing,
), ),
) )
val indices: List<Int> = if (numberOfItems == 0) { val indices: List<Int> =
if (numberOfItems == 0) {
emptyList() emptyList()
} else { } else {
buildList { buildList {
@ -107,7 +111,8 @@ fun FloatingActionButtonMenu(
exit = exitTransition, exit = exitTransition,
) { ) {
Row( Row(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
onClick = { onClick = {
fabExpanded = false fabExpanded = false
item.onSelected?.invoke() item.onSelected?.invoke()
@ -117,7 +122,8 @@ fun FloatingActionButtonMenu(
horizontalArrangement = Arrangement.spacedBy(Spacing.xxs), horizontalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Text( Text(
modifier = Modifier modifier =
Modifier
.padding(horizontal = Spacing.xs) .padding(horizontal = Spacing.xs)
.background( .background(
color = MaterialTheme.colorScheme.surfaceVariant, color = MaterialTheme.colorScheme.surfaceVariant,
@ -131,7 +137,8 @@ fun FloatingActionButtonMenu(
color = MaterialTheme.colorScheme.onBackground, color = MaterialTheme.colorScheme.onBackground,
) )
Icon( Icon(
modifier = Modifier modifier =
Modifier
.size(IconSize.m) .size(IconSize.m)
.background( .background(
color = MaterialTheme.colorScheme.primaryContainer, color = MaterialTheme.colorScheme.primaryContainer,
@ -147,8 +154,10 @@ fun FloatingActionButtonMenu(
Spacer(modifier = Modifier.height(Spacing.xxs)) Spacer(modifier = Modifier.height(Spacing.xxs))
} }
val fabContainerColor = when (theme) { val fabContainerColor =
UiTheme.Black -> schemeProvider.getColorScheme( when (theme) {
UiTheme.Black ->
schemeProvider.getColorScheme(
theme = UiTheme.Dark, theme = UiTheme.Dark,
dynamic = dynamicColors, dynamic = dynamicColors,
customSeed = seedColor, customSeed = seedColor,

View File

@ -23,7 +23,8 @@ fun PlaceholderImage(
title: String, title: String,
) { ) {
Box( Box(
modifier = modifier modifier =
modifier
.padding(Spacing.xxxs) .padding(Spacing.xxxs)
.size(size) .size(size)
.background( .background(
@ -34,7 +35,8 @@ fun PlaceholderImage(
) { ) {
val translationAmount = with(LocalDensity.current) { 2.dp.toPx() } val translationAmount = with(LocalDensity.current) { 2.dp.toPx() }
Text( Text(
modifier = Modifier.graphicsLayer { modifier =
Modifier.graphicsLayer {
translationY = -translationAmount translationY = -translationAmount
}, },
text = title.firstOrNull()?.toString().orEmpty().uppercase(), text = title.firstOrNull()?.toString().orEmpty().uppercase(),

View File

@ -16,7 +16,8 @@ fun ProgressHud(
color: Color = MaterialTheme.colorScheme.primary, color: Color = MaterialTheme.colorScheme.primary,
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.fillMaxSize() .fillMaxSize()
.background(overlayColor), .background(overlayColor),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,

View File

@ -23,7 +23,8 @@ fun SectionSelector(
onSectionSelected: (Int) -> Unit, onSectionSelected: (Int) -> Unit,
) { ) {
var isTowardsStart by remember { mutableStateOf(false) } var isTowardsStart by remember { mutableStateOf(false) }
val draggableState = remember { val draggableState =
remember {
DraggableState { delta -> DraggableState { delta ->
isTowardsStart = delta > 0 isTowardsStart = delta > 0
} }
@ -34,7 +35,8 @@ fun SectionSelector(
tabs = { tabs = {
titles.forEachIndexed { i, title -> titles.forEachIndexed { i, title ->
Tab( Tab(
modifier = Modifier.then( modifier =
Modifier.then(
if (draggable) { if (draggable) {
Modifier.draggable( Modifier.draggable(
state = draggableState, state = draggableState,

View File

@ -52,8 +52,10 @@ fun SwipeActionCard(
var secondNotified by remember { mutableStateOf(false) } var secondNotified by remember { mutableStateOf(false) }
val gestureBeginCallback by rememberUpdatedState(onGestureBegin) val gestureBeginCallback by rememberUpdatedState(onGestureBegin)
var lastProgress by remember { mutableStateOf(0.0f) } var lastProgress by remember { mutableStateOf(0.0f) }
val dismissState = rememberNoFlingSwipeToDismissBoxState( val dismissState =
confirmValueChange = rememberCallbackArgs { value -> rememberNoFlingSwipeToDismissBoxState(
confirmValueChange =
rememberCallbackArgs { value ->
when (value) { when (value) {
SwipeToDismissBoxValue.StartToEnd -> { SwipeToDismissBoxValue.StartToEnd -> {
val enableSecondAction = swipeToEndActions.size > 1 val enableSecondAction = swipeToEndActions.size > 1
@ -83,7 +85,8 @@ fun SwipeActionCard(
) )
LaunchedEffect(dismissState, swipeToEndActions, swipeToEndActions) { LaunchedEffect(dismissState, swipeToEndActions, swipeToEndActions) {
snapshotFlow { dismissState.progress }.onEach { progress -> snapshotFlow { dismissState.progress }.onEach { progress ->
val enableSecondAction = when (dismissState.targetValue) { val enableSecondAction =
when (dismissState.targetValue) {
SwipeToDismissBoxValue.Settled -> false SwipeToDismissBoxValue.Settled -> false
SwipeToDismissBoxValue.StartToEnd -> swipeToEndActions.size > 1 SwipeToDismissBoxValue.StartToEnd -> swipeToEndActions.size > 1
SwipeToDismissBoxValue.EndToStart -> swipeToStartActions.size > 1 SwipeToDismissBoxValue.EndToStart -> swipeToStartActions.size > 1
@ -120,14 +123,16 @@ fun SwipeActionCard(
enableDismissFromEndToStart = swipeToStartActions.isNotEmpty(), enableDismissFromEndToStart = swipeToStartActions.isNotEmpty(),
backgroundContent = { backgroundContent = {
val direction = dismissState.dismissDirection val direction = dismissState.dismissDirection
val actions = when (dismissState.targetValue) { val actions =
when (dismissState.targetValue) {
SwipeToDismissBoxValue.Settled -> listOf() SwipeToDismissBoxValue.Settled -> listOf()
SwipeToDismissBoxValue.StartToEnd -> swipeToEndActions SwipeToDismissBoxValue.StartToEnd -> swipeToEndActions
SwipeToDismissBoxValue.EndToStart -> swipeToStartActions SwipeToDismissBoxValue.EndToStart -> swipeToStartActions
} }
val enableSecondAction = actions.size > 1 val enableSecondAction = actions.size > 1
val bgColor by animateColorAsState( val bgColor by animateColorAsState(
targetValue = if ( targetValue =
if (
dismissState.progress < SECOND_ACTION_THRESHOLD || dismissState.progress < SECOND_ACTION_THRESHOLD ||
dismissState.targetValue == SwipeToDismissBoxValue.Settled || dismissState.targetValue == SwipeToDismissBoxValue.Settled ||
!enableSecondAction !enableSecondAction
@ -137,7 +142,8 @@ fun SwipeActionCard(
actions.getOrNull(1)?.backgroundColor ?: Color.Transparent actions.getOrNull(1)?.backgroundColor ?: Color.Transparent
}, },
) )
val alignment = when (direction) { val alignment =
when (direction) {
SwipeToDismissBoxValue.StartToEnd -> Alignment.CenterStart SwipeToDismissBoxValue.StartToEnd -> Alignment.CenterStart
else -> Alignment.CenterEnd else -> Alignment.CenterEnd
} }
@ -180,7 +186,8 @@ private fun rememberNoFlingSwipeToDismissBoxState(
// instead of LocalDensity.current we use a value that makes velocityThreshold to skyrocket // instead of LocalDensity.current we use a value that makes velocityThreshold to skyrocket
val density = Density(Float.POSITIVE_INFINITY) val density = Density(Float.POSITIVE_INFINITY)
return rememberSaveable( return rememberSaveable(
saver = SwipeToDismissBoxState.Saver( saver =
SwipeToDismissBoxState.Saver(
confirmValueChange = confirmValueChange, confirmValueChange = confirmValueChange,
density = density, density = density,
positionalThreshold = positionalThreshold, positionalThreshold = positionalThreshold,

View File

@ -58,14 +58,16 @@ fun ZoomableImage(
} }
BoxWithConstraints( BoxWithConstraints(
modifier = modifier modifier =
modifier
.fillMaxSize() .fillMaxSize()
.background(Color.Black), .background(Color.Black),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
AnimatedVisibility(visible = visible) { AnimatedVisibility(visible = visible) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.onClick( .onClick(
onDoubleClick = { onDoubleClick = {
if (scale > 1f) { if (scale > 1f) {
@ -86,7 +88,8 @@ fun ZoomableImage(
scale = (scale * gestureZoom).coerceIn(1f, 16f) scale = (scale * gestureZoom).coerceIn(1f, 16f)
offset = if (scale > 1) { offset =
if (scale > 1) {
Offset( Offset(
x = (offset.x + pan.x * scale).coerceIn(-maxX, maxX), x = (offset.x + pan.x * scale).coerceIn(-maxX, maxX),
y = (offset.y + pan.y * scale).coerceIn(-maxY, maxY), y = (offset.y + pan.y * scale).coerceIn(-maxY, maxY),
@ -116,14 +119,16 @@ fun ZoomableImage(
) )
}, },
onLoading = { progress -> onLoading = { progress ->
val prog = if (progress != null) { val prog =
if (progress != null) {
progress progress
} else { } else {
val transition = rememberInfiniteTransition() val transition = rememberInfiniteTransition()
val res by transition.animateFloat( val res by transition.animateFloat(
initialValue = 0f, initialValue = 0f,
targetValue = 1f, targetValue = 1f,
animationSpec = InfiniteRepeatableSpec( animationSpec =
InfiniteRepeatableSpec(
animation = tween(LOADING_ANIMATION_DURATION), animation = tween(LOADING_ANIMATION_DURATION),
), ),
) )

View File

@ -42,7 +42,8 @@ actual fun CustomImage(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
if (shouldBeRendered) { if (shouldBeRendered) {
val painterResource = asyncPainterResource( val painterResource =
asyncPainterResource(
data = url, data = url,
filterQuality = quality, filterQuality = quality,
) )

View File

@ -50,7 +50,8 @@ actual fun CustomWebView(
UIKitView( UIKitView(
factory = { factory = {
val config = WKWebViewConfiguration().apply { val config =
WKWebViewConfiguration().apply {
allowsInlineMediaPlayback = true allowsInlineMediaPlayback = true
} }
WKWebView( WKWebView(
@ -59,7 +60,8 @@ actual fun CustomWebView(
).apply { ).apply {
userInteractionEnabled = true userInteractionEnabled = true
allowsBackForwardNavigationGestures = true allowsBackForwardNavigationGestures = true
val navigationDelegate = object : NSObject(), WKNavigationDelegateProtocol { val navigationDelegate =
object : NSObject(), WKNavigationDelegateProtocol {
override fun webView( override fun webView(
webView: WKWebView, webView: WKWebView,
didFinishNavigation: WKNavigation?, didFinishNavigation: WKNavigation?,
@ -68,7 +70,8 @@ actual fun CustomWebView(
} }
} }
this.navigationDelegate = navigationDelegate this.navigationDelegate = navigationDelegate
this.scrollView.delegate = object : NSObject(), UIScrollViewDelegateProtocol { this.scrollView.delegate =
object : NSObject(), UIScrollViewDelegateProtocol {
override fun scrollViewDidScroll(scrollView: UIScrollView) { override fun scrollViewDidScroll(scrollView: UIScrollView) {
scrollView.contentOffset.useContents { scrollView.contentOffset.useContents {
val offsetX = (lastOffsetX - x).toFloat() / density val offsetX = (lastOffsetX - x).toFloat() / density

View File

@ -31,7 +31,6 @@ class DefaultDetailOpener(
private val identityRepository: IdentityRepository, private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository, private val communityRepository: CommunityRepository,
) : DetailOpener { ) : DetailOpener {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
override fun openCommunityDetail( override fun openCommunityDetail(
@ -39,7 +38,8 @@ class DefaultDetailOpener(
otherInstance: String, otherInstance: String,
) { ) {
scope.launch { scope.launch {
val (actualCommunity, actualInstance) = withContext(Dispatchers.IO) { val (actualCommunity, actualInstance) =
run {
val defaultResult = community to otherInstance val defaultResult = community to otherInstance
if (otherInstance.isNotEmpty()) { if (otherInstance.isNotEmpty()) {
val found = searchCommunity(name = community.name, host = otherInstance) val found = searchCommunity(name = community.name, host = otherInstance)
@ -52,9 +52,7 @@ class DefaultDetailOpener(
defaultResult defaultResult
} }
} }
withContext(Dispatchers.IO) {
itemCache.putCommunity(actualCommunity) itemCache.putCommunity(actualCommunity)
}
navigationCoordinator.pushScreen( navigationCoordinator.pushScreen(
CommunityDetailScreen( CommunityDetailScreen(
communityId = actualCommunity.id, communityId = actualCommunity.id,
@ -64,7 +62,10 @@ class DefaultDetailOpener(
} }
} }
override fun openUserDetail(user: UserModel, otherInstance: String) { override fun openUserDetail(
user: UserModel,
otherInstance: String,
) {
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
itemCache.putUser(user) itemCache.putUser(user)
@ -118,7 +119,8 @@ class DefaultDetailOpener(
itemCache.putComment(editedComment) itemCache.putComment(editedComment)
} }
} }
val screen = CreateCommentScreen( val screen =
CreateCommentScreen(
draftId = draftId, draftId = draftId,
originalPostId = originalPost?.id, originalPostId = originalPost?.id,
originalCommentId = originalComment?.id, originalCommentId = originalComment?.id,
@ -149,7 +151,8 @@ class DefaultDetailOpener(
itemCache.putPost(crossPost) itemCache.putPost(crossPost)
} }
} }
val screen = CreatePostScreen( val screen =
CreatePostScreen(
draftId = draftId, draftId = draftId,
editedPostId = editedPost?.id, editedPostId = editedPost?.id,
crossPostId = crossPost?.id, crossPostId = crossPost?.id,
@ -164,11 +167,15 @@ class DefaultDetailOpener(
} }
} }
private suspend fun searchCommunity(name: String, host: String): CommunityModel? { private suspend fun searchCommunity(
name: String,
host: String,
): CommunityModel? {
val auth = identityRepository.authToken.value val auth = identityRepository.authToken.value
tailrec suspend fun searchRec(page: Int = 0): CommunityModel? { tailrec suspend fun searchRec(page: Int = 0): CommunityModel? {
val results = communityRepository.search( val results =
communityRepository.search(
auth = auth, auth = auth,
query = name, query = name,
resultType = SearchResultType.Communities, resultType = SearchResultType.Communities,
@ -176,7 +183,8 @@ class DefaultDetailOpener(
limit = 50, limit = 50,
).filterIsInstance<SearchResult.Community>() ).filterIsInstance<SearchResult.Community>()
val found = results.firstOrNull { val found =
results.firstOrNull {
it.model.name == name && it.model.host == host it.model.name == name && it.model.host == host
}?.model }?.model
// iterates for no more than a number of pages before giving up // iterates for no more than a number of pages before giving up

View File

@ -5,19 +5,23 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface BlockActionType { sealed interface BlockActionType {
data object User : BlockActionType data object User : BlockActionType
data object Community : BlockActionType data object Community : BlockActionType
data object Instance : BlockActionType data object Instance : BlockActionType
} }
fun Int.toBlockActionType(): BlockActionType = when (this) { fun Int.toBlockActionType(): BlockActionType =
when (this) {
2 -> BlockActionType.Instance 2 -> BlockActionType.Instance
1 -> BlockActionType.Community 1 -> BlockActionType.Community
else -> BlockActionType.User else -> BlockActionType.User
} }
@Composable @Composable
fun BlockActionType.toReadableName(): String = when (this) { fun BlockActionType.toReadableName(): String =
when (this) {
BlockActionType.Community -> LocalXmlStrings.current.blockActionCommunity BlockActionType.Community -> LocalXmlStrings.current.blockActionCommunity
BlockActionType.Instance -> LocalXmlStrings.current.communityDetailBlockInstance BlockActionType.Instance -> LocalXmlStrings.current.communityDetailBlockInstance
BlockActionType.User -> LocalXmlStrings.current.blockActionUser BlockActionType.User -> LocalXmlStrings.current.blockActionUser
} }

View File

@ -53,22 +53,26 @@ fun CollapsedCommentCard(
val commentBarTheme by themeRepository.commentBarTheme.collectAsState() val commentBarTheme by themeRepository.commentBarTheme.collectAsState()
var commentHeight by remember { mutableStateOf(0f) } var commentHeight by remember { mutableStateOf(0f) }
val barWidth = 2.dp val barWidth = 2.dp
val barColor = themeRepository.getCommentBarColor( val barColor =
themeRepository.getCommentBarColor(
depth = comment.depth, depth = comment.depth,
commentBarTheme = commentBarTheme, commentBarTheme = commentBarTheme,
) )
Column( Column(
modifier = modifier.onClick( modifier =
modifier.onClick(
onClick = onClick ?: {}, onClick = onClick ?: {},
), ),
) { ) {
Box( Box(
modifier = Modifier.padding( modifier =
Modifier.padding(
start = (INDENT_AMOUNT * comment.depth).dp, start = (INDENT_AMOUNT * comment.depth).dp,
), ),
) { ) {
Column( Column(
modifier = Modifier modifier =
Modifier
.padding(start = barWidth) .padding(start = barWidth)
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
@ -116,7 +120,8 @@ fun CollapsedCommentCard(
} }
if (comment.depth > 0) { if (comment.depth > 0) {
Box( Box(
modifier = Modifier modifier =
Modifier
.padding(top = Spacing.xxs) .padding(top = Spacing.xxs)
.width(barWidth) .width(barWidth)
.height(commentHeight.toLocalDp()) .height(commentHeight.toLocalDp())

View File

@ -77,7 +77,8 @@ fun CommentCard(
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
var commentHeight by remember { mutableStateOf(0f) } var commentHeight by remember { mutableStateOf(0f) }
val commentBarTheme by themeRepository.commentBarTheme.collectAsState() val commentBarTheme by themeRepository.commentBarTheme.collectAsState()
val barColor = themeRepository.getCommentBarColor( val barColor =
themeRepository.getCommentBarColor(
depth = comment.depth, depth = comment.depth,
commentBarTheme = commentBarTheme, commentBarTheme = commentBarTheme,
) )
@ -87,17 +88,20 @@ fun CommentCard(
modifier = modifier, modifier = modifier,
) { ) {
Box( Box(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
onClick = onClick ?: {}, onClick = onClick ?: {},
onDoubleClick = onDoubleClick ?: {}, onDoubleClick = onDoubleClick ?: {},
).padding( ).padding(
start = indentAmount.takeIf { it > 0 }?.let { start =
indentAmount.takeIf { it > 0 }?.let {
(it * comment.depth).dp + Spacing.xxxs (it * comment.depth).dp + Spacing.xxxs
} ?: 0.dp, } ?: 0.dp,
), ),
) { ) {
Column( Column(
modifier = Modifier modifier =
Modifier
.padding(start = barWidth + Spacing.xxs) .padding(start = barWidth + Spacing.xxs)
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
@ -119,10 +123,12 @@ fun CommentCard(
distinguished = comment.distinguished, distinguished = comment.distinguished,
isOp = isOp, isOp = isOp,
isBot = comment.creator?.bot.takeIf { showBot } ?: false, isBot = comment.creator?.bot.takeIf { showBot } ?: false,
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator =
rememberCallbackArgs { user ->
onOpenCreator?.invoke(user, "") onOpenCreator?.invoke(user, "")
}, },
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity =
rememberCallbackArgs { community ->
onOpenCommunity?.invoke(community, "") onOpenCommunity?.invoke(community, "")
}, },
onToggleExpanded = onToggleExpanded, onToggleExpanded = onToggleExpanded,
@ -136,7 +142,8 @@ fun CommentCard(
} else { } else {
CustomizedContent(ContentFontClass.Body) { CustomizedContent(ContentFontClass.Body) {
CompositionLocalProvider( CompositionLocalProvider(
LocalDensity provides Density( LocalDensity provides
Density(
density = LocalDensity.current.density, density = LocalDensity.current.density,
// additional downscale for font in comments // additional downscale for font in comments
fontScale = LocalDensity.current.fontScale * COMMENT_TEXT_SCALE_FACTOR, fontScale = LocalDensity.current.fontScale * COMMENT_TEXT_SCALE_FACTOR,
@ -180,7 +187,8 @@ fun CommentCard(
} }
if (indentAmount > 0 && comment.depth > 0) { if (indentAmount > 0 && comment.depth > 0) {
Box( Box(
modifier = Modifier modifier =
Modifier
.padding(top = Spacing.xxs) .padding(top = Spacing.xxs)
.width(barWidth) .width(barWidth)
.height(commentHeight.toLocalDp()) .height(commentHeight.toLocalDp())

View File

@ -37,7 +37,8 @@ fun CommentCardPlaceholder(
horizontalArrangement = Arrangement.spacedBy(Spacing.s), horizontalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
Box( Box(
modifier = Modifier.size(IconSize.s) modifier =
Modifier.size(IconSize.s)
.clip(CircleShape) .clip(CircleShape)
.shimmerEffect(), .shimmerEffect(),
) )
@ -46,13 +47,15 @@ fun CommentCardPlaceholder(
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth(0.5f) .fillMaxWidth(0.5f)
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
@ -61,14 +64,16 @@ fun CommentCardPlaceholder(
} }
} }
Box( Box(
modifier = Modifier modifier =
Modifier
.height(80.dp) .height(80.dp)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))

View File

@ -81,7 +81,8 @@ fun CommunityAndCreatorInfo(
if (communityIcon.isNotEmpty()) { if (communityIcon.isNotEmpty()) {
if (autoLoadImages) { if (autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.onClick( .onClick(
onClick = { onClick = {
if (community != null) { if (community != null) {
@ -99,7 +100,8 @@ fun CommunityAndCreatorInfo(
) )
} else { } else {
PlaceholderImage( PlaceholderImage(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
onClick = { onClick = {
if (community != null) { if (community != null) {
onOpenCommunity?.invoke(community) onOpenCommunity?.invoke(community)
@ -114,7 +116,8 @@ fun CommunityAndCreatorInfo(
} else if (creatorAvatar.isNotEmpty()) { } else if (creatorAvatar.isNotEmpty()) {
if (autoLoadImages) { if (autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.onClick( .onClick(
onClick = { onClick = {
if (creator != null) { if (creator != null) {
@ -132,7 +135,8 @@ fun CommunityAndCreatorInfo(
) )
} else { } else {
PlaceholderImage( PlaceholderImage(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
onClick = { onClick = {
if (creator != null) { if (creator != null) {
onOpenCreator?.invoke(creator) onOpenCreator?.invoke(creator)
@ -151,7 +155,8 @@ fun CommunityAndCreatorInfo(
if (community != null) { if (community != null) {
CustomizedContent(ContentFontClass.AncillaryText) { CustomizedContent(ContentFontClass.AncillaryText) {
Text( Text(
modifier = Modifier modifier =
Modifier
.onClick( .onClick(
onClick = { onClick = {
onOpenCommunity?.invoke(community) onOpenCommunity?.invoke(community)
@ -168,7 +173,8 @@ fun CommunityAndCreatorInfo(
if (creator != null) { if (creator != null) {
CustomizedContent(ContentFontClass.AncillaryText) { CustomizedContent(ContentFontClass.AncillaryText) {
Text( Text(
modifier = Modifier modifier =
Modifier
.onClick( .onClick(
onClick = { onClick = {
onOpenCreator?.invoke(creator) onOpenCreator?.invoke(creator)
@ -234,7 +240,8 @@ fun CommunityAndCreatorInfo(
) )
} }
if (indicatorExpanded != null) { if (indicatorExpanded != null) {
val expandedModifier = Modifier val expandedModifier =
Modifier
.padding(end = Spacing.xs) .padding(end = Spacing.xs)
.onClick( .onClick(
onClick = { onClick = {

View File

@ -67,11 +67,14 @@ fun CommunityHeader(
contentDescription = null, contentDescription = null,
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.fillMaxSize() .fillMaxSize()
.background( .background(
brush = Brush.horizontalGradient( brush =
colors = listOf( Brush.horizontalGradient(
colors =
listOf(
MaterialTheme.colorScheme.background.copy(alpha = 0.95f), MaterialTheme.colorScheme.background.copy(alpha = 0.95f),
Color.Transparent, Color.Transparent,
MaterialTheme.colorScheme.background.copy(alpha = 0.75f), MaterialTheme.colorScheme.background.copy(alpha = 0.75f),
@ -92,7 +95,8 @@ fun CommunityHeader(
// avatar // avatar
if (communityIcon.isNotEmpty() && autoLoadImages) { if (communityIcon.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.padding(Spacing.xxxs) .padding(Spacing.xxxs)
.size(IconSize.xxl) .size(IconSize.xxl)
.clip(RoundedCornerShape(IconSize.xxl / 2)) .clip(RoundedCornerShape(IconSize.xxl / 2))
@ -144,7 +148,8 @@ fun CommunityHeader(
contentDescription = null, contentDescription = null,
) )
Text( Text(
text = community.subscribers.getPrettyNumber( text =
community.subscribers.getPrettyNumber(
thousandLabel = LocalXmlStrings.current.profileThousandShort, thousandLabel = LocalXmlStrings.current.profileThousandShort,
millionLabel = LocalXmlStrings.current.profileMillionShort, millionLabel = LocalXmlStrings.current.profileMillionShort,
), ),
@ -159,7 +164,8 @@ fun CommunityHeader(
contentDescription = null, contentDescription = null,
) )
Text( Text(
text = community.monthlyActiveUsers.getPrettyNumber( text =
community.monthlyActiveUsers.getPrettyNumber(
thousandLabel = LocalXmlStrings.current.profileThousandShort, thousandLabel = LocalXmlStrings.current.profileThousandShort,
millionLabel = LocalXmlStrings.current.profileMillionShort, millionLabel = LocalXmlStrings.current.profileMillionShort,
), ),
@ -172,7 +178,8 @@ fun CommunityHeader(
if (onInfo != null) { if (onInfo != null) {
Icon( Icon(
modifier = Modifier modifier =
Modifier
.padding(end = Spacing.s) .padding(end = Spacing.s)
.size(iconSize) .size(iconSize)
.onClick(onClick = onInfo), .onClick(onClick = onInfo),

View File

@ -69,7 +69,8 @@ fun CommunityItem(
var optionsMenuOpen by remember { mutableStateOf(false) } var optionsMenuOpen by remember { mutableStateOf(false) }
Row( Row(
modifier = modifier.then( modifier =
modifier.then(
if (noPadding) { if (noPadding) {
Modifier Modifier
} else { } else {
@ -81,7 +82,8 @@ fun CommunityItem(
) { ) {
if (communityIcon.isNotEmpty() && autoLoadImages) { if (communityIcon.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.padding(Spacing.xxxs) .padding(Spacing.xxxs)
.size(iconSize) .size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)), .clip(RoundedCornerShape(iconSize / 2)),
@ -98,7 +100,8 @@ fun CommunityItem(
modifier = Modifier.weight(1f).padding(start = Spacing.xs), modifier = Modifier.weight(1f).padding(start = Spacing.xs),
) { ) {
Text( Text(
text = buildString { text =
buildString {
append(title) append(title)
}, },
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
@ -107,7 +110,8 @@ fun CommunityItem(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
Text( Text(
text = buildString { text =
buildString {
append("!") append("!")
append(communityHandle) append(communityHandle)
}, },
@ -147,12 +151,14 @@ fun CommunityItem(
showSubscribeButton -> { showSubscribeButton -> {
Icon( Icon(
modifier = Modifier modifier =
Modifier
.size(IconSize.m) .size(IconSize.m)
.onClick( .onClick(
onClick = { onSubscribe?.invoke() }, onClick = { onSubscribe?.invoke() },
), ),
imageVector = when (community.subscribed) { imageVector =
when (community.subscribed) {
true -> { true -> {
Icons.Outlined.RemoveCircleOutline Icons.Outlined.RemoveCircleOutline
} }
@ -174,7 +180,8 @@ fun CommunityItem(
if (options.isNotEmpty()) { if (options.isNotEmpty()) {
Box { Box {
Icon( Icon(
modifier = Modifier.size(IconSize.m) modifier =
Modifier.size(IconSize.m)
.padding(Spacing.xs) .padding(Spacing.xs)
.onGloballyPositioned { .onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
@ -194,7 +201,8 @@ fun CommunityItem(
onDismiss = { onDismiss = {
optionsMenuOpen = false optionsMenuOpen = false
}, },
offset = DpOffset( offset =
DpOffset(
x = optionsOffset.x.toLocalDp(), x = optionsOffset.x.toLocalDp(),
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),

View File

@ -23,7 +23,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.shimmerEffect
@Composable @Composable
fun CommunityItemPlaceholder() { fun CommunityItemPlaceholder() {
Row( Row(
modifier = Modifier.padding( modifier =
Modifier.padding(
vertical = Spacing.xs, vertical = Spacing.xs,
horizontal = Spacing.s, horizontal = Spacing.s,
), ),
@ -31,7 +32,8 @@ fun CommunityItemPlaceholder() {
horizontalArrangement = Arrangement.spacedBy(Spacing.xs), horizontalArrangement = Arrangement.spacedBy(Spacing.xs),
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.padding(Spacing.xxxs) .padding(Spacing.xxxs)
.size(IconSize.l) .size(IconSize.l)
.clip(CircleShape) .clip(CircleShape)
@ -42,14 +44,16 @@ fun CommunityItemPlaceholder() {
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.height(40.dp) .height(40.dp)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(20.dp) .height(20.dp)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))

View File

@ -2,5 +2,6 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui
sealed interface CreatePostSection { sealed interface CreatePostSection {
data object Edit : CreatePostSection data object Edit : CreatePostSection
data object Preview : CreatePostSection data object Preview : CreatePostSection
} }

View File

@ -31,7 +31,8 @@ fun DetailInfoItem(
Icon(imageVector = icon, contentDescription = null) Icon(imageVector = icon, contentDescription = null)
} }
Text( Text(
text = buildAnnotatedString { text =
buildAnnotatedString {
withStyle( withStyle(
SpanStyle( SpanStyle(
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,

View File

@ -22,14 +22,18 @@ internal class DefaultFabNestedScrollConnection : FabNestedScrollConnection {
private val fabVisible = MutableStateFlow(true) private val fabVisible = MutableStateFlow(true)
private val scope = CoroutineScope(SupervisorJob()) private val scope = CoroutineScope(SupervisorJob())
override val isFabVisible: StateFlow<Boolean> override val isFabVisible: StateFlow<Boolean>
get() = fabVisible get() =
fabVisible
.stateIn( .stateIn(
scope = scope, scope = scope,
started = SharingStarted.WhileSubscribed(5_000), started = SharingStarted.WhileSubscribed(5_000),
initialValue = true, initialValue = true,
) )
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { override fun onPreScroll(
available: Offset,
source: NestedScrollSource,
): Offset {
if (available.y < -THRESHOLD) { if (available.y < -THRESHOLD) {
fabVisible.value = false fabVisible.value = false
} }

View File

@ -31,6 +31,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
sealed interface InboxCardType { sealed interface InboxCardType {
data object Mention : InboxCardType data object Mention : InboxCardType
data object Reply : InboxCardType data object Reply : InboxCardType
} }
@ -54,7 +55,8 @@ fun InboxCard(
onReply: (() -> Unit)? = null, onReply: (() -> Unit)? = null,
) { ) {
Box( Box(
modifier = Modifier.then( modifier =
Modifier.then(
if (postLayout == PostLayout.Card) { if (postLayout == PostLayout.Card) {
Modifier Modifier
.padding(horizontal = Spacing.xs) .padding(horizontal = Spacing.xs)
@ -94,7 +96,8 @@ fun InboxCard(
} else { } else {
CustomizedContent(ContentFontClass.Body) { CustomizedContent(ContentFontClass.Body) {
PostCardBody( PostCardBody(
modifier = Modifier.padding( modifier =
Modifier.padding(
horizontal = Spacing.s, horizontal = Spacing.s,
), ),
// takes just the first line // takes just the first line
@ -108,7 +111,8 @@ fun InboxCard(
} }
} }
InboxReplySubtitle( InboxReplySubtitle(
modifier = Modifier.padding( modifier =
Modifier.padding(
start = Spacing.s, start = Spacing.s,
end = Spacing.s, end = Spacing.s,
top = Spacing.s, top = Spacing.s,
@ -127,7 +131,8 @@ fun InboxCard(
downVoted = mention.myVote < 0, downVoted = mention.myVote < 0,
options = options, options = options,
onOpenCommunity = onOpenCommunity, onOpenCommunity = onOpenCommunity,
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator =
rememberCallbackArgs { user ->
onOpenCreator(user) onOpenCreator(user)
}, },
onUpVote = onUpVote, onUpVote = onUpVote,

View File

@ -22,11 +22,10 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.shimmerEffect import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.shimmerEffect
@Composable @Composable
fun InboxCardPlaceholder( fun InboxCardPlaceholder(postLayout: PostLayout = PostLayout.Card) {
postLayout: PostLayout = PostLayout.Card,
) {
Column( Column(
modifier = Modifier.then( modifier =
Modifier.then(
if (postLayout == PostLayout.Card) { if (postLayout == PostLayout.Card) {
Modifier Modifier
.padding(horizontal = Spacing.xs) .padding(horizontal = Spacing.xs)
@ -43,14 +42,16 @@ fun InboxCardPlaceholder(
verticalArrangement = Arrangement.spacedBy(Spacing.xs), verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.padding(vertical = Spacing.xxxs) .padding(vertical = Spacing.xxxs)
.height(50.dp) .height(50.dp)
.fillMaxWidth() .fillMaxWidth()
@ -58,7 +59,8 @@ fun InboxCardPlaceholder(
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))

View File

@ -29,7 +29,8 @@ fun InboxCardHeader(
) { ) {
val fullColor = MaterialTheme.colorScheme.onBackground val fullColor = MaterialTheme.colorScheme.onBackground
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha) val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
val header = buildAnnotatedString { val header =
buildAnnotatedString {
withStyle(SpanStyle(fontWeight = FontWeight.Bold, color = fullColor)) { withStyle(SpanStyle(fontWeight = FontWeight.Bold, color = fullColor)) {
append(mention.creator.name) append(mention.creator.name)
} }
@ -60,7 +61,8 @@ fun InboxCardHeader(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
modifier = Modifier modifier =
Modifier
.weight(1f) .weight(1f)
.padding( .padding(
vertical = Spacing.xs, vertical = Spacing.xs,
@ -72,7 +74,8 @@ fun InboxCardHeader(
) )
if (!mention.read) { if (!mention.read) {
Icon( Icon(
modifier = Modifier modifier =
Modifier
.padding(end = Spacing.s) .padding(end = Spacing.s)
.size(IconSize.xs), .size(IconSize.xs),
imageVector = Icons.Filled.FiberManualRecord, imageVector = Icons.Filled.FiberManualRecord,

View File

@ -104,7 +104,8 @@ fun InboxReplySubtitle(
) { ) {
if (creatorName.isNotEmpty()) { if (creatorName.isNotEmpty()) {
Row( Row(
modifier = Modifier modifier =
Modifier
.weight(1f) .weight(1f)
.onClick( .onClick(
onClick = { onClick = {
@ -118,7 +119,8 @@ fun InboxReplySubtitle(
) { ) {
if (creatorAvatar.isNotEmpty() && autoLoadImages) { if (creatorAvatar.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.padding(Spacing.xxxs) .padding(Spacing.xxxs)
.size(iconSize) .size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)), .clip(RoundedCornerShape(iconSize / 2)),
@ -141,7 +143,8 @@ fun InboxReplySubtitle(
} }
if (communityName.isNotEmpty()) { if (communityName.isNotEmpty()) {
Row( Row(
modifier = Modifier modifier =
Modifier
.weight(1f) .weight(1f)
.onClick( .onClick(
onClick = { onClick = {
@ -156,7 +159,8 @@ fun InboxReplySubtitle(
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
if (communityIcon.isNotEmpty() && autoLoadImages) { if (communityIcon.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier modifier =
Modifier
.padding(Spacing.xxxs) .padding(Spacing.xxxs)
.size(iconSize) .size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)), .clip(RoundedCornerShape(iconSize / 2)),
@ -185,7 +189,8 @@ fun InboxReplySubtitle(
horizontalArrangement = Arrangement.spacedBy(Spacing.xxs), horizontalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Icon( Icon(
modifier = buttonModifier.padding( modifier =
buttonModifier.padding(
top = 3.5.dp, top = 3.5.dp,
bottom = 3.5.dp, bottom = 3.5.dp,
end = 3.5.dp, end = 3.5.dp,
@ -216,7 +221,8 @@ fun InboxReplySubtitle(
} }
if (options.isNotEmpty()) { if (options.isNotEmpty()) {
Icon( Icon(
modifier = Modifier.size(IconSize.m) modifier =
Modifier.size(IconSize.m)
.padding(Spacing.xs) .padding(Spacing.xs)
.onGloballyPositioned { .onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
@ -233,13 +239,15 @@ fun InboxReplySubtitle(
} }
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
FeedbackButton( FeedbackButton(
modifier = buttonModifier.padding( modifier =
buttonModifier.padding(
top = 2.5.dp, top = 2.5.dp,
bottom = 2.5.dp, bottom = 2.5.dp,
end = 2.5.dp, end = 2.5.dp,
), ),
imageVector = Icons.Default.ArrowCircleUp, imageVector = Icons.Default.ArrowCircleUp,
tintColor = if (upVoted) { tintColor =
if (upVoted) {
upVoteColor ?: defaultUpvoteColor upVoteColor ?: defaultUpvoteColor
} else { } else {
ancillaryColor ancillaryColor
@ -250,7 +258,8 @@ fun InboxReplySubtitle(
) )
if (showScores) { if (showScores) {
Text( Text(
text = formatToReadableValue( text =
formatToReadableValue(
voteFormat = voteFormat, voteFormat = voteFormat,
score = score, score = score,
upVotes = upVotes, upVotes = upVotes,
@ -265,13 +274,15 @@ fun InboxReplySubtitle(
) )
} }
FeedbackButton( FeedbackButton(
modifier = buttonModifier.padding( modifier =
buttonModifier.padding(
top = 2.5.dp, top = 2.5.dp,
bottom = 2.5.dp, bottom = 2.5.dp,
start = 2.5.dp, start = 2.5.dp,
), ),
imageVector = Icons.Default.ArrowCircleDown, imageVector = Icons.Default.ArrowCircleDown,
tintColor = if (downVoted) { tintColor =
if (downVoted) {
downVoteColor ?: defaultDownVoteColor downVoteColor ?: defaultDownVoteColor
} else { } else {
ancillaryColor ancillaryColor
@ -286,7 +297,8 @@ fun InboxReplySubtitle(
onDismiss = { onDismiss = {
optionsExpanded = false optionsExpanded = false
}, },
offset = DpOffset( offset =
DpOffset(
x = optionsOffset.x.toLocalDp(), x = optionsOffset.x.toLocalDp(),
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),

View File

@ -22,7 +22,8 @@ fun IndicatorChip(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Box( Box(
modifier = modifier modifier =
modifier
.border( .border(
color = MaterialTheme.colorScheme.onBackground, color = MaterialTheme.colorScheme.onBackground,
width = Dp.Hairline, width = Dp.Hairline,

View File

@ -10,33 +10,38 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings
sealed interface ModeratorZoneAction { sealed interface ModeratorZoneAction {
data object GlobalModLog : ModeratorZoneAction data object GlobalModLog : ModeratorZoneAction
data object GlobalReports : ModeratorZoneAction data object GlobalReports : ModeratorZoneAction
data object ModeratedContents : ModeratorZoneAction data object ModeratedContents : ModeratorZoneAction
} }
fun Int.toModeratorZoneAction(): ModeratorZoneAction = when (this) { fun Int.toModeratorZoneAction(): ModeratorZoneAction =
when (this) {
2 -> ModeratorZoneAction.ModeratedContents 2 -> ModeratorZoneAction.ModeratedContents
1 -> ModeratorZoneAction.GlobalReports 1 -> ModeratorZoneAction.GlobalReports
else -> ModeratorZoneAction.GlobalModLog else -> ModeratorZoneAction.GlobalModLog
} }
fun ModeratorZoneAction.toInt(): Int = when (this) { fun ModeratorZoneAction.toInt(): Int =
when (this) {
ModeratorZoneAction.GlobalModLog -> 0 ModeratorZoneAction.GlobalModLog -> 0
ModeratorZoneAction.GlobalReports -> 1 ModeratorZoneAction.GlobalReports -> 1
ModeratorZoneAction.ModeratedContents -> 2 ModeratorZoneAction.ModeratedContents -> 2
} }
@Composable @Composable
fun ModeratorZoneAction.toReadableName(): String = when (this) { fun ModeratorZoneAction.toReadableName(): String =
when (this) {
ModeratorZoneAction.GlobalModLog -> LocalXmlStrings.current.modlogTitle ModeratorZoneAction.GlobalModLog -> LocalXmlStrings.current.modlogTitle
ModeratorZoneAction.GlobalReports -> LocalXmlStrings.current.reportListTitle ModeratorZoneAction.GlobalReports -> LocalXmlStrings.current.reportListTitle
ModeratorZoneAction.ModeratedContents -> LocalXmlStrings.current.moderatorZoneActionContents ModeratorZoneAction.ModeratedContents -> LocalXmlStrings.current.moderatorZoneActionContents
} }
@Composable @Composable
fun ModeratorZoneAction.toIcon(): ImageVector = when (this) { fun ModeratorZoneAction.toIcon(): ImageVector =
when (this) {
ModeratorZoneAction.GlobalModLog -> Icons.AutoMirrored.Default.ListAlt ModeratorZoneAction.GlobalModLog -> Icons.AutoMirrored.Default.ListAlt
ModeratorZoneAction.GlobalReports -> Icons.Default.Report ModeratorZoneAction.GlobalReports -> Icons.Default.Report
ModeratorZoneAction.ModeratedContents -> Icons.Default.Shield ModeratorZoneAction.ModeratedContents -> Icons.Default.Shield
} }

View File

@ -60,7 +60,8 @@ fun MultiCommunityItem(
) { ) {
if (communityIcon.isNotEmpty() && autoLoadImages) { if (communityIcon.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier.padding(Spacing.xxxs).size(iconSize) modifier =
Modifier.padding(Spacing.xxxs).size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)), .clip(RoundedCornerShape(iconSize / 2)),
url = communityIcon, url = communityIcon,
contentScale = ContentScale.FillBounds, contentScale = ContentScale.FillBounds,
@ -77,7 +78,8 @@ fun MultiCommunityItem(
) { ) {
Text( Text(
modifier = Modifier.padding(vertical = Spacing.s), modifier = Modifier.padding(vertical = Spacing.s),
text = buildString { text =
buildString {
append(title) append(title)
}, },
color = fullColor, color = fullColor,
@ -88,7 +90,8 @@ fun MultiCommunityItem(
if (options.isNotEmpty()) { if (options.isNotEmpty()) {
Box { Box {
Icon( Icon(
modifier = Modifier.size(IconSize.m) modifier =
Modifier.size(IconSize.m)
.padding(Spacing.xs) .padding(Spacing.xs)
.onGloballyPositioned { .onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
@ -108,7 +111,8 @@ fun MultiCommunityItem(
onDismiss = { onDismiss = {
optionsMenuOpen = false optionsMenuOpen = false
}, },
offset = DpOffset( offset =
DpOffset(
x = optionsOffset.x.toLocalDp(), x = optionsOffset.x.toLocalDp(),
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),

View File

@ -7,32 +7,60 @@ data class Option(
sealed class OptionId(val value: Int) { sealed class OptionId(val value: Int) {
data object Share : OptionId(0) data object Share : OptionId(0)
data object Hide : OptionId(1) data object Hide : OptionId(1)
data object SeeRaw : OptionId(2) data object SeeRaw : OptionId(2)
data object CrossPost : OptionId(3) data object CrossPost : OptionId(3)
data object Report : OptionId(4) data object Report : OptionId(4)
data object Edit : OptionId(5) data object Edit : OptionId(5)
data object Delete : OptionId(6) data object Delete : OptionId(6)
data object Purge : OptionId(7) data object Purge : OptionId(7)
data object InfoInstance : OptionId(8) data object InfoInstance : OptionId(8)
data object Block : OptionId(9) data object Block : OptionId(9)
data object BlockInstance : OptionId(10) data object BlockInstance : OptionId(10)
data object ToggleRead : OptionId(11) data object ToggleRead : OptionId(11)
data object FeaturePost : OptionId(13) data object FeaturePost : OptionId(13)
data object LockPost : OptionId(14) data object LockPost : OptionId(14)
data object Remove : OptionId(15) data object Remove : OptionId(15)
data object DistinguishComment : OptionId(16) data object DistinguishComment : OptionId(16)
data object OpenReports : OptionId(17) data object OpenReports : OptionId(17)
data object ResolveReport : OptionId(18) data object ResolveReport : OptionId(18)
data object BanUser : OptionId(19) data object BanUser : OptionId(19)
data object AddMod : OptionId(20) data object AddMod : OptionId(20)
data object Favorite : OptionId(21) data object Favorite : OptionId(21)
data object ViewModlog : OptionId(22) data object ViewModlog : OptionId(22)
data object Unban : OptionId(23) data object Unban : OptionId(23)
data object SetCustomSort : OptionId(24) data object SetCustomSort : OptionId(24)
data object Search : OptionId(25) data object Search : OptionId(25)
data object Copy : OptionId(26) data object Copy : OptionId(26)
data object ExploreInstance : OptionId(27) data object ExploreInstance : OptionId(27)
data object Unsubscribe : OptionId(28) data object Unsubscribe : OptionId(28)
data object PurgeCreator : OptionId(29) data object PurgeCreator : OptionId(29)
} }

View File

@ -90,7 +90,8 @@ fun PostCard(
) { ) {
val markRead = post.read && fadeRead val markRead = post.read && fadeRead
Box( Box(
modifier = modifier.then( modifier =
modifier.then(
if (postLayout == PostLayout.Card) { if (postLayout == PostLayout.Card) {
Modifier Modifier
.padding(horizontal = Spacing.xs) .padding(horizontal = Spacing.xs)
@ -116,7 +117,8 @@ fun PostCard(
post = post, post = post,
isFromModerator = isFromModerator, isFromModerator = isFromModerator,
hideAuthor = hideAuthor, hideAuthor = hideAuthor,
backgroundColor = when (postLayout) { backgroundColor =
when (postLayout) {
PostLayout.Card -> MaterialTheme.colorScheme.surfaceColorAtElevation(5.dp) PostLayout.Card -> MaterialTheme.colorScheme.surfaceColorAtElevation(5.dp)
else -> MaterialTheme.colorScheme.background else -> MaterialTheme.colorScheme.background
}, },
@ -218,7 +220,8 @@ private fun CompactPost(
post.url.orEmpty().takeIf { !it.looksLikeAnImage && !it.looksLikeAVideo }.orEmpty() post.url.orEmpty().takeIf { !it.looksLikeAnImage && !it.looksLikeAVideo }.orEmpty()
Column( Column(
modifier = modifier modifier =
modifier
.background(MaterialTheme.colorScheme.background) .background(MaterialTheme.colorScheme.background)
.padding(horizontal = Spacing.xs) .padding(horizontal = Spacing.xs)
.pointerInput(Unit) { .pointerInput(Unit) {
@ -242,16 +245,19 @@ private fun CompactPost(
locked = post.locked, locked = post.locked,
markRead = markRead, markRead = markRead,
isFromModerator = isFromModerator, isFromModerator = isFromModerator,
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity =
rememberCallbackArgs { community ->
onOpenCommunity?.invoke(community, "") onOpenCommunity?.invoke(community, "")
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator =
rememberCallbackArgs { user ->
onOpenCreator?.invoke(user, "") onOpenCreator?.invoke(user, "")
}, },
autoLoadImages = autoLoadImages, autoLoadImages = autoLoadImages,
preferNicknames = preferNicknames, preferNicknames = preferNicknames,
onDoubleClick = onDoubleClick, onDoubleClick = onDoubleClick,
onLongClick = rememberCallback { onLongClick =
rememberCallback {
optionsMenuOpen.value = true optionsMenuOpen.value = true
}, },
) )
@ -281,13 +287,15 @@ private fun CompactPost(
if (post.videoUrl.isNotEmpty()) { if (post.videoUrl.isNotEmpty()) {
PostCardVideo( PostCardVideo(
modifier = Modifier modifier =
Modifier
.weight(0.25f) .weight(0.25f)
.padding(vertical = Spacing.xxs), .padding(vertical = Spacing.xxs),
url = post.videoUrl, url = post.videoUrl,
blurred = blurNsfw && post.nsfw, blurred = blurNsfw && post.nsfw,
autoLoadImages = autoLoadImages, autoLoadImages = autoLoadImages,
onOpen = rememberCallback { onOpen =
rememberCallback {
if (postLinkUrl.isNotEmpty()) { if (postLinkUrl.isNotEmpty()) {
navigationCoordinator.handleUrl( navigationCoordinator.handleUrl(
url = postLinkUrl, url = postLinkUrl,
@ -306,7 +314,8 @@ private fun CompactPost(
) )
} else { } else {
PostCardImage( PostCardImage(
modifier = Modifier modifier =
Modifier
.weight(0.25f) .weight(0.25f)
.then( .then(
if (fullHeightImage) { if (fullHeightImage) {
@ -325,7 +334,8 @@ private fun CompactPost(
Icon(imageVector = Icons.Default.Download, contentDescription = null) Icon(imageVector = Icons.Default.Download, contentDescription = null)
}, },
blurred = blurNsfw && post.nsfw, blurred = blurNsfw && post.nsfw,
onImageClick = rememberCallbackArgs { url -> onImageClick =
rememberCallbackArgs { url ->
if (postLinkUrl.isNotEmpty()) { if (postLinkUrl.isNotEmpty()) {
navigationCoordinator.handleUrl( navigationCoordinator.handleUrl(
url = postLinkUrl, url = postLinkUrl,
@ -342,14 +352,16 @@ private fun CompactPost(
} }
}, },
onDoubleClick = onDoubleClick, onDoubleClick = onDoubleClick,
onLongClick = rememberCallback { onLongClick =
rememberCallback {
optionsMenuOpen.value = true optionsMenuOpen.value = true
}, },
) )
} }
} }
PostCardFooter( PostCardFooter(
modifier = Modifier.padding( modifier =
Modifier.padding(
top = Spacing.xxs, top = Spacing.xxs,
start = Spacing.xs, start = Spacing.xs,
end = Spacing.xs, end = Spacing.xs,
@ -359,7 +371,8 @@ private fun CompactPost(
voteFormat = voteFormat, voteFormat = voteFormat,
score = post.score, score = post.score,
showScores = showScores, showScores = showScores,
unreadComments = post.unreadComments.takeIf { unreadComments =
post.unreadComments.takeIf {
it != null && it > 0 && showUnreadComments && it != post.comments it != null && it > 0 && showUnreadComments && it != post.comments
}, },
upVotes = post.upvotes, upVotes = post.upvotes,
@ -421,7 +434,8 @@ private fun ExtendedPost(
val customTabsHelper = remember { getCustomTabsHelper() } val customTabsHelper = remember { getCustomTabsHelper() }
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val optionsMenuOpen = remember { mutableStateOf(false) } val optionsMenuOpen = remember { mutableStateOf(false) }
val postLinkUrl = post.url.orEmpty().takeIf { val postLinkUrl =
post.url.orEmpty().takeIf {
it != post.imageUrl && it != post.imageUrl &&
it != post.videoUrl && it != post.videoUrl &&
!it.looksLikeAnImage && !it.looksLikeAnImage &&
@ -430,7 +444,8 @@ private fun ExtendedPost(
}.orEmpty() }.orEmpty()
Column( Column(
modifier = modifier modifier =
modifier
.background(backgroundColor) .background(backgroundColor)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
@ -453,22 +468,26 @@ private fun ExtendedPost(
locked = post.locked, locked = post.locked,
markRead = markRead, markRead = markRead,
isFromModerator = isFromModerator, isFromModerator = isFromModerator,
onOpenCommunity = rememberCallbackArgs { community -> onOpenCommunity =
rememberCallbackArgs { community ->
onOpenCommunity?.invoke(community, "") onOpenCommunity?.invoke(community, "")
}, },
onOpenCreator = rememberCallbackArgs { user -> onOpenCreator =
rememberCallbackArgs { user ->
onOpenCreator?.invoke(user, "") onOpenCreator?.invoke(user, "")
}, },
autoLoadImages = autoLoadImages, autoLoadImages = autoLoadImages,
preferNicknames = preferNicknames, preferNicknames = preferNicknames,
onDoubleClick = onDoubleClick, onDoubleClick = onDoubleClick,
onLongClick = rememberCallback { onLongClick =
rememberCallback {
optionsMenuOpen.value = true optionsMenuOpen.value = true
}, },
) )
CustomizedContent(ContentFontClass.Title) { CustomizedContent(ContentFontClass.Title) {
PostCardTitle( PostCardTitle(
modifier = Modifier.padding( modifier =
Modifier.padding(
vertical = Spacing.xs, vertical = Spacing.xs,
horizontal = Spacing.s, horizontal = Spacing.s,
), ),
@ -483,7 +502,8 @@ private fun ExtendedPost(
onClick = onClick, onClick = onClick,
onOpenImage = onOpenImage, onOpenImage = onOpenImage,
onDoubleClick = onDoubleClick, onDoubleClick = onDoubleClick,
onLongClick = rememberCallback { onLongClick =
rememberCallback {
optionsMenuOpen.value = true optionsMenuOpen.value = true
}, },
) )
@ -491,7 +511,8 @@ private fun ExtendedPost(
if (post.embeddedUrl.isNotEmpty()) { if (post.embeddedUrl.isNotEmpty()) {
PostCardEmbeddedWebView( PostCardEmbeddedWebView(
modifier = Modifier modifier =
Modifier
.padding( .padding(
vertical = Spacing.xxs, vertical = Spacing.xxs,
horizontal = if (fullWidthImage) 0.dp else Spacing.s, horizontal = if (fullWidthImage) 0.dp else Spacing.s,
@ -518,7 +539,8 @@ private fun ExtendedPost(
) )
} else if (post.videoUrl.isNotEmpty()) { } else if (post.videoUrl.isNotEmpty()) {
PostCardVideo( PostCardVideo(
modifier = Modifier modifier =
Modifier
.padding( .padding(
vertical = Spacing.xxs, vertical = Spacing.xxs,
horizontal = if (fullWidthImage) 0.dp else Spacing.s, horizontal = if (fullWidthImage) 0.dp else Spacing.s,
@ -546,7 +568,8 @@ private fun ExtendedPost(
) )
} else { } else {
PostCardImage( PostCardImage(
modifier = Modifier modifier =
Modifier
.padding( .padding(
vertical = Spacing.xs, vertical = Spacing.xs,
horizontal = if (fullWidthImage) 0.dp else Spacing.s, horizontal = if (fullWidthImage) 0.dp else Spacing.s,
@ -566,7 +589,8 @@ private fun ExtendedPost(
), ),
imageUrl = post.imageUrl, imageUrl = post.imageUrl,
blurred = blurNsfw && post.nsfw, blurred = blurNsfw && post.nsfw,
onImageClick = rememberCallbackArgs { url -> onImageClick =
rememberCallbackArgs { url ->
if (postLinkUrl.isNotEmpty()) { if (postLinkUrl.isNotEmpty()) {
navigationCoordinator.handleUrl( navigationCoordinator.handleUrl(
url = postLinkUrl, url = postLinkUrl,
@ -601,13 +625,15 @@ private fun ExtendedPost(
} else { } else {
CustomizedContent(ContentFontClass.Body) { CustomizedContent(ContentFontClass.Body) {
PostCardBody( PostCardBody(
modifier = Modifier.padding( modifier =
Modifier.padding(
top = Spacing.xxs, top = Spacing.xxs,
start = Spacing.s, start = Spacing.s,
end = Spacing.s, end = Spacing.s,
), ),
text = post.text, text = post.text,
maxLines = if (limitBodyHeight) { maxLines =
if (limitBodyHeight) {
settings.postBodyMaxLines settings.postBodyMaxLines
} else { } else {
null null
@ -630,7 +656,8 @@ private fun ExtendedPost(
} }
if (postLinkUrl.isNotEmpty()) { if (postLinkUrl.isNotEmpty()) {
PostLinkBanner( PostLinkBanner(
modifier = Modifier modifier =
Modifier
.padding( .padding(
top = Spacing.s, top = Spacing.s,
bottom = Spacing.xxs, bottom = Spacing.xxs,
@ -656,7 +683,8 @@ private fun ExtendedPost(
) )
} }
PostCardFooter( PostCardFooter(
modifier = Modifier.padding( modifier =
Modifier.padding(
top = Spacing.xs, top = Spacing.xs,
start = Spacing.s, start = Spacing.s,
end = Spacing.s, end = Spacing.s,
@ -666,7 +694,8 @@ private fun ExtendedPost(
voteFormat = voteFormat, voteFormat = voteFormat,
score = post.score, score = post.score,
showScores = showScores, showScores = showScores,
unreadComments = post.unreadComments.takeIf { unreadComments =
post.unreadComments.takeIf {
it != null && it > 0 && showUnreadComments && it != post.comments it != null && it > 0 && showUnreadComments && it != post.comments
}, },
upVotes = post.upvotes, upVotes = post.upvotes,

View File

@ -57,7 +57,8 @@ fun PostCardBody(
content = text, content = text,
maxLines = maxLines, maxLines = maxLines,
autoLoadImages = autoLoadImages, autoLoadImages = autoLoadImages,
typography = markdownTypography( typography =
markdownTypography(
h1 = typography.titleLarge, h1 = typography.titleLarge,
h2 = typography.titleLarge, h2 = typography.titleLarge,
h3 = typography.titleMedium, h3 = typography.titleMedium,
@ -72,14 +73,16 @@ fun PostCardBody(
ordered = typography.bodyMedium, ordered = typography.bodyMedium,
code = typography.bodyMedium.copy(fontFamily = FontFamily.Monospace), code = typography.bodyMedium.copy(fontFamily = FontFamily.Monospace),
), ),
colors = markdownColor( colors =
markdownColor(
text = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor), text = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor),
linkText = MaterialTheme.colorScheme.primary.copy(alpha = additionalAlphaFactor), linkText = MaterialTheme.colorScheme.primary.copy(alpha = additionalAlphaFactor),
codeText = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor), codeText = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor),
codeBackground = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f), codeBackground = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f),
dividerColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), dividerColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
), ),
onOpenUrl = rememberCallbackArgs { url -> onOpenUrl =
rememberCallbackArgs { url ->
navigationCoordinator.handleUrl( navigationCoordinator.handleUrl(
url = url, url = url,
openingMode = settingsRepository.currentSettings.value.urlOpeningMode.toUrlOpeningMode(), openingMode = settingsRepository.currentSettings.value.urlOpeningMode.toUrlOpeningMode(),
@ -91,7 +94,8 @@ fun PostCardBody(
onOpenWeb = onOpenWeb, onOpenWeb = onOpenWeb,
) )
}, },
onOpenImage = rememberCallbackArgs { url -> onOpenImage =
rememberCallbackArgs { url ->
onOpenImage?.invoke(url) onOpenImage?.invoke(url)
}, },
onClick = onClick, onClick = onClick,

View File

@ -97,7 +97,8 @@ fun PostCardFooter(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Icon( Icon(
modifier = buttonModifier.padding( modifier =
buttonModifier.padding(
top = 3.5.dp, top = 3.5.dp,
end = 3.5.dp, end = 3.5.dp,
bottom = 3.5.dp, bottom = 3.5.dp,
@ -120,7 +121,8 @@ fun PostCardFooter(
} }
if (unreadComments != null) { if (unreadComments != null) {
Text( Text(
modifier = Modifier modifier =
Modifier
.padding(start = Spacing.xxs) .padding(start = Spacing.xxs)
.background( .background(
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,
@ -144,14 +146,16 @@ fun PostCardFooter(
) { ) {
val isShowingUpdateDate = !updateDate.isNullOrBlank() val isShowingUpdateDate = !updateDate.isNullOrBlank()
Icon( Icon(
modifier = Modifier.size(IconSize.s).then( modifier =
Modifier.size(IconSize.s).then(
if (!isShowingUpdateDate) { if (!isShowingUpdateDate) {
Modifier.padding(0.5.dp) Modifier.padding(0.5.dp)
} else { } else {
Modifier Modifier
}, },
), ),
imageVector = if (isShowingUpdateDate) { imageVector =
if (isShowingUpdateDate) {
Icons.Default.Update Icons.Default.Update
} else { } else {
Icons.Default.Schedule Icons.Default.Schedule
@ -169,7 +173,8 @@ fun PostCardFooter(
} }
if (options.isNotEmpty()) { if (options.isNotEmpty()) {
Icon( Icon(
modifier = Modifier.size(IconSize.m) modifier =
Modifier.size(IconSize.m)
.padding(Spacing.xs) .padding(Spacing.xs)
.onGloballyPositioned { .onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
@ -187,17 +192,20 @@ fun PostCardFooter(
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
if (actionButtonsActive) { if (actionButtonsActive) {
FeedbackButton( FeedbackButton(
modifier = buttonModifier.padding( modifier =
buttonModifier.padding(
top = 2.5.dp, top = 2.5.dp,
bottom = 2.5.dp, bottom = 2.5.dp,
end = 2.5.dp, end = 2.5.dp,
), ),
imageVector = if (!saved) { imageVector =
if (!saved) {
Icons.Default.BookmarkBorder Icons.Default.BookmarkBorder
} else { } else {
Icons.Default.Bookmark Icons.Default.Bookmark
}, },
tintColor = if (saved) { tintColor =
if (saved) {
MaterialTheme.colorScheme.secondary MaterialTheme.colorScheme.secondary
} else { } else {
ancillaryColor ancillaryColor
@ -209,12 +217,14 @@ fun PostCardFooter(
} }
FeedbackButton( FeedbackButton(
modifier = buttonModifier.padding(all = 2.5.dp), modifier = buttonModifier.padding(all = 2.5.dp),
imageVector = if (actionButtonsActive) { imageVector =
if (actionButtonsActive) {
Icons.Default.ArrowCircleUp Icons.Default.ArrowCircleUp
} else { } else {
Icons.Default.ArrowUpward Icons.Default.ArrowUpward
}, },
tintColor = if (upVoted) { tintColor =
if (upVoted) {
upVoteColor ?: defaultUpvoteColor upVoteColor ?: defaultUpvoteColor
} else { } else {
ancillaryColor ancillaryColor
@ -225,7 +235,8 @@ fun PostCardFooter(
) )
if (showScores) { if (showScores) {
Text( Text(
text = formatToReadableValue( text =
formatToReadableValue(
voteFormat = voteFormat, voteFormat = voteFormat,
score = score, score = score,
upVotes = upVotes, upVotes = upVotes,
@ -240,17 +251,20 @@ fun PostCardFooter(
) )
} }
FeedbackButton( FeedbackButton(
modifier = buttonModifier.padding( modifier =
buttonModifier.padding(
top = 2.5.dp, top = 2.5.dp,
bottom = 2.5.dp, bottom = 2.5.dp,
end = 2.5.dp, end = 2.5.dp,
), ),
imageVector = if (actionButtonsActive) { imageVector =
if (actionButtonsActive) {
Icons.Default.ArrowCircleDown Icons.Default.ArrowCircleDown
} else { } else {
Icons.Default.ArrowDownward Icons.Default.ArrowDownward
}, },
tintColor = if (downVoted) { tintColor =
if (downVoted) {
downVoteColor ?: defaultDownVoteColor downVoteColor ?: defaultDownVoteColor
} else { } else {
ancillaryColor ancillaryColor
@ -266,7 +280,8 @@ fun PostCardFooter(
onDismiss = { onDismiss = {
optionsMenuOpen.value = false optionsMenuOpen.value = false
}, },
offset = DpOffset( offset =
DpOffset(
x = optionsOffset.x.toLocalDp(), x = optionsOffset.x.toLocalDp(),
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),

View File

@ -37,7 +37,8 @@ fun PostCardImage(
) { ) {
if (imageUrl.isNotEmpty()) { if (imageUrl.isNotEmpty()) {
CustomImage( CustomImage(
modifier = modifier.fillMaxWidth() modifier =
modifier.fillMaxWidth()
.heightIn(min = minHeight, max = maxHeight) .heightIn(min = minHeight, max = maxHeight)
.blur(radius = if (blurred) 60.dp else 0.dp) .blur(radius = if (blurred) 60.dp else 0.dp)
.onClick( .onClick(
@ -59,14 +60,16 @@ fun PostCardImage(
) )
}, },
onLoading = { progress -> onLoading = { progress ->
val prog = if (progress != null) { val prog =
if (progress != null) {
progress progress
} else { } else {
val transition = rememberInfiniteTransition() val transition = rememberInfiniteTransition()
val res by transition.animateFloat( val res by transition.animateFloat(
initialValue = 0f, initialValue = 0f,
targetValue = 1f, targetValue = 1f,
animationSpec = InfiniteRepeatableSpec( animationSpec =
InfiniteRepeatableSpec(
animation = tween(1000), animation = tween(1000),
), ),
) )

View File

@ -42,7 +42,8 @@ fun PostCardPlaceholder(
horizontalArrangement = Arrangement.spacedBy(Spacing.s), horizontalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
Box( Box(
modifier = Modifier.size(IconSize.s) modifier =
Modifier.size(IconSize.s)
.clip(CircleShape) .clip(CircleShape)
.shimmerEffect(), .shimmerEffect(),
) )
@ -51,13 +52,15 @@ fun PostCardPlaceholder(
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth(0.5f) .fillMaxWidth(0.5f)
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
@ -69,14 +72,16 @@ fun PostCardPlaceholder(
horizontalArrangement = Arrangement.spacedBy(Spacing.xs), horizontalArrangement = Arrangement.spacedBy(Spacing.xs),
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.weight(0.2f) .weight(0.2f)
.aspectRatio(1.33f) .aspectRatio(1.33f)
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(40.dp) .height(40.dp)
.weight(1f) .weight(1f)
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
@ -84,7 +89,8 @@ fun PostCardPlaceholder(
) )
} }
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))
@ -95,7 +101,8 @@ fun PostCardPlaceholder(
PostLayout.Card -> { PostLayout.Card -> {
Column( Column(
modifier = Modifier modifier =
Modifier
.shadow(elevation = 5.dp, shape = RoundedCornerShape(CornerSize.l)) .shadow(elevation = 5.dp, shape = RoundedCornerShape(CornerSize.l))
.clip(RoundedCornerShape(CornerSize.l)) .clip(RoundedCornerShape(CornerSize.l))
.background( .background(
@ -109,7 +116,8 @@ fun PostCardPlaceholder(
horizontalArrangement = Arrangement.spacedBy(Spacing.s), horizontalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.size(IconSize.l) .size(IconSize.l)
.clip(CircleShape) .clip(CircleShape)
.shimmerEffect(), .shimmerEffect(),
@ -119,13 +127,15 @@ fun PostCardPlaceholder(
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth(0.5f) .fillMaxWidth(0.5f)
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
@ -133,20 +143,23 @@ fun PostCardPlaceholder(
} }
} }
Box( Box(
modifier = Modifier.height(IconSize.l) modifier =
Modifier.height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(200.dp) .height(200.dp)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
@ -165,7 +178,8 @@ fun PostCardPlaceholder(
horizontalArrangement = Arrangement.spacedBy(Spacing.s), horizontalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
Box( Box(
modifier = Modifier modifier =
Modifier
.size(IconSize.l) .size(IconSize.l)
.clip(CircleShape) .clip(CircleShape)
.shimmerEffect(), .shimmerEffect(),
@ -175,13 +189,15 @@ fun PostCardPlaceholder(
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier.height(IconSize.s) modifier =
Modifier.height(IconSize.s)
.fillMaxWidth(0.5f) .fillMaxWidth(0.5f)
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
@ -189,21 +205,24 @@ fun PostCardPlaceholder(
} }
} }
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(200.dp) .height(200.dp)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.s)) .clip(RoundedCornerShape(CornerSize.s))
.shimmerEffect(), .shimmerEffect(),
) )
Box( Box(
modifier = Modifier modifier =
Modifier
.height(IconSize.l) .height(IconSize.l)
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(CornerSize.m)) .clip(RoundedCornerShape(CornerSize.m))

View File

@ -50,12 +50,14 @@ fun PostCardTitle(
val themeRepository = remember { getThemeRepository() } val themeRepository = remember { getThemeRepository() }
val fontFamily by themeRepository.contentFontFamily.collectAsState() val fontFamily by themeRepository.contentFontFamily.collectAsState()
val typography = fontFamily.toTypography() val typography = fontFamily.toTypography()
val weightNormalOrLight = if (bolder) { val weightNormalOrLight =
if (bolder) {
FontWeight.Normal FontWeight.Normal
} else { } else {
FontWeight.Light FontWeight.Light
} }
val weightMediumOrNormal = if (bolder) { val weightMediumOrNormal =
if (bolder) {
FontWeight.Medium FontWeight.Medium
} else { } else {
FontWeight.Normal FontWeight.Normal
@ -66,7 +68,8 @@ fun PostCardTitle(
modifier = modifier.padding(horizontal = Spacing.xxs), modifier = modifier.padding(horizontal = Spacing.xxs),
content = text, content = text,
autoLoadImages = autoLoadImages, autoLoadImages = autoLoadImages,
typography = markdownTypography( typography =
markdownTypography(
h1 = typography.titleLarge.copy(fontWeight = weightNormalOrLight), h1 = typography.titleLarge.copy(fontWeight = weightNormalOrLight),
h2 = typography.titleLarge.copy(fontWeight = weightNormalOrLight), h2 = typography.titleLarge.copy(fontWeight = weightNormalOrLight),
h3 = typography.titleMedium.copy(fontWeight = weightMediumOrNormal), h3 = typography.titleMedium.copy(fontWeight = weightMediumOrNormal),
@ -81,13 +84,15 @@ fun PostCardTitle(
ordered = typography.bodyMedium, ordered = typography.bodyMedium,
code = typography.bodyMedium.copy(fontFamily = FontFamily.Monospace), code = typography.bodyMedium.copy(fontFamily = FontFamily.Monospace),
), ),
colors = markdownColor( colors =
markdownColor(
text = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor), text = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor),
codeText = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor), codeText = MaterialTheme.colorScheme.onBackground.copy(alpha = additionalAlphaFactor),
codeBackground = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f), codeBackground = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f),
dividerColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), dividerColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
), ),
onOpenUrl = rememberCallbackArgs { url -> onOpenUrl =
rememberCallbackArgs { url ->
navigationCoordinator.handleUrl( navigationCoordinator.handleUrl(
url = url, url = url,
openingMode = settingsRepository.currentSettings.value.urlOpeningMode.toUrlOpeningMode(), openingMode = settingsRepository.currentSettings.value.urlOpeningMode.toUrlOpeningMode(),
@ -99,7 +104,8 @@ fun PostCardTitle(
onOpenWeb = onOpenWeb, onOpenWeb = onOpenWeb,
) )
}, },
onOpenImage = rememberCallbackArgs { url -> onOpenImage =
rememberCallbackArgs { url ->
onOpenImage?.invoke(url) onOpenImage?.invoke(url)
}, },
onClick = onClick, onClick = onClick,

View File

@ -24,7 +24,8 @@ fun PostLinkBanner(
) { ) {
if (url.isNotEmpty()) { if (url.isNotEmpty()) {
Row( Row(
modifier = modifier modifier =
modifier
.background( .background(
color = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.1f), color = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.1f),
shape = RoundedCornerShape(CornerSize.l), shape = RoundedCornerShape(CornerSize.l),

View File

@ -2,5 +2,6 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui
sealed interface ProfileLoggedSection { sealed interface ProfileLoggedSection {
data object Posts : ProfileLoggedSection data object Posts : ProfileLoggedSection
data object Comments : ProfileLoggedSection data object Comments : ProfileLoggedSection
} }

View File

@ -24,7 +24,8 @@ fun SettingsFormattedInfo(
) { ) {
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha) val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
Box( Box(
modifier = modifier modifier =
modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
vertical = Spacing.xs, vertical = Spacing.xs,

View File

@ -24,7 +24,8 @@ fun SettingsHeader(
) { ) {
val fullColor = MaterialTheme.colorScheme.onBackground val fullColor = MaterialTheme.colorScheme.onBackground
Row( Row(
modifier = modifier.padding( modifier =
modifier.padding(
vertical = Spacing.xxs, vertical = Spacing.xxs,
horizontal = Spacing.s, horizontal = Spacing.s,
), ),

View File

@ -31,7 +31,8 @@ fun SettingsImageInfo(
) { ) {
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha) val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
Box( Box(
modifier = modifier modifier =
modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
vertical = Spacing.xs, vertical = Spacing.xs,

View File

@ -33,7 +33,8 @@ fun SettingsIntValueRow(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Column( Column(
modifier = Modifier modifier =
Modifier
.weight(1f) .weight(1f)
.padding(vertical = Spacing.s), .padding(vertical = Spacing.s),
) { ) {
@ -59,7 +60,8 @@ fun SettingsIntValueRow(
onClick = onDecrement, onClick = onDecrement,
) )
Text( Text(
modifier = Modifier modifier =
Modifier
.sizeIn(minWidth = 40.dp) .sizeIn(minWidth = 40.dp)
.padding(horizontal = Spacing.s), .padding(horizontal = Spacing.s),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,

View File

@ -38,7 +38,8 @@ fun SettingsRow(
val fullColor = MaterialTheme.colorScheme.onBackground val fullColor = MaterialTheme.colorScheme.onBackground
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha) val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
Row( Row(
modifier = modifier modifier =
modifier
.padding( .padding(
vertical = Spacing.s, vertical = Spacing.s,
horizontal = Spacing.m, horizontal = Spacing.m,

View File

@ -27,7 +27,8 @@ fun SettingsTextualInfo(
val fullColor = MaterialTheme.colorScheme.onBackground val fullColor = MaterialTheme.colorScheme.onBackground
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha) val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
Box( Box(
modifier = modifier modifier =
modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
vertical = Spacing.xs, vertical = Spacing.xs,

View File

@ -57,12 +57,15 @@ fun TextFormattingBar(
// bold // bold
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val selection = textFieldValue.selection val selection = textFieldValue.selection
val newValue = textFieldValue.let { val newValue =
val newText = buildString { textFieldValue.let {
val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("**") append("**")
if (selection.collapsed) { if (selection.collapsed) {
@ -83,7 +86,8 @@ fun TextFormattingBar(
), ),
) )
} }
val newSelection = if (selection.collapsed) { val newSelection =
if (selection.collapsed) {
TextRange(index = selection.start + textPlaceholder.length + 2) TextRange(index = selection.start + textPlaceholder.length + 2)
} else { } else {
TextRange( TextRange(
@ -105,12 +109,15 @@ fun TextFormattingBar(
// italic // italic
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val selection = textFieldValue.selection val selection = textFieldValue.selection
val newValue = textFieldValue.let { val newValue =
val newText = buildString { textFieldValue.let {
val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("*") append("*")
if (selection.collapsed) { if (selection.collapsed) {
@ -131,7 +138,8 @@ fun TextFormattingBar(
), ),
) )
} }
val newSelection = if (selection.collapsed) { val newSelection =
if (selection.collapsed) {
TextRange(index = selection.start + textPlaceholder.length + 1) TextRange(index = selection.start + textPlaceholder.length + 1)
} else { } else {
TextRange( TextRange(
@ -153,12 +161,15 @@ fun TextFormattingBar(
// strikethrough // strikethrough
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val selection = textFieldValue.selection val selection = textFieldValue.selection
val newValue = textFieldValue.let { val newValue =
val newText = buildString { textFieldValue.let {
val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("~~") append("~~")
if (selection.collapsed) { if (selection.collapsed) {
@ -179,7 +190,8 @@ fun TextFormattingBar(
), ),
) )
} }
val newSelection = if (selection.collapsed) { val newSelection =
if (selection.collapsed) {
TextRange(index = selection.start + textPlaceholder.length + 2) TextRange(index = selection.start + textPlaceholder.length + 2)
} else { } else {
TextRange( TextRange(
@ -202,7 +214,8 @@ fun TextFormattingBar(
if (onSelectImage != null) { if (onSelectImage != null) {
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
onClick = { onClick = {
onSelectImage.invoke() onSelectImage.invoke()
}, },
@ -217,12 +230,15 @@ fun TextFormattingBar(
// hyperlink // hyperlink
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val newValue = textFieldValue.let { val newValue =
textFieldValue.let {
val selection = it.selection val selection = it.selection
val newText = buildString { val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("[") append("[")
if (selection.collapsed) { if (selection.collapsed) {
@ -245,7 +261,8 @@ fun TextFormattingBar(
), ),
) )
} }
val newSelection = if (selection.collapsed) { val newSelection =
if (selection.collapsed) {
TextRange(index = selection.start + textPlaceholder.length + 1) TextRange(index = selection.start + textPlaceholder.length + 1)
} else { } else {
TextRange( TextRange(
@ -267,12 +284,15 @@ fun TextFormattingBar(
// inline code // inline code
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val newValue = textFieldValue.let { val newValue =
textFieldValue.let {
val selection = it.selection val selection = it.selection
val newText = buildString { val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("`") append("`")
if (selection.collapsed) { if (selection.collapsed) {
@ -293,7 +313,8 @@ fun TextFormattingBar(
), ),
) )
} }
val newSelection = if (selection.collapsed) { val newSelection =
if (selection.collapsed) {
TextRange(index = selection.start + textPlaceholder.length + 1) TextRange(index = selection.start + textPlaceholder.length + 1)
} else { } else {
TextRange( TextRange(
@ -315,12 +336,15 @@ fun TextFormattingBar(
// block quote // block quote
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val newValue = textFieldValue.let { val newValue =
textFieldValue.let {
val selection = it.selection val selection = it.selection
val newText = buildString { val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("\n> ") append("\n> ")
append( append(
@ -345,12 +369,15 @@ fun TextFormattingBar(
// bulleted list // bulleted list
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val newValue = textFieldValue.let { val newValue =
textFieldValue.let {
val selection = it.selection val selection = it.selection
val newText = buildString { val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("\n- ") append("\n- ")
append( append(
@ -375,12 +402,15 @@ fun TextFormattingBar(
// numbered list // numbered list
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
key = textFieldValue, key = textFieldValue,
onClick = { onClick = {
val newValue = textFieldValue.let { val newValue =
textFieldValue.let {
val selection = it.selection val selection = it.selection
val newText = buildString { val newText =
buildString {
append(it.text.substring(0, selection.start)) append(it.text.substring(0, selection.start))
append("\n1. ") append("\n1. ")
append( append(
@ -406,7 +436,8 @@ fun TextFormattingBar(
if (onSelectLanguage != null) { if (onSelectLanguage != null) {
item { item {
Box( Box(
modifier = Modifier modifier =
Modifier
.size(IconSize.m) .size(IconSize.m)
.border( .border(
color = MaterialTheme.colorScheme.onBackground, color = MaterialTheme.colorScheme.onBackground,
@ -417,7 +448,8 @@ fun TextFormattingBar(
.padding(Spacing.xxxs), .padding(Spacing.xxxs),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
val languageCode = availableLanguages.firstOrNull { l -> val languageCode =
availableLanguages.firstOrNull { l ->
l.id == currentLanguageId l.id == currentLanguageId
}?.takeIf { l -> }?.takeIf { l ->
l.id > 0 // undetermined language l.id > 0 // undetermined language
@ -436,7 +468,8 @@ fun TextFormattingBar(
if (lastActionIcon != null && onLastAction != null) { if (lastActionIcon != null && onLastAction != null) {
item { item {
Icon( Icon(
modifier = Modifier.onClick( modifier =
Modifier.onClick(
onClick = { onClick = {
onLastAction() onLastAction()
}, },

View File

@ -93,7 +93,8 @@ fun NavigationCoordinator.handleUrl(
private fun normalizeUrl(url: String?): Pair<String, String> { private fun normalizeUrl(url: String?): Pair<String, String> {
val matches = Regex("https?://(?<instance>.*?)(?<pathAndQuery>/.*)").findAll(url.orEmpty()) val matches = Regex("https?://(?<instance>.*?)(?<pathAndQuery>/.*)").findAll(url.orEmpty())
var instance = "" var instance = ""
val res = buildString { val res =
buildString {
if (matches.count() > 0) { if (matches.count() > 0) {
val match = matches.iterator().next() val match = matches.iterator().next()
val value = match.groups["pathAndQuery"]?.value.orEmpty() val value = match.groups["pathAndQuery"]?.value.orEmpty()
@ -110,7 +111,8 @@ private fun normalizeUrl(url: String?): Pair<String, String> {
return res to instance return res to instance
} }
private fun extractCommunity(url: String): CommunityModel? = when { private fun extractCommunity(url: String): CommunityModel? =
when {
url.startsWith("/c/") -> { url.startsWith("/c/") -> {
val cleanString = url.substring(3) val cleanString = url.substring(3)
if (cleanString.count { it == '@' } == 1) { if (cleanString.count { it == '@' } == 1) {
@ -142,9 +144,10 @@ private fun extractCommunity(url: String): CommunityModel? = when {
} }
else -> null else -> null
} }
private fun extractUser(url: String): UserModel? = when { private fun extractUser(url: String): UserModel? =
when {
url.startsWith("@") -> { url.startsWith("@") -> {
val cleanString = url.substring(1) val cleanString = url.substring(1)
if (cleanString.count { it == '@' } == 1) { if (cleanString.count { it == '@' } == 1) {
@ -176,12 +179,13 @@ private fun extractUser(url: String): UserModel? = when {
} }
else -> null else -> null
} }
private fun extractPost(url: String): PostModel? { private fun extractPost(url: String): PostModel? {
val regex = Regex("/post/(?<postId>.*$)") val regex = Regex("/post/(?<postId>.*$)")
val match = regex.find(url) val match = regex.find(url)
val id = match val id =
match
?.let { it.groups["postId"]?.value.orEmpty() }?.toLongOrNull() ?.let { it.groups["postId"]?.value.orEmpty() }?.toLongOrNull()
return if (id != null) { return if (id != null) {
PostModel(id = id) PostModel(id = id)

View File

@ -2,5 +2,6 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui
sealed interface UserDetailSection { sealed interface UserDetailSection {
data object Posts : UserDetailSection data object Posts : UserDetailSection
data object Comments : UserDetailSection data object Comments : UserDetailSection
} }

View File

@ -70,9 +70,12 @@ fun UserHeader(
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
) )
Box( Box(
modifier = Modifier.fillMaxSize().background( modifier =
brush = Brush.horizontalGradient( Modifier.fillMaxSize().background(
colors = listOf( brush =
Brush.horizontalGradient(
colors =
listOf(
MaterialTheme.colorScheme.background.copy(alpha = 0.95f), MaterialTheme.colorScheme.background.copy(alpha = 0.95f),
Color.Transparent, Color.Transparent,
MaterialTheme.colorScheme.background.copy(alpha = 0.75f), MaterialTheme.colorScheme.background.copy(alpha = 0.75f),
@ -92,7 +95,8 @@ fun UserHeader(
val userAvatar = user.avatar.orEmpty() val userAvatar = user.avatar.orEmpty()
if (userAvatar.isNotEmpty() && autoLoadImages) { if (userAvatar.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier.padding(Spacing.xxxs) modifier =
Modifier.padding(Spacing.xxxs)
.size(IconSize.xxl) .size(IconSize.xxl)
.clip(RoundedCornerShape(IconSize.xxl / 2)) .clip(RoundedCornerShape(IconSize.xxl / 2))
.onClick( .onClick(
@ -145,7 +149,8 @@ fun UserHeader(
contentDescription = null, contentDescription = null,
) )
Text( Text(
text = postScore.getPrettyNumber( text =
postScore.getPrettyNumber(
thousandLabel = LocalXmlStrings.current.profileThousandShort, thousandLabel = LocalXmlStrings.current.profileThousandShort,
millionLabel = LocalXmlStrings.current.profileMillionShort, millionLabel = LocalXmlStrings.current.profileMillionShort,
), ),
@ -163,7 +168,8 @@ fun UserHeader(
contentDescription = null, contentDescription = null,
) )
Text( Text(
text = commentScore.getPrettyNumber( text =
commentScore.getPrettyNumber(
thousandLabel = LocalXmlStrings.current.profileThousandShort, thousandLabel = LocalXmlStrings.current.profileThousandShort,
millionLabel = LocalXmlStrings.current.profileMillionShort, millionLabel = LocalXmlStrings.current.profileMillionShort,
), ),
@ -199,7 +205,8 @@ fun UserHeader(
if (onInfo != null) { if (onInfo != null) {
Icon( Icon(
modifier = Modifier modifier =
Modifier
.padding(end = Spacing.s) .padding(end = Spacing.s)
.size(iconSize) .size(iconSize)
.onClick(onClick = onInfo), .onClick(onClick = onInfo),

View File

@ -60,7 +60,8 @@ fun UserItem(
var optionsMenuOpen by remember { mutableStateOf(false) } var optionsMenuOpen by remember { mutableStateOf(false) }
Row( Row(
modifier = modifier.padding( modifier =
modifier.padding(
vertical = Spacing.xs, vertical = Spacing.xs,
horizontal = Spacing.s, horizontal = Spacing.s,
), ),
@ -69,7 +70,8 @@ fun UserItem(
) { ) {
if (avatar.isNotEmpty() && autoLoadImages) { if (avatar.isNotEmpty() && autoLoadImages) {
CustomImage( CustomImage(
modifier = Modifier.padding(Spacing.xxxs).size(iconSize) modifier =
Modifier.padding(Spacing.xxxs).size(iconSize)
.clip(RoundedCornerShape(iconSize / 2)), .clip(RoundedCornerShape(iconSize / 2)),
url = avatar, url = avatar,
quality = FilterQuality.Low, quality = FilterQuality.Low,
@ -86,7 +88,8 @@ fun UserItem(
modifier = Modifier.weight(1f).padding(start = Spacing.xs), modifier = Modifier.weight(1f).padding(start = Spacing.xs),
) { ) {
Text( Text(
text = buildString { text =
buildString {
append(displayName) append(displayName)
}, },
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
@ -95,7 +98,8 @@ fun UserItem(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
Text( Text(
text = buildString { text =
buildString {
append("!") append("!")
append(userHandle) append(userHandle)
}, },
@ -107,7 +111,8 @@ fun UserItem(
if (options.isNotEmpty()) { if (options.isNotEmpty()) {
Box { Box {
Icon( Icon(
modifier = Modifier.size(IconSize.m) modifier =
Modifier.size(IconSize.m)
.padding(Spacing.xs) .padding(Spacing.xs)
.onGloballyPositioned { .onGloballyPositioned {
optionsOffset = it.positionInParent() optionsOffset = it.positionInParent()
@ -127,7 +132,8 @@ fun UserItem(
onDismiss = { onDismiss = {
optionsMenuOpen = false optionsMenuOpen = false
}, },
offset = DpOffset( offset =
DpOffset(
x = optionsOffset.x.toLocalDp(), x = optionsOffset.x.toLocalDp(),
y = optionsOffset.y.toLocalDp(), y = optionsOffset.y.toLocalDp(),
), ),

View File

@ -4,8 +4,9 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.DefaultFab
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.FabNestedScrollConnection import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.FabNestedScrollConnection
import org.koin.dsl.module import org.koin.dsl.module
val lemmyUiModule = module { val lemmyUiModule =
module {
factory<FabNestedScrollConnection> { factory<FabNestedScrollConnection> {
DefaultFabNestedScrollConnection() DefaultFabNestedScrollConnection()
} }
} }

View File

@ -4,8 +4,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.FabNestedS
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
actual fun getFabNestedScrollConnection(): FabNestedScrollConnection = actual fun getFabNestedScrollConnection(): FabNestedScrollConnection = LemmyUiDiHelper.fabNestedScrollConnection
LemmyUiDiHelper.fabNestedScrollConnection
object LemmyUiDiHelper : KoinComponent { object LemmyUiDiHelper : KoinComponent {
val fabNestedScrollConnection: FabNestedScrollConnection by inject() val fabNestedScrollConnection: FabNestedScrollConnection by inject()

View File

@ -33,7 +33,8 @@ class AppIconBottomSheet : Screen {
val coreResources = remember { getCoreResources() } val coreResources = remember { getCoreResources() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -44,7 +45,8 @@ class AppIconBottomSheet : Screen {
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
BottomSheetHeader(LocalXmlStrings.current.settingsAppIcon) BottomSheetHeader(LocalXmlStrings.current.settingsAppIcon)
val values = listOf( val values =
listOf(
AppIconVariant.Default, AppIconVariant.Default,
AppIconVariant.Alt1, AppIconVariant.Alt1,
) )
@ -56,7 +58,8 @@ class AppIconBottomSheet : Screen {
SettingsRow( SettingsRow(
modifier = Modifier.padding(vertical = Spacing.xxs), modifier = Modifier.padding(vertical = Spacing.xxs),
title = value.toReadableName(), title = value.toReadableName(),
painter = when (value) { painter =
when (value) {
AppIconVariant.Alt1 -> coreResources.appIconAlt1 AppIconVariant.Alt1 -> coreResources.appIconAlt1
else -> coreResources.appIconDefault else -> coreResources.appIconDefault
}, },

View File

@ -27,13 +27,13 @@ import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotific
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
class BarThemeBottomSheet : Screen { class BarThemeBottomSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -44,7 +44,8 @@ class BarThemeBottomSheet : Screen {
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
BottomSheetHeader(LocalXmlStrings.current.settingsBarTheme) BottomSheetHeader(LocalXmlStrings.current.settingsBarTheme)
val values = listOf( val values =
listOf(
UiBarTheme.Transparent, UiBarTheme.Transparent,
UiBarTheme.Opaque, UiBarTheme.Opaque,
) )
@ -54,7 +55,8 @@ class BarThemeBottomSheet : Screen {
) { ) {
for (value in values) { for (value in values) {
Row( Row(
modifier = Modifier.padding( modifier =
Modifier.padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
) )

View File

@ -37,14 +37,14 @@ class BlockBottomSheet(
private val userInstanceName: String? = null, private val userInstanceName: String? = null,
private val userInstanceId: Long? = null, private val userInstanceId: Long? = null,
) : Screen { ) : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -59,30 +59,35 @@ class BlockBottomSheet(
modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
val values: List<Triple<BlockActionType, Long, String>> = buildList { val values: List<Triple<BlockActionType, Long, String>> =
buildList {
if (userName != null && userId != null) { if (userName != null && userId != null) {
this += Triple( this +=
Triple(
BlockActionType.User, BlockActionType.User,
userId, userId,
userName, userName,
) )
} }
if (communityName != null && communityId != null) { if (communityName != null && communityId != null) {
this += Triple( this +=
Triple(
BlockActionType.Community, BlockActionType.Community,
communityId, communityId,
communityName, communityName,
) )
} }
if (instanceName != null && instanceId != null) { if (instanceName != null && instanceId != null) {
this += Triple( this +=
Triple(
BlockActionType.Instance, BlockActionType.Instance,
instanceId, instanceId,
instanceName, instanceName,
) )
} }
if (userInstanceName != null && userInstanceId != null && userInstanceName != instanceName) { if (userInstanceName != null && userInstanceId != null && userInstanceName != instanceName) {
this += Triple( this +=
Triple(
BlockActionType.Instance, BlockActionType.Instance,
userInstanceId, userInstanceId,
userInstanceName, userInstanceName,
@ -91,7 +96,8 @@ class BlockBottomSheet(
} }
for (value in values) { for (value in values) {
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
@ -99,8 +105,10 @@ class BlockBottomSheet(
.fillMaxWidth() .fillMaxWidth()
.onClick( .onClick(
onClick = { onClick = {
val event = when (value.first) { val event =
BlockActionType.Community -> NotificationCenterEvent.BlockActionSelected( when (value.first) {
BlockActionType.Community ->
NotificationCenterEvent.BlockActionSelected(
communityId = value.second, communityId = value.second,
) )
@ -109,7 +117,8 @@ class BlockBottomSheet(
instanceId = value.second, instanceId = value.second,
) )
BlockActionType.User -> NotificationCenterEvent.BlockActionSelected( BlockActionType.User ->
NotificationCenterEvent.BlockActionSelected(
userId = value.second, userId = value.second,
) )
} }
@ -119,7 +128,8 @@ class BlockBottomSheet(
), ),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
val valueText = buildString { val valueText =
buildString {
append(value.first.toReadableName()) append(value.first.toReadableName())
val additionalText = value.third val additionalText = value.third
if (additionalText.isNotEmpty()) { if (additionalText.isNotEmpty()) {

View File

@ -29,14 +29,14 @@ class CopyPostBottomSheet(
private val title: String? = null, private val title: String? = null,
private val text: String? = null, private val text: String? = null,
) : Screen { ) : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -55,7 +55,8 @@ class CopyPostBottomSheet(
val textCanBeCopied = !text.isNullOrBlank() val textCanBeCopied = !text.isNullOrBlank()
if (titleCanBeCopied) { if (titleCanBeCopied) {
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
@ -79,7 +80,8 @@ class CopyPostBottomSheet(
} }
if (textCanBeCopied) { if (textCanBeCopied) {
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
@ -101,13 +103,15 @@ class CopyPostBottomSheet(
) )
} }
if (titleCanBeCopied) { if (titleCanBeCopied) {
val textToCopy = buildString { val textToCopy =
buildString {
append(title) append(title)
append("\n") append("\n")
append(text) append(text)
} }
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,

View File

@ -34,7 +34,8 @@ enum class DurationBottomSheetType {
} }
class DurationBottomSheet( class DurationBottomSheet(
private val values: List<Duration> = listOf( private val values: List<Duration> =
listOf(
1.seconds, 1.seconds,
2.seconds, 2.seconds,
3.seconds, 3.seconds,
@ -43,13 +44,13 @@ class DurationBottomSheet(
), ),
private val type: DurationBottomSheetType = DurationBottomSheetType.ZOMBIE_MODE_INTERVAL, private val type: DurationBottomSheetType = DurationBottomSheetType.ZOMBIE_MODE_INTERVAL,
) : Screen { ) : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -59,7 +60,8 @@ class DurationBottomSheet(
), ),
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
val title = when (type) { val title =
when (type) {
DurationBottomSheetType.ZOMBIE_MODE_INTERVAL -> LocalXmlStrings.current.settingsZombieModeInterval DurationBottomSheetType.ZOMBIE_MODE_INTERVAL -> LocalXmlStrings.current.settingsZombieModeInterval
DurationBottomSheetType.INBOX_CHECK_PERIOD -> LocalXmlStrings.current.settingsInboxBackgroundCheckPeriod DurationBottomSheetType.INBOX_CHECK_PERIOD -> LocalXmlStrings.current.settingsInboxBackgroundCheckPeriod
} }
@ -70,7 +72,8 @@ class DurationBottomSheet(
) { ) {
for (value in values) { for (value in values) {
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
@ -78,7 +81,8 @@ class DurationBottomSheet(
.fillMaxWidth() .fillMaxWidth()
.onClick( .onClick(
onClick = { onClick = {
val event = when (type) { val event =
when (type) {
DurationBottomSheetType.ZOMBIE_MODE_INTERVAL -> DurationBottomSheetType.ZOMBIE_MODE_INTERVAL ->
NotificationCenterEvent.ChangeZombieInterval(value) NotificationCenterEvent.ChangeZombieInterval(value)
@ -92,7 +96,8 @@ class DurationBottomSheet(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
text = value.getPrettyDuration( text =
value.getPrettyDuration(
secondsLabel = LocalXmlStrings.current.postSecondShort, secondsLabel = LocalXmlStrings.current.postSecondShort,
minutesLabel = LocalXmlStrings.current.postMinuteShort, minutesLabel = LocalXmlStrings.current.postMinuteShort,
hoursLabel = LocalXmlStrings.current.postHourShort, hoursLabel = LocalXmlStrings.current.postHourShort,

View File

@ -64,7 +64,8 @@ fun EditFormattedInfoDialog(
}, },
) { ) {
Column( Column(
modifier = Modifier modifier =
Modifier
.imePadding() .imePadding()
.background(color = MaterialTheme.colorScheme.surface) .background(color = MaterialTheme.colorScheme.surface)
.padding(Spacing.s), .padding(Spacing.s),
@ -82,16 +83,19 @@ fun EditFormattedInfoDialog(
verticalArrangement = Arrangement.spacedBy(Spacing.xs), verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) { ) {
SectionSelector( SectionSelector(
titles = listOf( titles =
listOf(
LocalXmlStrings.current.createPostTabEditor, LocalXmlStrings.current.createPostTabEditor,
LocalXmlStrings.current.createPostTabPreview, LocalXmlStrings.current.createPostTabPreview,
), ),
currentSection = when (currentSection) { currentSection =
when (currentSection) {
CreatePostSection.Preview -> 1 CreatePostSection.Preview -> 1
else -> 0 else -> 0
}, },
onSectionSelected = { onSectionSelected = {
val section = when (it) { val section =
when (it) {
1 -> CreatePostSection.Preview 1 -> CreatePostSection.Preview
else -> CreatePostSection.Edit else -> CreatePostSection.Edit
} }
@ -101,7 +105,8 @@ fun EditFormattedInfoDialog(
if (currentSection == CreatePostSection.Edit) { if (currentSection == CreatePostSection.Edit) {
TextFormattingBar( TextFormattingBar(
modifier = Modifier.padding( modifier =
Modifier.padding(
top = Spacing.s, top = Spacing.s,
start = Spacing.s, start = Spacing.s,
end = Spacing.s, end = Spacing.s,
@ -112,10 +117,12 @@ fun EditFormattedInfoDialog(
}, },
) )
TextField( TextField(
modifier = Modifier modifier =
Modifier
.height(400.dp) .height(400.dp)
.fillMaxWidth(), .fillMaxWidth(),
colors = TextFieldDefaults.colors( colors =
TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent, focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent, disabledContainerColor = Color.Transparent,
@ -128,7 +135,8 @@ fun EditFormattedInfoDialog(
}, },
textStyle = typography.bodyMedium, textStyle = typography.bodyMedium,
value = textFieldValue, value = textFieldValue,
keyboardOptions = KeyboardOptions( keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Text, keyboardType = KeyboardType.Text,
autoCorrect = true, autoCorrect = true,
capitalization = KeyboardCapitalization.Sentences, capitalization = KeyboardCapitalization.Sentences,
@ -139,12 +147,14 @@ fun EditFormattedInfoDialog(
) )
} else { } else {
Box( Box(
modifier = Modifier modifier =
Modifier
.height(400.dp) .height(400.dp)
.fillMaxWidth(), .fillMaxWidth(),
) { ) {
PostCardBody( PostCardBody(
modifier = Modifier modifier =
Modifier
.padding(Spacing.s) .padding(Spacing.s)
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
text = textFieldValue.text, text = textFieldValue.text,

View File

@ -52,7 +52,8 @@ fun EditTextualInfoDialog(
}, },
) { ) {
Column( Column(
modifier = Modifier modifier =
Modifier
.imePadding() .imePadding()
.background(color = MaterialTheme.colorScheme.surface) .background(color = MaterialTheme.colorScheme.surface)
.padding(Spacing.s), .padding(Spacing.s),
@ -68,7 +69,8 @@ fun EditTextualInfoDialog(
TextField( TextField(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = TextFieldDefaults.colors( colors =
TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent, focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent, unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent, disabledContainerColor = Color.Transparent,
@ -81,7 +83,8 @@ fun EditTextualInfoDialog(
}, },
textStyle = typography.bodyMedium, textStyle = typography.bodyMedium,
value = textFieldValue, value = textFieldValue,
keyboardOptions = KeyboardOptions( keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Text, keyboardType = KeyboardType.Text,
autoCorrect = true, autoCorrect = true,
), ),

View File

@ -32,7 +32,8 @@ class InboxTypeSheet : Screen {
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -48,7 +49,8 @@ class InboxTypeSheet : Screen {
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
@ -71,7 +73,8 @@ class InboxTypeSheet : Screen {
) )
} }
Row( Row(
modifier = Modifier modifier =
Modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,

View File

@ -30,13 +30,13 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLanguageFlag
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLanguageName import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLanguageName
class LanguageBottomSheet : Screen { class LanguageBottomSheet : Screen {
@Composable @Composable
override fun Content() { override fun Content() {
val navigationCoordinator = remember { getNavigationCoordinator() } val navigationCoordinator = remember { getNavigationCoordinator() }
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.safeContent) .windowInsetsPadding(WindowInsets.safeContent)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -47,7 +47,8 @@ class LanguageBottomSheet : Screen {
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
BottomSheetHeader(LocalXmlStrings.current.settingsLanguage) BottomSheetHeader(LocalXmlStrings.current.settingsLanguage)
val values = listOf( val values =
listOf(
Locales.Ar, Locales.Ar,
Locales.Bg, Locales.Bg,
Locales.Cs, Locales.Cs,
@ -84,7 +85,8 @@ class LanguageBottomSheet : Screen {
Locales.Uk, Locales.Uk,
) )
Column( Column(
modifier = Modifier modifier =
Modifier
.weight(1f) .weight(1f)
.fillMaxWidth() .fillMaxWidth()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
@ -92,7 +94,8 @@ class LanguageBottomSheet : Screen {
) { ) {
for (value in values) { for (value in values) {
Row( Row(
modifier = Modifier.padding( modifier =
Modifier.padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
) )
@ -108,7 +111,8 @@ class LanguageBottomSheet : Screen {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
text = buildAnnotatedString { text =
buildAnnotatedString {
with(value) { with(value) {
append(toLanguageFlag()) append(toLanguageFlag())
append(" ") append(" ")

View File

@ -32,7 +32,8 @@ class LikedTypeSheet : Screen {
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -48,7 +49,8 @@ class LikedTypeSheet : Screen {
verticalArrangement = Arrangement.spacedBy(Spacing.xxs), verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
) { ) {
Row( Row(
modifier = Modifier modifier =
Modifier
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
@ -71,7 +73,8 @@ class LikedTypeSheet : Screen {
) )
} }
Row( Row(
modifier = Modifier modifier =
Modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
horizontal = Spacing.s, horizontal = Spacing.s,

View File

@ -41,7 +41,8 @@ class ListingTypeBottomSheet(
val notificationCenter = remember { getNotificationCenter() } val notificationCenter = remember { getNotificationCenter() }
Column( Column(
modifier = Modifier modifier =
Modifier
.windowInsetsPadding(WindowInsets.navigationBars) .windowInsetsPadding(WindowInsets.navigationBars)
.padding( .padding(
top = Spacing.s, top = Spacing.s,
@ -52,7 +53,8 @@ class ListingTypeBottomSheet(
verticalArrangement = Arrangement.spacedBy(Spacing.s), verticalArrangement = Arrangement.spacedBy(Spacing.s),
) { ) {
BottomSheetHeader(LocalXmlStrings.current.homeListingTitle) BottomSheetHeader(LocalXmlStrings.current.homeListingTitle)
val values = buildList { val values =
buildList {
if (isLogged) { if (isLogged) {
this += ListingType.Subscribed this += ListingType.Subscribed
} }
@ -65,7 +67,8 @@ class ListingTypeBottomSheet(
) { ) {
for (value in values) { for (value in values) {
Row( Row(
modifier = Modifier.padding( modifier =
Modifier.padding(
horizontal = Spacing.s, horizontal = Spacing.s,
vertical = Spacing.s, vertical = Spacing.s,
) )

Some files were not shown because too many files have changed in this diff Show More