Merge branch 'develop' into feature/fga/update_rust_sdk
This commit is contained in:
commit
8bca19a3fa
341 changed files with 9655 additions and 2495 deletions
|
|
@ -39,7 +39,8 @@ sealed interface Async<out T> {
|
|||
suspend fun <T> (suspend () -> T).execute(state: MutableState<Async<T>>) {
|
||||
try {
|
||||
state.value = Async.Loading()
|
||||
state.value = Async.Success(this())
|
||||
val result = this()
|
||||
state.value = Async.Success(result)
|
||||
} catch (error: Throwable) {
|
||||
state.value = Async.Failure(error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ class StableCharSequence(val charSequence: CharSequence) {
|
|||
|
||||
override fun hashCode() = hash
|
||||
override fun equals(other: Any?) = other is StableCharSequence && other.hash == hash
|
||||
|
||||
override fun toString(): String = "StableCharSequence(\"$charSequence\")"
|
||||
}
|
||||
|
||||
fun CharSequence.toStableCharSequence() = StableCharSequence(this)
|
||||
|
|
|
|||
1
libraries/dateformatter/.gitignore
vendored
Normal file
1
libraries/dateformatter/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
43
libraries/dateformatter/build.gradle.kts
Normal file
43
libraries/dateformatter/build.gradle.kts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
|
||||
@Suppress("DSL_SCOPE_VIOLATION")
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.anvil)
|
||||
}
|
||||
|
||||
anvil {
|
||||
generateDaggerFactories.set(true)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.dateformatter"
|
||||
|
||||
dependencies {
|
||||
anvil(projects.anvilcodegen)
|
||||
implementation(libs.dagger)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(projects.anvilannotations)
|
||||
api(libs.datetime)
|
||||
ksp(libs.showkase.processor)
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.test.truth)
|
||||
}
|
||||
}
|
||||
0
libraries/dateformatter/consumer-rules.pro
Normal file
0
libraries/dateformatter/consumer-rules.pro
Normal file
21
libraries/dateformatter/proguard-rules.pro
vendored
Normal file
21
libraries/dateformatter/proguard-rules.pro
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
16
libraries/dateformatter/src/main/AndroidManifest.xml
Normal file
16
libraries/dateformatter/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2023 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<manifest />
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter
|
||||
|
||||
interface LastMessageFormatter {
|
||||
fun format(timestamp: Long?): String
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.TimeZone
|
||||
import java.util.*
|
||||
|
||||
@Module
|
||||
@ContributesTo(AppScope::class)
|
||||
object DateFormatterModule {
|
||||
@Provides
|
||||
fun providesClock(): Clock = Clock.System
|
||||
|
||||
@Provides
|
||||
fun providesLocale(): Locale = Locale.getDefault()
|
||||
|
||||
@Provides
|
||||
fun providesTimezone(): TimeZone = TimeZone.currentSystemDefault()
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import android.text.format.DateFormat
|
||||
import android.text.format.DateUtils
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toInstant
|
||||
import kotlinx.datetime.toJavaLocalDate
|
||||
import kotlinx.datetime.toJavaLocalDateTime
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import java.time.Period
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultLastMessageFormatter @Inject constructor(
|
||||
private val clock: Clock,
|
||||
private val locale: Locale,
|
||||
private val timezone: TimeZone,
|
||||
) : LastMessageFormatter {
|
||||
private val onlyTimeFormatter: DateTimeFormatter by lazy {
|
||||
val pattern = DateFormat.getBestDateTimePattern(locale, "HH:mm") ?: "HH:mm"
|
||||
DateTimeFormatter.ofPattern(pattern)
|
||||
}
|
||||
|
||||
private val dateWithMonthFormatter: DateTimeFormatter by lazy {
|
||||
val pattern = DateFormat.getBestDateTimePattern(locale, "d MMM") ?: "d MMM"
|
||||
DateTimeFormatter.ofPattern(pattern)
|
||||
}
|
||||
|
||||
private val dateWithYearFormatter: DateTimeFormatter by lazy {
|
||||
val pattern = DateFormat.getBestDateTimePattern(locale, "dd.MM.yyyy") ?: "dd.MM.yyyy"
|
||||
DateTimeFormatter.ofPattern(pattern)
|
||||
}
|
||||
|
||||
override fun format(timestamp: Long?): String {
|
||||
if (timestamp == null) return ""
|
||||
val now: Instant = clock.now()
|
||||
val tsInstant = Instant.fromEpochMilliseconds(timestamp)
|
||||
val nowDateTime = now.toLocalDateTime(timezone)
|
||||
val tsDateTime = tsInstant.toLocalDateTime(timezone)
|
||||
val isSameDay = nowDateTime.date == tsDateTime.date
|
||||
return when {
|
||||
isSameDay -> {
|
||||
onlyTimeFormatter.format(tsDateTime.toJavaLocalDateTime())
|
||||
}
|
||||
else -> {
|
||||
formatDate(tsDateTime, nowDateTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatDate(
|
||||
date: LocalDateTime,
|
||||
currentDate: LocalDateTime,
|
||||
): String {
|
||||
val period = Period.between(date.date.toJavaLocalDate(), currentDate.date.toJavaLocalDate())
|
||||
return if (period.years.absoluteValue >= 1) {
|
||||
formatDateWithYear(date)
|
||||
} else if (period.days.absoluteValue < 2 && period.months.absoluteValue < 1) {
|
||||
getRelativeDay(date.toInstant(timezone).toEpochMilliseconds())
|
||||
} else {
|
||||
formatDateWithMonth(date)
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatDateWithMonth(localDateTime: LocalDateTime): String {
|
||||
return dateWithMonthFormatter.format(localDateTime.toJavaLocalDateTime())
|
||||
}
|
||||
|
||||
private fun formatDateWithYear(localDateTime: LocalDateTime): String {
|
||||
return dateWithYearFormatter.format(localDateTime.toJavaLocalDateTime())
|
||||
}
|
||||
|
||||
private fun getRelativeDay(ts: Long): String {
|
||||
return DateUtils.getRelativeTimeSpanString(
|
||||
ts,
|
||||
clock.now().toEpochMilliseconds(),
|
||||
DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.FORMAT_SHOW_WEEKDAY
|
||||
)?.toString() ?: ""
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.TimeZone
|
||||
import org.junit.Test
|
||||
import java.util.Locale
|
||||
|
||||
class DefaultLastMessageFormatterTest {
|
||||
|
||||
@Test
|
||||
fun `test null`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(null)).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test epoch`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(0)).isEqualTo("01.01.1970")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test now`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1980-04-06T18:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:35")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test one second before`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1980-04-06T18:35:23.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:35")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test one minute before`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1980-04-06T18:34:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("18:34")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test one hour before`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1980-04-06T17:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("17:35")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test one day before same time`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1980-04-05T18:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
// TODO DateUtils.getRelativeTimeSpanString returns null.
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test one month before same time`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1980-03-06T18:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("6 Mar")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test one year before same time`() {
|
||||
val now = "1980-04-06T18:35:24.00Z"
|
||||
val dat = "1979-04-06T18:35:24.00Z"
|
||||
val formatter = createFormatter(now)
|
||||
assertThat(formatter.format(Instant.parse(dat).toEpochMilliseconds())).isEqualTo("06.04.1979")
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DefaultLastMessageFormatter and set current time to the provided date.
|
||||
*/
|
||||
private fun createFormatter(@Suppress("SameParameterValue") currentDate: String): LastMessageFormatter {
|
||||
val clock = FakeClock().also { it.givenInstant(Instant.parse(currentDate)) }
|
||||
return DefaultLastMessageFormatter(clock, Locale.US, TimeZone.UTC)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -14,20 +14,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.components
|
||||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
@Composable
|
||||
fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(text = text)
|
||||
class FakeClock : Clock {
|
||||
private var instant: Instant = Instant.fromEpochMilliseconds(0)
|
||||
|
||||
fun givenInstant(instant: Instant) {
|
||||
this.instant = instant
|
||||
}
|
||||
|
||||
override fun now(): Instant = instant
|
||||
}
|
||||
|
|
@ -52,10 +52,4 @@ val ElementGreen = Color(0xFF0DBD8B)
|
|||
val ElementOrange = Color(0xFFD9B072)
|
||||
val Vermilion = Color(0xFFFF5B55)
|
||||
|
||||
// TODO Update color
|
||||
val MessageHighlightLight = Azure
|
||||
|
||||
// TODO Update color
|
||||
val MessageHighlightDark = Azure
|
||||
|
||||
val LinkColor = Color(0xFF054F6E)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ fun Boolean.toEnabledColor(): Color {
|
|||
return if (this) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
MaterialTheme.colorScheme.secondary
|
||||
MaterialTheme.colorScheme.primary.copy(alpha = 0.40f)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,55 +16,13 @@
|
|||
|
||||
package io.element.android.libraries.designsystem
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.airbnb.android.showkase.annotation.ShowkaseTypography
|
||||
|
||||
@ShowkaseTypography(name = "Body Large", group = "Element")
|
||||
val bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "Headline Small", group = "Element")
|
||||
val headlineSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = bodyLarge,
|
||||
headlineSmall = headlineSmall,
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
|
||||
// TODO Remove
|
||||
object ElementTextStyles {
|
||||
|
||||
object Bold {
|
||||
|
|
@ -21,7 +21,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
|||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.platform.LocalUriHandler
|
|||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.TextLayoutResult
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
|
||||
|
|
@ -83,6 +84,7 @@ fun ClickableLinkText(
|
|||
onTextLayout = {
|
||||
layoutResult.value = it
|
||||
},
|
||||
inlineContent = inlineContent
|
||||
inlineContent = inlineContent,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,15 @@ package io.element.android.libraries.designsystem.components
|
|||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
@Composable
|
||||
fun LabelledCheckbox(
|
||||
|
|
@ -42,13 +45,23 @@ fun LabelledCheckbox(
|
|||
onCheckedChange = onCheckedChange,
|
||||
enabled = enabled,
|
||||
)
|
||||
Text(text = text)
|
||||
Text(
|
||||
text = text,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun LabelledCheckboxPreview() {
|
||||
fun LabelledCheckboxLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun LabelledCheckboxDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
LabelledCheckbox(
|
||||
checked = true,
|
||||
text = "Some text",
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -32,6 +30,10 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
@Composable
|
||||
fun ProgressDialog(
|
||||
|
|
@ -48,19 +50,19 @@ fun ProgressDialog(
|
|||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
if (!text.isNullOrBlank()) {
|
||||
Text(
|
||||
text = text,
|
||||
color = MaterialTheme.colorScheme.background,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
}
|
||||
|
|
@ -69,8 +71,15 @@ fun ProgressDialog(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun ProgressDialogPreview() {
|
||||
@Composable
|
||||
fun ProgressDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ProgressDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ProgressDialog(text = "test dialog content")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.components
|
||||
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -29,7 +28,7 @@ fun VectorIcon(
|
|||
modifier: Modifier = Modifier,
|
||||
tint: Color = LocalContentColor.current,
|
||||
) {
|
||||
Icon(
|
||||
androidx.compose.material3.Icon(
|
||||
painter = painterResource(id = resourceId),
|
||||
contentDescription = null,
|
||||
modifier = modifier,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import androidx.compose.foundation.background
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -34,6 +33,9 @@ import androidx.compose.ui.unit.sp
|
|||
import coil.compose.AsyncImage
|
||||
import io.element.android.libraries.designsystem.AvatarGradientEnd
|
||||
import io.element.android.libraries.designsystem.AvatarGradientStart
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
|
|
@ -97,6 +99,13 @@ private fun InitialsAvatar(
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
fun InitialsAvatarPreview() {
|
||||
fun AvatarLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AvatarDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Avatar(AvatarData(name = "A"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,20 @@ import androidx.compose.foundation.layout.Row
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
|
|
@ -43,6 +50,12 @@ fun ConfirmationDialog(
|
|||
onCancelClicked: () -> Unit = {},
|
||||
onThirdButtonClicked: () -> Unit = {},
|
||||
onDismiss: () -> Unit = {},
|
||||
shape: Shape = AlertDialogDefaults.shape,
|
||||
containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
iconContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
titleContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
) {
|
||||
AlertDialog(
|
||||
modifier = modifier,
|
||||
|
|
@ -93,12 +106,25 @@ fun ConfirmationDialog(
|
|||
}
|
||||
}
|
||||
},
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun ConfirmationDialogPreview() {
|
||||
@Composable
|
||||
fun ConfirmationDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ConfirmationDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ConfirmationDialog(
|
||||
title = "Title",
|
||||
content = "Content",
|
||||
|
|
|
|||
|
|
@ -21,13 +21,20 @@ import androidx.compose.foundation.layout.Row
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
|
|
@ -37,6 +44,12 @@ fun ErrorDialog(
|
|||
title: String = stringResource(id = StringR.string.dialog_title_error),
|
||||
submitText: String = stringResource(id = StringR.string.ok),
|
||||
onDismiss: () -> Unit = {},
|
||||
shape: Shape = AlertDialogDefaults.shape,
|
||||
containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
iconContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
titleContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
) {
|
||||
AlertDialog(
|
||||
modifier = modifier,
|
||||
|
|
@ -62,12 +75,25 @@ fun ErrorDialog(
|
|||
}
|
||||
}
|
||||
},
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun ErrorDialogPreview() {
|
||||
@Composable
|
||||
fun ErrorDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ErrorDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ErrorDialog(
|
||||
content = "Content",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,13 +20,18 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Announcement
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Divider
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
@Composable
|
||||
fun PreferenceCategory(
|
||||
|
|
@ -46,20 +51,39 @@ fun PreferenceCategory(
|
|||
Text(
|
||||
modifier = Modifier.padding(top = 8.dp, start = 56.dp),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
text = title
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
text = title,
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PreferenceCategoryPreview() {
|
||||
@Composable
|
||||
fun PreferenceCategoryLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferenceCategoryDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
PreferenceCategory(
|
||||
title = "Category title",
|
||||
) {
|
||||
PreferenceTextPreview()
|
||||
PreferenceSwitchPreview()
|
||||
PreferenceSlidePreview()
|
||||
PreferenceText(
|
||||
title = "Title",
|
||||
icon = Icons.Default.BugReport,
|
||||
)
|
||||
PreferenceSwitch(
|
||||
title = "Switch",
|
||||
icon = Icons.Default.Announcement,
|
||||
isChecked = true
|
||||
)
|
||||
PreferenceSlide(
|
||||
title = "Slide",
|
||||
summary = "Summary",
|
||||
value = 0.75F
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,10 @@ import androidx.compose.foundation.layout.systemBarsPadding
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Announcement
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -42,6 +39,13 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.sp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -110,12 +114,36 @@ fun PreferenceTopAppBar(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PreferenceScreenPreview() {
|
||||
@Composable
|
||||
fun PreferenceViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferenceViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
PreferenceView(
|
||||
title = "Preference screen"
|
||||
) {
|
||||
PreferenceCategoryPreview()
|
||||
PreferenceCategory(
|
||||
title = "Category title",
|
||||
) {
|
||||
PreferenceText(
|
||||
title = "Title",
|
||||
icon = Icons.Default.BugReport,
|
||||
)
|
||||
PreferenceSwitch(
|
||||
title = "Switch",
|
||||
icon = Icons.Default.Announcement,
|
||||
isChecked = true
|
||||
)
|
||||
PreferenceSlide(
|
||||
title = "Slide",
|
||||
summary = "Summary",
|
||||
value = 0.75F
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,16 @@ import androidx.compose.foundation.layout.defaultMinSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Slider
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.toEnabledColor
|
||||
|
||||
@Composable
|
||||
|
|
@ -84,9 +86,16 @@ fun PreferenceSlide(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PreferenceSlidePreview() {
|
||||
@Composable
|
||||
fun PreferenceSlideLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferenceSlideDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
PreferenceSlide(
|
||||
title = "Slide",
|
||||
summary = "Summary",
|
||||
|
|
|
|||
|
|
@ -24,15 +24,17 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Announcement
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.toEnabledColor
|
||||
|
||||
@Composable
|
||||
|
|
@ -75,12 +77,20 @@ fun PreferenceSwitch(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PreferenceSwitchPreview() {
|
||||
@Composable
|
||||
fun PreferenceSwitchLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferenceSwitchDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
PreferenceSwitch(
|
||||
title = "Switch",
|
||||
icon = Icons.Default.Announcement,
|
||||
enabled = true,
|
||||
isChecked = true
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,15 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
@Composable
|
||||
fun PreferenceText(
|
||||
|
|
@ -57,15 +59,23 @@ fun PreferenceText(
|
|||
.weight(1f)
|
||||
.padding(end = preferencePaddingEnd),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
text = title
|
||||
text = title,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PreferenceTextPreview() {
|
||||
@Composable
|
||||
fun PreferenceTextLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferenceTextDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
PreferenceText(
|
||||
title = "Title",
|
||||
icon = Icons.Default.BugReport,
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ package io.element.android.libraries.designsystem.components.preferences.compone
|
|||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.toEnabledColor
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.preview
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||
|
||||
@Composable
|
||||
fun ElementPreviewLight(
|
||||
showBackground: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
ElementPreview(
|
||||
darkTheme = false,
|
||||
showBackground = showBackground,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ElementPreviewDark(
|
||||
showBackground: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
ElementPreview(
|
||||
darkTheme = true,
|
||||
showBackground = showBackground,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ElementPreview(
|
||||
darkTheme: Boolean,
|
||||
showBackground: Boolean,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
ElementTheme(darkTheme = darkTheme) {
|
||||
if (showBackground) {
|
||||
Box(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
||||
content()
|
||||
}
|
||||
} else {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.SystemGrey4Dark
|
||||
import io.element.android.libraries.designsystem.SystemGrey6Light
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.previews.ColorListPreview
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
|
||||
/**
|
||||
* Room list.
|
||||
*/
|
||||
@Composable
|
||||
fun MaterialTheme.roomListRoomName() = colorScheme.primary
|
||||
|
||||
@Composable
|
||||
fun MaterialTheme.roomListRoomMessage() = colorScheme.secondary
|
||||
|
||||
@Composable
|
||||
fun MaterialTheme.roomListRoomMessageDate() = colorScheme.secondary
|
||||
|
||||
@Composable
|
||||
fun MaterialTheme.roomListUnreadIndicator() = colorScheme.primary
|
||||
|
||||
@Composable
|
||||
fun ElementColors.roomListPlaceHolder() = if (isLight) SystemGrey6Light else SystemGrey4Dark
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ColorAliasesLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ColorAliasesDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ColorListPreview(
|
||||
backgroundColor = Color.Black,
|
||||
foregroundColor = Color.White,
|
||||
colors = persistentMapOf(
|
||||
"roomListRoomName" to MaterialTheme.roomListRoomName(),
|
||||
"roomListRoomMessage" to MaterialTheme.roomListRoomMessage(),
|
||||
"roomListRoomMessageDate" to MaterialTheme.roomListRoomMessageDate(),
|
||||
"roomListUnreadIndicator" to MaterialTheme.roomListUnreadIndicator(),
|
||||
"roomListPlaceHolder" to ElementTheme.colors.roomListPlaceHolder(),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.Azure
|
||||
import io.element.android.libraries.designsystem.DarkGrey
|
||||
import io.element.android.libraries.designsystem.SystemGrey5Dark
|
||||
import io.element.android.libraries.designsystem.SystemGrey6Dark
|
||||
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
|
||||
|
||||
fun elementColorsDark() = ElementColors(
|
||||
messageFromMeBackground = SystemGrey5Dark,
|
||||
messageFromOtherBackground = SystemGrey6Dark,
|
||||
messageHighlightedBackground = Azure,
|
||||
isLight = false,
|
||||
)
|
||||
|
||||
// TODO Lots of colors are missing
|
||||
val materialColorSchemeDark = darkColorScheme(
|
||||
primary = Color.White,
|
||||
// TODO onPrimary = ColorDarkTokens.OnPrimary,
|
||||
// TODO primaryContainer = ColorDarkTokens.PrimaryContainer,
|
||||
// TODO onPrimaryContainer = ColorDarkTokens.OnPrimaryContainer,
|
||||
// TODO inversePrimary = ColorDarkTokens.InversePrimary,
|
||||
secondary = DarkGrey,
|
||||
// TODO onSecondary = ColorDarkTokens.OnSecondary,
|
||||
// TODO secondaryContainer = ColorDarkTokens.SecondaryContainer,
|
||||
// TODO onSecondaryContainer = ColorDarkTokens.OnSecondaryContainer,
|
||||
tertiary = Color.White,
|
||||
// TODO onTertiary = ColorDarkTokens.OnTertiary,
|
||||
// TODO tertiaryContainer = ColorDarkTokens.TertiaryContainer,
|
||||
// TODO onTertiaryContainer = ColorDarkTokens.OnTertiaryContainer,
|
||||
background = Color.Black,
|
||||
onBackground = Color.White,
|
||||
surface = Color.Black,
|
||||
onSurface = Color.White,
|
||||
surfaceVariant = SystemGrey5Dark,
|
||||
// TODO onSurfaceVariant = ColorDarkTokens.OnSurfaceVariant,
|
||||
// TODO surfaceTint = primary,
|
||||
// TODO inverseSurface = ColorDarkTokens.InverseSurface,
|
||||
// TODO inverseOnSurface = ColorDarkTokens.InverseOnSurface,
|
||||
// TODO error = ColorDarkTokens.Error,
|
||||
// TODO onError = ColorDarkTokens.OnError,
|
||||
// TODO errorContainer = ColorDarkTokens.ErrorContainer,
|
||||
// TODO onErrorContainer = ColorDarkTokens.OnErrorContainer,
|
||||
// TODO outline = ColorDarkTokens.Outline,
|
||||
// TODO outlineVariant = ColorDarkTokens.OutlineVariant,
|
||||
// TODO scrim = ColorDarkTokens.Scrim,
|
||||
)
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ColorsSchemePreviewDark() = ColorsSchemePreview(
|
||||
Color.White,
|
||||
Color.Black,
|
||||
materialColorSchemeDark,
|
||||
)
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.Azure
|
||||
import io.element.android.libraries.designsystem.LightGrey
|
||||
import io.element.android.libraries.designsystem.SystemGrey5Light
|
||||
import io.element.android.libraries.designsystem.SystemGrey6Light
|
||||
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
|
||||
|
||||
fun elementColorsLight() = ElementColors(
|
||||
messageFromMeBackground = SystemGrey5Light,
|
||||
messageFromOtherBackground = SystemGrey6Light,
|
||||
messageHighlightedBackground = Azure,
|
||||
isLight = true,
|
||||
)
|
||||
|
||||
// TODO Lots of colors are missing
|
||||
val materialColorSchemeLight = lightColorScheme(
|
||||
primary = Color.Black,
|
||||
// TODO onPrimary = ColorLightTokens.OnPrimary,
|
||||
// TODO primaryContainer = ColorLightTokens.PrimaryContainer,
|
||||
// TODO onPrimaryContainer = ColorLightTokens.OnPrimaryContainer,
|
||||
// TODO inversePrimary = ColorLightTokens.InversePrimary,
|
||||
secondary = LightGrey,
|
||||
// TODO onSecondary = ColorLightTokens.OnSecondary,
|
||||
// TODO secondaryContainer = ColorLightTokens.SecondaryContainer,
|
||||
// TODO onSecondaryContainer = ColorLightTokens.OnSecondaryContainer,
|
||||
tertiary = Color.Black,
|
||||
// TODO onTertiary = ColorLightTokens.OnTertiary,
|
||||
// TODO tertiaryContainer = ColorLightTokens.TertiaryContainer,
|
||||
// TODO onTertiaryContainer = ColorLightTokens.OnTertiaryContainer,
|
||||
background = Color.White,
|
||||
onBackground = Color.Black,
|
||||
surface = Color.White,
|
||||
onSurface = Color.Black,
|
||||
surfaceVariant = SystemGrey5Light,
|
||||
onSurfaceVariant = Color.Black,
|
||||
// TODO surfaceTint = primary,
|
||||
// TODO inverseSurface = ColorLightTokens.InverseSurface,
|
||||
// TODO inverseOnSurface = ColorLightTokens.InverseOnSurface,
|
||||
// TODO error = ColorLightTokens.Error,
|
||||
// TODO onError = ColorLightTokens.OnError,
|
||||
// TODO errorContainer = ColorLightTokens.ErrorContainer,
|
||||
// TODO onErrorContainer = ColorLightTokens.OnErrorContainer,
|
||||
// TODO outline = ColorLightTokens.Outline,
|
||||
// TODO outlineVariant = ColorLightTokens.OutlineVariant,
|
||||
// TODO scrim = ColorLightTokens.Scrim,
|
||||
)
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ColorsSchemePreviewLight() = ColorsSchemePreview(
|
||||
Color.Black,
|
||||
Color.White,
|
||||
materialColorSchemeLight,
|
||||
)
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
class ElementColors(
|
||||
messageFromMeBackground: Color,
|
||||
messageFromOtherBackground: Color,
|
||||
messageHighlightedBackground: Color,
|
||||
isLight: Boolean,
|
||||
) {
|
||||
var messageFromMeBackground by mutableStateOf(messageFromMeBackground)
|
||||
private set
|
||||
var messageFromOtherBackground by mutableStateOf(messageFromOtherBackground)
|
||||
private set
|
||||
var messageHighlightedBackground by mutableStateOf(messageHighlightedBackground)
|
||||
private set
|
||||
|
||||
var isLight by mutableStateOf(isLight)
|
||||
private set
|
||||
|
||||
fun copy(
|
||||
messageFromMeBackground: Color = this.messageFromMeBackground,
|
||||
messageFromOtherBackground: Color = this.messageFromOtherBackground,
|
||||
messageHighlightedBackground: Color = this.messageHighlightedBackground,
|
||||
isLight: Boolean = this.isLight,
|
||||
) = ElementColors(
|
||||
messageFromMeBackground = messageFromMeBackground,
|
||||
messageFromOtherBackground = messageFromOtherBackground,
|
||||
messageHighlightedBackground = messageHighlightedBackground,
|
||||
isLight = isLight,
|
||||
)
|
||||
|
||||
fun updateColorsFrom(other: ElementColors) {
|
||||
messageFromMeBackground = other.messageFromMeBackground
|
||||
messageFromOtherBackground = other.messageFromOtherBackground
|
||||
messageHighlightedBackground = other.messageHighlightedBackground
|
||||
isLight = other.isLight
|
||||
}
|
||||
}
|
||||
|
|
@ -14,77 +14,58 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Color.White,
|
||||
secondary = DarkGrey,
|
||||
tertiary = Color.White,
|
||||
background = Color.Black,
|
||||
onBackground = Color.White,
|
||||
surface = Color.Black,
|
||||
surfaceVariant = SystemGrey5Dark,
|
||||
onSurface = Color.White,
|
||||
onSurfaceVariant = Color.White,
|
||||
)
|
||||
/**
|
||||
* Inspired from https://medium.com/@lucasyujideveloper/54cbcbde1ace
|
||||
*/
|
||||
object ElementTheme {
|
||||
val colors: ElementColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalColors.current
|
||||
}
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Color.Black,
|
||||
secondary = LightGrey,
|
||||
tertiary = Color.Black,
|
||||
background = Color.White,
|
||||
onBackground = Color.Black,
|
||||
surface = Color.White,
|
||||
surfaceVariant = SystemGrey5Light,
|
||||
onSurface = Color.Black,
|
||||
onSurfaceVariant = Color.Black,
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
@Suppress("CompositionLocalAllowlist")
|
||||
val LocalIsDarkTheme = compositionLocalOf<Boolean> { error("Not defined") }
|
||||
/* Global variables (application level) */
|
||||
val LocalColors = staticCompositionLocalOf { elementColorsLight() }
|
||||
|
||||
@Composable
|
||||
fun ElementXTheme(
|
||||
fun ElementTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = false,
|
||||
content: @Composable () -> Unit
|
||||
dynamicColor: Boolean = false, /* true to enable MaterialYou */
|
||||
lightColors: ElementColors = elementColorsLight(),
|
||||
darkColors: ElementColors = elementColorsDark(),
|
||||
materialLightColors: ColorScheme = materialColorSchemeLight,
|
||||
materialDarkColors: ColorScheme = materialColorSchemeDark,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val useDarkIcons = !darkTheme
|
||||
val currentColor = remember { if (darkTheme) darkColors else lightColors }
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
darkTheme -> materialDarkColors
|
||||
else -> materialLightColors
|
||||
}
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val useDarkIcons = !darkTheme
|
||||
|
||||
SideEffect {
|
||||
systemUiController.setStatusBarColor(
|
||||
color = colorScheme.background
|
||||
|
|
@ -94,11 +75,13 @@ fun ElementXTheme(
|
|||
darkIcons = useDarkIcons
|
||||
)
|
||||
}
|
||||
|
||||
CompositionLocalProvider(LocalIsDarkTheme provides darkTheme) {
|
||||
val rememberedColors = remember { currentColor.copy() }.apply { updateColorsFrom(currentColor) }
|
||||
CompositionLocalProvider(
|
||||
LocalColors provides rememberedColors,
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
// TODO typography =
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.airbnb.android.showkase.annotation.ShowkaseTypography
|
||||
|
||||
/**
|
||||
* TODO Provide the typo to Material3 theme.
|
||||
*/
|
||||
@ShowkaseTypography(name = "H1", group = "Element")
|
||||
val h1Default: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.SansSerif,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 24.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "Body1", group = "Element")
|
||||
val body1Default: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.SansSerif,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "BodySmall", group = "Element")
|
||||
val bodySmallDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.SansSerif,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "bodyMedium", group = "Element")
|
||||
val bodyMediumDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.SansSerif,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "Body Large", group = "Element")
|
||||
val bodyLargeDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "Headline Small", group = "Element")
|
||||
val headlineSmallDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 24.sp,
|
||||
lineHeight = 30.sp,
|
||||
letterSpacing = 1.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "Headline Medium", group = "Element")
|
||||
val headlineMediumDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 34.sp,
|
||||
letterSpacing = 1.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "Headline Large", group = "Element")
|
||||
val headlineLargeDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 38.sp,
|
||||
letterSpacing = 1.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "titleSmall", group = "Element")
|
||||
val titleSmallDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
|
||||
@ShowkaseTypography(name = "titleMedium", group = "Element")
|
||||
val titleMediumDefault: TextStyle = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 18.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ButtonElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
|
||||
@Composable
|
||||
fun Button(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
shape: Shape = ButtonDefaults.shape,
|
||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
||||
border: BorderStroke? = null,
|
||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
content: @Composable RowScope.() -> Unit
|
||||
) {
|
||||
androidx.compose.material3.Button(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
elevation = elevation,
|
||||
border = border,
|
||||
contentPadding = contentPadding,
|
||||
interactionSource = interactionSource,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ButtonsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ButtonsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Column {
|
||||
Button(onClick = {}, enabled = true) {
|
||||
Text(text = "Click me! - Enabled")
|
||||
}
|
||||
Button(onClick = {}, enabled = false) {
|
||||
Text(text = "Click me! - Disabled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.CheckboxColors
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
|
||||
@Composable
|
||||
fun Checkbox(
|
||||
checked: Boolean,
|
||||
onCheckedChange: ((Boolean) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
colors: CheckboxColors = CheckboxDefaults.colors(),
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
androidx.compose.material3.Checkbox(
|
||||
checked = checked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
colors = colors,
|
||||
interactionSource = interactionSource,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CheckboxesLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CheckboxesDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Column {
|
||||
Checkbox(onCheckedChange = {}, enabled = true, checked = true)
|
||||
Checkbox(onCheckedChange = {}, enabled = true, checked = false)
|
||||
Checkbox(onCheckedChange = {}, enabled = false, checked = true)
|
||||
Checkbox(onCheckedChange = {}, enabled = false, checked = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
@Composable
|
||||
fun CircularProgressIndicator(
|
||||
progress: Float,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = ProgressIndicatorDefaults.circularColor,
|
||||
strokeWidth: Dp = ProgressIndicatorDefaults.CircularStrokeWidth
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = modifier,
|
||||
progress = progress,
|
||||
color = color,
|
||||
strokeWidth = strokeWidth,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CircularProgressIndicator(
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = ProgressIndicatorDefaults.circularColor,
|
||||
strokeWidth: Dp = ProgressIndicatorDefaults.CircularStrokeWidth,
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = modifier,
|
||||
color = color,
|
||||
strokeWidth = strokeWidth,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.material3.DividerDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
|
||||
@Composable
|
||||
fun Divider(
|
||||
modifier: Modifier = Modifier,
|
||||
thickness: Dp = DividerDefaults.Thickness,
|
||||
color: Color = DividerDefaults.color,
|
||||
) {
|
||||
androidx.compose.material3.Divider(
|
||||
modifier = modifier,
|
||||
thickness = thickness,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun DividerLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun DividerDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Divider()
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.FloatingActionButtonElevation
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
|
||||
@Composable
|
||||
fun FloatingActionButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
shape: Shape = FloatingActionButtonDefaults.shape,
|
||||
containerColor: Color = FloatingActionButtonDefaults.containerColor,
|
||||
contentColor: Color = contentColorFor(containerColor),
|
||||
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
androidx.compose.material3.FloatingActionButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
elevation = elevation,
|
||||
interactionSource = interactionSource,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
@Composable
|
||||
fun Icon(
|
||||
imageVector: ImageVector,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = LocalContentColor.current
|
||||
) {
|
||||
androidx.compose.material3.Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Icon(
|
||||
bitmap: ImageBitmap,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = LocalContentColor.current
|
||||
) {
|
||||
androidx.compose.material3.Icon(
|
||||
bitmap = bitmap,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun IconButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
androidx.compose.material3.IconButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
colors = IconButtonDefaults.iconButtonColors(),
|
||||
interactionSource = interactionSource,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MediumTopAppBar(
|
||||
title: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
navigationIcon: @Composable () -> Unit = {},
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
|
||||
colors: TopAppBarColors = TopAppBarDefaults.mediumTopAppBarColors(),
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||
) {
|
||||
androidx.compose.material3.MediumTopAppBar(
|
||||
title = title,
|
||||
modifier = modifier,
|
||||
navigationIcon = navigationIcon,
|
||||
actions = actions,
|
||||
windowInsets = windowInsets,
|
||||
colors = colors,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.ModalBottomSheetDefaults
|
||||
import androidx.compose.material.ModalBottomSheetState
|
||||
import androidx.compose.material.ModalBottomSheetValue
|
||||
import androidx.compose.material.contentColorFor
|
||||
import androidx.compose.material.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun ModalBottomSheetLayout(
|
||||
sheetContent: @Composable ColumnScope.() -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
sheetState: ModalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
|
||||
sheetShape: Shape = MaterialTheme.shapes.large,
|
||||
sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
|
||||
sheetBackgroundColor: Color = MaterialTheme.colors.surface,
|
||||
sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
|
||||
scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
|
||||
content: @Composable () -> Unit = {}
|
||||
) {
|
||||
androidx.compose.material.ModalBottomSheetLayout(
|
||||
sheetContent = sheetContent,
|
||||
modifier = modifier,
|
||||
sheetState = sheetState,
|
||||
sheetShape = sheetShape,
|
||||
sheetElevation = sheetElevation,
|
||||
sheetBackgroundColor = sheetBackgroundColor,
|
||||
sheetContentColor = sheetContentColor,
|
||||
scrimColor = scrimColor,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.TextFieldColors
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun OutlinedTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
readOnly: Boolean = false,
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
label: @Composable (() -> Unit)? = null,
|
||||
placeholder: @Composable (() -> Unit)? = null,
|
||||
leadingIcon: @Composable (() -> Unit)? = null,
|
||||
trailingIcon: @Composable (() -> Unit)? = null,
|
||||
supportingText: @Composable (() -> Unit)? = null,
|
||||
isError: Boolean = false,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
shape: Shape = TextFieldDefaults.outlinedShape,
|
||||
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
|
||||
) {
|
||||
androidx.compose.material3.OutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
readOnly = readOnly,
|
||||
textStyle = textStyle,
|
||||
label = label,
|
||||
placeholder = placeholder,
|
||||
leadingIcon = leadingIcon,
|
||||
trailingIcon = trailingIcon,
|
||||
supportingText = supportingText,
|
||||
isError = isError,
|
||||
visualTransformation = visualTransformation,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
singleLine = singleLine,
|
||||
maxLines = maxLines,
|
||||
interactionSource = interactionSource,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun OutlinedTextFieldsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun OutlinedTextFieldsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Column {
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = true, readOnly = true)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = true, readOnly = false)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = false, readOnly = true)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = false, readOnly = false)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = true, readOnly = true)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = true, readOnly = false)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = false, readOnly = true)
|
||||
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = false, readOnly = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Scaffold(
|
||||
modifier: Modifier = Modifier,
|
||||
topBar: @Composable () -> Unit = {},
|
||||
bottomBar: @Composable () -> Unit = {},
|
||||
snackbarHost: @Composable () -> Unit = {},
|
||||
floatingActionButton: @Composable () -> Unit = {},
|
||||
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
||||
containerColor: Color = MaterialTheme.colorScheme.background,
|
||||
contentColor: Color = contentColorFor(containerColor),
|
||||
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
|
||||
content: @Composable (PaddingValues) -> Unit
|
||||
) {
|
||||
androidx.compose.material3.Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = topBar,
|
||||
bottomBar = bottomBar,
|
||||
snackbarHost = snackbarHost,
|
||||
floatingActionButton = floatingActionButton,
|
||||
floatingActionButtonPosition = floatingActionButtonPosition,
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
contentWindowInsets = contentWindowInsets,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.SliderColors
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
|
||||
@Composable
|
||||
fun Slider(
|
||||
value: Float,
|
||||
onValueChange: (Float) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
|
||||
/*@IntRange(from = 0)*/
|
||||
steps: Int = 0,
|
||||
onValueChangeFinished: (() -> Unit)? = null,
|
||||
colors: SliderColors = SliderDefaults.colors(),
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
androidx.compose.material3.Slider(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
valueRange = valueRange,
|
||||
steps = steps,
|
||||
onValueChangeFinished = onValueChangeFinished,
|
||||
colors = colors,
|
||||
interactionSource = interactionSource,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SlidersLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SlidersDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Column {
|
||||
Slider(onValueChange = {}, value = 0.33f, enabled = true)
|
||||
Slider(onValueChange = {}, value = 0.33f, enabled = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun Surface(
|
||||
modifier: Modifier = Modifier,
|
||||
shape: Shape = RectangleShape,
|
||||
color: Color = MaterialTheme.colorScheme.surface,
|
||||
contentColor: Color = contentColorFor(color),
|
||||
tonalElevation: Dp = 0.dp,
|
||||
shadowElevation: Dp = 0.dp,
|
||||
border: BorderStroke? = null,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
androidx.compose.material3.Surface(
|
||||
modifier = modifier,
|
||||
shape = shape,
|
||||
color = color,
|
||||
contentColor = contentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
shadowElevation = shadowElevation,
|
||||
border = border,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.TextLayoutResult
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.utils.toHrf
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
|
||||
@Composable
|
||||
fun Text(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = Color.Unspecified,
|
||||
fontSize: TextUnit = TextUnit.Unspecified,
|
||||
fontStyle: FontStyle? = null,
|
||||
fontWeight: FontWeight? = null,
|
||||
fontFamily: FontFamily? = null,
|
||||
letterSpacing: TextUnit = TextUnit.Unspecified,
|
||||
textDecoration: TextDecoration? = null,
|
||||
textAlign: TextAlign? = null,
|
||||
lineHeight: TextUnit = TextUnit.Unspecified,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
softWrap: Boolean = true,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||
style: TextStyle = LocalTextStyle.current
|
||||
) {
|
||||
androidx.compose.material3.Text(
|
||||
text = text,
|
||||
modifier = modifier,
|
||||
color = color,
|
||||
fontSize = fontSize,
|
||||
fontStyle = fontStyle,
|
||||
fontWeight = fontWeight,
|
||||
fontFamily = fontFamily,
|
||||
letterSpacing = letterSpacing,
|
||||
textDecoration = textDecoration,
|
||||
textAlign = textAlign,
|
||||
lineHeight = lineHeight,
|
||||
overflow = overflow,
|
||||
softWrap = softWrap,
|
||||
maxLines = maxLines,
|
||||
onTextLayout = onTextLayout,
|
||||
style = style,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Text(
|
||||
text: AnnotatedString,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = Color.Unspecified,
|
||||
fontSize: TextUnit = TextUnit.Unspecified,
|
||||
fontStyle: FontStyle? = null,
|
||||
fontWeight: FontWeight? = null,
|
||||
fontFamily: FontFamily? = null,
|
||||
letterSpacing: TextUnit = TextUnit.Unspecified,
|
||||
textDecoration: TextDecoration? = null,
|
||||
textAlign: TextAlign? = null,
|
||||
lineHeight: TextUnit = TextUnit.Unspecified,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
softWrap: Boolean = true,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
inlineContent: ImmutableMap<String, InlineTextContent> = persistentMapOf(),
|
||||
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||
style: TextStyle = LocalTextStyle.current
|
||||
) {
|
||||
androidx.compose.material3.Text(
|
||||
text = text,
|
||||
modifier = modifier,
|
||||
color = color,
|
||||
fontSize = fontSize,
|
||||
fontStyle = fontStyle,
|
||||
fontWeight = fontWeight,
|
||||
fontFamily = fontFamily,
|
||||
letterSpacing = letterSpacing,
|
||||
textDecoration = textDecoration,
|
||||
textAlign = textAlign,
|
||||
lineHeight = lineHeight,
|
||||
overflow = overflow,
|
||||
softWrap = softWrap,
|
||||
maxLines = maxLines,
|
||||
inlineContent = inlineContent,
|
||||
onTextLayout = onTextLayout,
|
||||
style = style,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TextLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TextDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
val colors = mapOf(
|
||||
"primary" to MaterialTheme.colorScheme.primary,
|
||||
"secondary" to MaterialTheme.colorScheme.secondary,
|
||||
"tertiary" to MaterialTheme.colorScheme.tertiary,
|
||||
"background" to MaterialTheme.colorScheme.background,
|
||||
"error" to MaterialTheme.colorScheme.error,
|
||||
"surface" to MaterialTheme.colorScheme.surface,
|
||||
"surfaceVariant" to MaterialTheme.colorScheme.surfaceVariant,
|
||||
"primaryContainer" to MaterialTheme.colorScheme.primaryContainer,
|
||||
"secondaryContainer" to MaterialTheme.colorScheme.secondaryContainer,
|
||||
"tertiaryContainer" to MaterialTheme.colorScheme.tertiaryContainer,
|
||||
// "inversePrimary" to MaterialTheme.colorScheme.inversePrimary,
|
||||
"errorContainer" to MaterialTheme.colorScheme.errorContainer,
|
||||
"inverseSurface" to MaterialTheme.colorScheme.inverseSurface,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.width(IntrinsicSize.Max)
|
||||
) {
|
||||
colors.keys.forEach { name ->
|
||||
val color = colors[name]!!
|
||||
val textColor = contentColorFor(backgroundColor = color)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(color = color)
|
||||
.fillMaxWidth()
|
||||
.padding(2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Text on $name\n${textColor.toHrf()} on ${color.toHrf()}",
|
||||
color = textColor,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.TextFieldColors
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
readOnly: Boolean = false,
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
label: @Composable (() -> Unit)? = null,
|
||||
placeholder: @Composable (() -> Unit)? = null,
|
||||
leadingIcon: @Composable (() -> Unit)? = null,
|
||||
trailingIcon: @Composable (() -> Unit)? = null,
|
||||
supportingText: @Composable (() -> Unit)? = null,
|
||||
isError: Boolean = false,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
shape: Shape = TextFieldDefaults.filledShape,
|
||||
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
|
||||
) {
|
||||
androidx.compose.material3.TextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
readOnly = readOnly,
|
||||
textStyle = textStyle,
|
||||
label = label,
|
||||
placeholder = placeholder,
|
||||
leadingIcon = leadingIcon,
|
||||
trailingIcon = trailingIcon,
|
||||
supportingText = supportingText,
|
||||
isError = isError,
|
||||
visualTransformation = visualTransformation,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
singleLine = singleLine,
|
||||
maxLines = maxLines,
|
||||
interactionSource = interactionSource,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TopAppBar(
|
||||
title: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
navigationIcon: @Composable () -> Unit = {},
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
|
||||
colors: TopAppBarColors = TopAppBarDefaults.smallTopAppBarColors(),
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||
) {
|
||||
androidx.compose.material3.TopAppBar(
|
||||
title = title,
|
||||
modifier = modifier,
|
||||
navigationIcon = navigationIcon,
|
||||
actions = actions,
|
||||
windowInsets = windowInsets,
|
||||
colors = colors,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.previews
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
@Composable
|
||||
internal fun ColorListPreview(
|
||||
backgroundColor: Color,
|
||||
foregroundColor: Color,
|
||||
colors: ImmutableMap<String, Color>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(color = backgroundColor)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
colors.keys.forEach { name ->
|
||||
val color = colors[name]!!
|
||||
ColorPreview(backgroundColor = backgroundColor, foregroundColor = foregroundColor, name = name, color = color)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.previews
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.utils.toHrf
|
||||
|
||||
@Composable
|
||||
internal fun ColorPreview(
|
||||
backgroundColor: Color,
|
||||
foregroundColor: Color,
|
||||
name: String, color: Color,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier.fillMaxWidth()) {
|
||||
Text(text = name + " " + color.toHrf(), fontSize = 6.sp, color = foregroundColor)
|
||||
val backgroundBrush = Brush.linearGradient(
|
||||
listOf(
|
||||
backgroundColor,
|
||||
foregroundColor,
|
||||
)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.background(backgroundBrush)
|
||||
) {
|
||||
repeat(2) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(1.dp)
|
||||
.background(color = color)
|
||||
.height(10.dp)
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.previews
|
||||
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
|
||||
@Composable
|
||||
internal fun ColorsSchemePreview(
|
||||
backgroundColor: Color,
|
||||
foregroundColor: Color,
|
||||
colorScheme: ColorScheme,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val colors = persistentMapOf(
|
||||
"primary" to colorScheme.primary,
|
||||
"onPrimary" to colorScheme.onPrimary,
|
||||
"primaryContainer" to colorScheme.primaryContainer,
|
||||
"onPrimaryContainer" to colorScheme.onPrimaryContainer,
|
||||
"inversePrimary" to colorScheme.inversePrimary,
|
||||
"secondary" to colorScheme.secondary,
|
||||
"onSecondary" to colorScheme.onSecondary,
|
||||
"secondaryContainer" to colorScheme.secondaryContainer,
|
||||
"onSecondaryContainer" to colorScheme.onSecondaryContainer,
|
||||
"tertiary" to colorScheme.tertiary,
|
||||
"onTertiary" to colorScheme.onTertiary,
|
||||
"tertiaryContainer" to colorScheme.tertiaryContainer,
|
||||
"onTertiaryContainer" to colorScheme.onTertiaryContainer,
|
||||
"background" to colorScheme.background,
|
||||
"onBackground" to colorScheme.onBackground,
|
||||
"surface" to colorScheme.surface,
|
||||
"onSurface" to colorScheme.onSurface,
|
||||
"surfaceVariant" to colorScheme.surfaceVariant,
|
||||
"onSurfaceVariant" to colorScheme.onSurfaceVariant,
|
||||
"surfaceTint" to colorScheme.surfaceTint,
|
||||
"inverseSurface" to colorScheme.inverseSurface,
|
||||
"inverseOnSurface" to colorScheme.inverseOnSurface,
|
||||
"error" to colorScheme.error,
|
||||
"onError" to colorScheme.onError,
|
||||
"errorContainer" to colorScheme.errorContainer,
|
||||
"onErrorContainer" to colorScheme.onErrorContainer,
|
||||
"outline" to colorScheme.outline,
|
||||
"outlineVariant" to colorScheme.outlineVariant,
|
||||
"scrim" to colorScheme.scrim,
|
||||
)
|
||||
ColorListPreview(
|
||||
backgroundColor = backgroundColor,
|
||||
foregroundColor = foregroundColor,
|
||||
colors = colors,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.utils
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Convert color to Human Readable Format.
|
||||
*/
|
||||
internal fun Color.toHrf(): String {
|
||||
return "0x" + value.toString(16).take(8).uppercase()
|
||||
}
|
||||
|
|
@ -23,5 +23,5 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.google.android.material:material:1.7.0")
|
||||
implementation(libs.androidx.material)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.0"
|
||||
kotlin("plugin.serialization") version "1.8.10"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
|
|
@ -25,10 +25,18 @@ import io.element.android.libraries.matrix.room.MatrixRoom
|
|||
import io.element.android.libraries.matrix.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrixtest.media.FakeMediaResolver
|
||||
import io.element.android.libraries.matrixtest.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrixtest.room.InMemoryRoomSummaryDataSource
|
||||
import io.element.android.libraries.matrixtest.room.FakeRoomSummaryDataSource
|
||||
import kotlinx.coroutines.delay
|
||||
import org.matrix.rustcomponents.sdk.MediaSource
|
||||
|
||||
class FakeMatrixClient(override val sessionId: SessionId) : MatrixClient {
|
||||
class FakeMatrixClient(
|
||||
override val sessionId: SessionId = SessionId(A_SESSION_ID),
|
||||
private val userDisplayName: Result<String> = Result.success(A_USER_NAME),
|
||||
private val userAvatarURLString: Result<String> = Result.success(AN_AVATAR_URL),
|
||||
val roomSummaryDataSource: RoomSummaryDataSource = FakeRoomSummaryDataSource()
|
||||
) : MatrixClient {
|
||||
|
||||
private var logoutFailure: Throwable? = null
|
||||
|
||||
override fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||
return FakeMatrixRoom(roomId)
|
||||
|
|
@ -39,23 +47,30 @@ class FakeMatrixClient(override val sessionId: SessionId) : MatrixClient {
|
|||
override fun stopSync() = Unit
|
||||
|
||||
override fun roomSummaryDataSource(): RoomSummaryDataSource {
|
||||
return InMemoryRoomSummaryDataSource()
|
||||
return roomSummaryDataSource
|
||||
}
|
||||
|
||||
override fun mediaResolver(): MediaResolver {
|
||||
return FakeMediaResolver()
|
||||
}
|
||||
|
||||
override suspend fun logout() = Unit
|
||||
fun givenLogoutError(failure: Throwable) {
|
||||
logoutFailure = failure
|
||||
}
|
||||
|
||||
override fun userId(): UserId = UserId("")
|
||||
override suspend fun logout() {
|
||||
delay(100)
|
||||
logoutFailure?.let { throw it }
|
||||
}
|
||||
|
||||
override fun userId(): UserId = A_USER_ID
|
||||
|
||||
override suspend fun loadUserDisplayName(): Result<String> {
|
||||
return Result.success("")
|
||||
return userDisplayName
|
||||
}
|
||||
|
||||
override suspend fun loadUserAvatarURLString(): Result<String> {
|
||||
return Result.success("")
|
||||
return userAvatarURLString
|
||||
}
|
||||
|
||||
override suspend fun loadMediaContentForSource(source: MediaSource): Result<ByteArray> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
|
||||
const val A_USER_NAME = "alice"
|
||||
const val A_PASSWORD = "password"
|
||||
|
||||
val A_USER_ID = UserId("@alice:server.org")
|
||||
val A_ROOM_ID = RoomId("!aRoomId")
|
||||
val AN_EVENT_ID = EventId("\$anEventId")
|
||||
|
||||
const val A_ROOM_NAME = "A room name"
|
||||
const val A_MESSAGE = "Hello world!"
|
||||
const val A_REPLY = "OK, I'll be there!"
|
||||
const val ANOTHER_MESSAGE = "Hello universe!"
|
||||
|
||||
const val A_HOMESERVER = "matrix.org"
|
||||
const val A_HOMESERVER_2 = "matrix-client.org"
|
||||
const val A_SESSION_ID = "sessionId"
|
||||
|
||||
const val AN_AVATAR_URL = "mxc://data"
|
||||
|
||||
const val A_FAILURE_REASON = "There has been a failure"
|
||||
val A_THROWABLE = Throwable(A_FAILURE_REASON)
|
||||
val AN_EXCEPTION = Exception(A_FAILURE_REASON)
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.auth
|
||||
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrixtest.A_HOMESERVER
|
||||
import io.element.android.libraries.matrixtest.A_SESSION_ID
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
class FakeAuthenticationService : MatrixAuthenticationService {
|
||||
private var homeserver: String = A_HOMESERVER
|
||||
private var loginError: Throwable? = null
|
||||
|
||||
override fun isLoggedIn(): Flow<Boolean> {
|
||||
return flowOf(false)
|
||||
}
|
||||
|
||||
override suspend fun getLatestSessionId(): SessionId? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun restoreSession(sessionId: SessionId): MatrixClient? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getHomeserver(): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun givenHomeserver(homeserver: String) {
|
||||
this.homeserver = homeserver
|
||||
}
|
||||
|
||||
override fun getHomeserverOrDefault(): String {
|
||||
return homeserver
|
||||
}
|
||||
|
||||
override suspend fun setHomeserver(homeserver: String) {
|
||||
delay(100)
|
||||
}
|
||||
|
||||
override suspend fun login(username: String, password: String): SessionId {
|
||||
delay(100)
|
||||
loginError?.let { throw it }
|
||||
return SessionId(A_SESSION_ID)
|
||||
}
|
||||
|
||||
fun givenLoginError(throwable: Throwable?) {
|
||||
loginError = throwable
|
||||
}
|
||||
}
|
||||
|
|
@ -20,17 +20,20 @@ import io.element.android.libraries.matrix.core.EventId
|
|||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrixtest.A_ROOM_ID
|
||||
import io.element.android.libraries.matrixtest.timeline.FakeMatrixTimeline
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
|
||||
class FakeMatrixRoom(
|
||||
override val roomId: RoomId,
|
||||
override val roomId: RoomId = A_ROOM_ID,
|
||||
override val name: String? = null,
|
||||
override val bestName: String = "",
|
||||
override val displayName: String = "",
|
||||
override val topic: String? = null,
|
||||
override val avatarUrl: String? = null
|
||||
override val avatarUrl: String? = null,
|
||||
private val matrixTimeline: MatrixTimeline = FakeMatrixTimeline(),
|
||||
) : MatrixRoom {
|
||||
|
||||
override fun syncUpdateFlow(): Flow<Long> {
|
||||
|
|
@ -38,7 +41,7 @@ class FakeMatrixRoom(
|
|||
}
|
||||
|
||||
override fun timeline(): MatrixTimeline {
|
||||
return FakeMatrixTimeline()
|
||||
return matrixTimeline
|
||||
}
|
||||
|
||||
override suspend fun fetchMembers(): Result<Unit> {
|
||||
|
|
@ -54,18 +57,34 @@ class FakeMatrixRoom(
|
|||
}
|
||||
|
||||
override suspend fun sendMessage(message: String): Result<Unit> {
|
||||
TODO("Not yet implemented")
|
||||
delay(100)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
var editMessageParameter: String? = null
|
||||
private set
|
||||
|
||||
override suspend fun editMessage(originalEventId: EventId, message: String): Result<Unit> {
|
||||
TODO("Not yet implemented")
|
||||
editMessageParameter = message
|
||||
delay(100)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
var replyMessageParameter: String? = null
|
||||
private set
|
||||
|
||||
override suspend fun replyMessage(eventId: EventId, message: String): Result<Unit> {
|
||||
TODO("Not yet implemented")
|
||||
replyMessageParameter = message
|
||||
delay(100)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
var redactEventEventIdParam: EventId? = null
|
||||
private set
|
||||
|
||||
override suspend fun redactEvent(eventId: EventId, reason: String?): Result<Unit> {
|
||||
TODO("Not yet implemented")
|
||||
redactEventEventIdParam = eventId
|
||||
delay(100)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,22 @@ import io.element.android.libraries.matrix.room.RoomSummaryDataSource
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class InMemoryRoomSummaryDataSource : RoomSummaryDataSource {
|
||||
class FakeRoomSummaryDataSource : RoomSummaryDataSource {
|
||||
|
||||
override fun roomSummaries(): StateFlow<List<RoomSummary>> {
|
||||
return MutableStateFlow(emptyList())
|
||||
private val roomSummariesFlow = MutableStateFlow<List<RoomSummary>>(emptyList())
|
||||
|
||||
suspend fun postRoomSummary(roomSummaries: List<RoomSummary>) {
|
||||
roomSummariesFlow.emit(roomSummaries)
|
||||
}
|
||||
|
||||
override fun setSlidingSyncRange(range: IntRange) = Unit
|
||||
override fun roomSummaries(): StateFlow<List<RoomSummary>> {
|
||||
return roomSummariesFlow
|
||||
}
|
||||
|
||||
var latestSlidingSyncRange: IntRange? = null
|
||||
private set
|
||||
|
||||
override fun setSlidingSyncRange(range: IntRange) {
|
||||
latestSlidingSyncRange = range
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.room
|
||||
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.room.RoomSummary
|
||||
import io.element.android.libraries.matrix.room.RoomSummaryDetails
|
||||
import io.element.android.libraries.matrixtest.A_MESSAGE
|
||||
import io.element.android.libraries.matrixtest.A_ROOM_ID
|
||||
import io.element.android.libraries.matrixtest.A_ROOM_NAME
|
||||
|
||||
fun aRoomSummaryFilled(
|
||||
roomId: RoomId = A_ROOM_ID,
|
||||
name: String = A_ROOM_NAME,
|
||||
isDirect: Boolean = false,
|
||||
avatarURLString: String? = null,
|
||||
lastMessage: CharSequence? = A_MESSAGE,
|
||||
lastMessageTimestamp: Long? = null,
|
||||
unreadNotificationCount: Int = 2,
|
||||
) = RoomSummary.Filled(
|
||||
aRoomSummaryDetail(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
isDirect = isDirect,
|
||||
avatarURLString = avatarURLString,
|
||||
lastMessage = lastMessage,
|
||||
lastMessageTimestamp = lastMessageTimestamp,
|
||||
unreadNotificationCount = unreadNotificationCount,
|
||||
)
|
||||
)
|
||||
|
||||
fun aRoomSummaryDetail(
|
||||
roomId: RoomId = A_ROOM_ID,
|
||||
name: String = A_ROOM_NAME,
|
||||
isDirect: Boolean = false,
|
||||
avatarURLString: String? = null,
|
||||
lastMessage: CharSequence? = A_MESSAGE,
|
||||
lastMessageTimestamp: Long? = null,
|
||||
unreadNotificationCount: Int = 2,
|
||||
) = RoomSummaryDetails(
|
||||
roomId = roomId,
|
||||
name = name,
|
||||
isDirect = isDirect,
|
||||
avatarURLString = avatarURLString,
|
||||
lastMessage = lastMessage,
|
||||
lastMessageTimestamp = lastMessageTimestamp,
|
||||
unreadNotificationCount = unreadNotificationCount,
|
||||
)
|
||||
|
|
@ -19,21 +19,20 @@ package io.element.android.libraries.matrixtest.timeline
|
|||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.timeline.MatrixTimelineItem
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import org.matrix.rustcomponents.sdk.TimelineListener
|
||||
|
||||
class FakeMatrixTimeline : MatrixTimeline {
|
||||
|
||||
override var callback: MatrixTimeline.Callback?
|
||||
get() = null
|
||||
set(value) {}
|
||||
override var callback: MatrixTimeline.Callback? = null
|
||||
|
||||
override fun timelineItems(): Flow<List<MatrixTimelineItem>> {
|
||||
return emptyFlow()
|
||||
}
|
||||
|
||||
override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit> {
|
||||
delay(100)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -36,6 +35,9 @@ import androidx.compose.ui.unit.sp
|
|||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
|
|
@ -64,8 +66,9 @@ fun MatrixUserHeader(
|
|||
fontWeight = FontWeight.SemiBold,
|
||||
text = matrixUser.getBestName(),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
// Id
|
||||
if (matrixUser.username.isNullOrEmpty().not()) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
|
@ -82,7 +85,14 @@ fun MatrixUserHeader(
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
fun MatrixUserHeaderPreview() {
|
||||
fun MatrixUserHeaderLightPreview() = ElementPreviewLight { ContentToPreview1() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun MatrixUserHeaderDarkPreview() = ElementPreviewDark { ContentToPreview1() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview1() {
|
||||
MatrixUserHeader(
|
||||
MatrixUser(
|
||||
id = UserId("@alice:server.org"),
|
||||
|
|
@ -94,7 +104,14 @@ fun MatrixUserHeaderPreview() {
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
fun MatrixUserHeaderNoUsernamePreview() {
|
||||
fun MatrixUserHeaderNoUserNameLightPreview() = ElementPreviewLight { ContentToPreview2() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun MatrixUserHeaderNoUserNameDarkPreview() = ElementPreviewDark { ContentToPreview2() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview2() {
|
||||
MatrixUserHeader(
|
||||
MatrixUser(
|
||||
id = UserId("@alice:server.org"),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -35,6 +34,9 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
|
|
@ -68,7 +70,8 @@ fun MatrixUserRow(
|
|||
fontWeight = FontWeight.SemiBold,
|
||||
text = matrixUser.getBestName(),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
// Id
|
||||
if (matrixUser.username.isNullOrEmpty().not()) {
|
||||
|
|
@ -86,7 +89,14 @@ fun MatrixUserRow(
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
fun MatrixUserRowPreview() {
|
||||
fun MatrixUserRowLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun MatrixUserRowDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
MatrixUserRow(
|
||||
MatrixUser(
|
||||
id = UserId("@alice:server.org"),
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@ dependencies {
|
|||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.matrix)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(libs.wysiwyg)
|
||||
implementation(libs.androidx.constraintlayout)
|
||||
implementation("com.google.android.material:material:1.7.0")
|
||||
implementation(libs.androidx.material)
|
||||
ksp(libs.showkase.processor)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import android.net.Uri
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -33,6 +33,9 @@ import androidx.compose.ui.unit.sp
|
|||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
|
|
@ -123,7 +126,8 @@ private fun FakeComposer(
|
|||
.align(Alignment.Center),
|
||||
textAlign = TextAlign.Center,
|
||||
text = "Composer Preview",
|
||||
fontSize = 20.sp
|
||||
fontSize = 20.sp,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -145,7 +149,14 @@ private fun MessageComposerView.setup(isDarkMode: Boolean, composerMode: Message
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TextComposerPreview() {
|
||||
fun TextComposerLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TextComposerDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
TextComposer(
|
||||
onSendMessage = {},
|
||||
fullscreen = false,
|
||||
|
|
|
|||
|
|
@ -2979,4 +2979,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress_message">Hlasovou zprávu nelze spustit, protože právě nahráváte živé vysílání. Ukončete prosím živé vysílání, abyste mohli začít nahrávat hlasovou zprávu</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Nelze spustit hlasovou zprávu</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Chyba připojení - nahrávání pozastaveno</string>
|
||||
<string name="rich_text_editor_inline_code">Použít formát inline kódu</string>
|
||||
</resources>
|
||||
|
|
@ -2918,4 +2918,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress_message">Du kannst keine Sprachnachricht beginnen, da du im Moment eine Echtzeitübertragung aufzeichnest. Bitte beende deine Sprachübertragung, um ein Gespräch zu beginnen</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Kann Sprachnachricht nicht beginnen</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Verbindungsfehler − Aufnahme pausiert</string>
|
||||
<string name="rich_text_editor_inline_code">Als Inline-Code formatieren</string>
|
||||
</resources>
|
||||
|
|
@ -2256,7 +2256,7 @@
|
|||
<string name="create_poll_options_title">Koosta valikud</string>
|
||||
<string name="create_poll_question_hint">Küsimus või teema</string>
|
||||
<string name="create_poll_question_title">Küsitluse küsimus või teema</string>
|
||||
<string name="create_poll_title">Koosta üks küsitlus</string>
|
||||
<string name="create_poll_title">Loo selline küsitlus</string>
|
||||
<string name="attachment_type_poll">Küsitlus</string>
|
||||
<string name="identity_server_consent_dialog_title_2">Saada e-posti aadressid ja telefoninumbrid %s serverisse</string>
|
||||
<string name="settings_discovery_consent_notice_off_2">Sinu kontaktid on vaid sinu teada. Kui tahad nende hulgast leida Matrix\'i kasutajaid, siis me vajame sinu luba nende andmete saatmiseks räsitud kujul isikutuvastusserverisse.</string>
|
||||
|
|
@ -2330,9 +2330,9 @@
|
|||
<string name="location_activity_title_preview">Asukoht</string>
|
||||
<string name="location_activity_title_static_sharing">Jaga asukohta</string>
|
||||
<string name="closed_poll_option_description">Tulemusi kuvame vaid siis, kui küsitlus on lõppenud</string>
|
||||
<string name="closed_poll_option_title">Küsitlus on lõppenud</string>
|
||||
<string name="closed_poll_option_title">Suletud valikutega küsitlus</string>
|
||||
<string name="open_poll_option_description">Osalejad näevad tulemusi peale oma valiku salvestamist</string>
|
||||
<string name="open_poll_option_title">Ava küsitlus</string>
|
||||
<string name="open_poll_option_title">Avatud valikutega küsitlus</string>
|
||||
<string name="poll_type_title">Küsitluse tüüp</string>
|
||||
<string name="edit_poll_title">Muuda küsitlust</string>
|
||||
<string name="poll_no_votes_cast">Hääletanuid ei ole</string>
|
||||
|
|
@ -2910,4 +2910,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress">Häälsõnumi esitamine ei õnnestu</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">Kuna sa hetkel salvestad ringhäälingukõnet, siis häälsõnumi salvestamine või esitamine ei õnnestu. Selleks palun lõpeta ringhäälingukõne</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Viga võrguühenduses - salvestamine on peatatud</string>
|
||||
<string name="rich_text_editor_inline_code">Kasuta lõimitud koodi vormingut</string>
|
||||
</resources>
|
||||
|
|
@ -2919,4 +2919,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress_message">از آنجا که در حال ضبط پخشی زندهاید، نمیتوانید پیامی صوتی را آغاز کنید. لطفاً برای آغاز ضبط یک پیام صوتی، پخش زندهتان را پایان دهید</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">نمیتوان پخش صوتی را آغاز کرد</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">خطای اتّصال - ضبط مکث شد</string>
|
||||
<string name="rich_text_editor_inline_code">اعمال قالب کد درونخط</string>
|
||||
</resources>
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
<string name="incoming_video_call">Saapuva videopuhelu</string>
|
||||
<string name="incoming_voice_call">Saapuva puhelu</string>
|
||||
<string name="call_in_progress">Puhelu käynnissä…</string>
|
||||
<string name="call_error_user_not_responding">Toinen puoli ei vastannut.</string>
|
||||
<string name="call_error_user_not_responding">Toinen osapuoli ei vastannut.</string>
|
||||
<string name="permissions_rationale_popup_title">Huomio</string>
|
||||
<string name="permissions_rationale_msg_record_audio">${app_name} tarvitsee käyttöluvan mikrofoniin suorittakseen puheluita.</string>
|
||||
<string name="permissions_rationale_msg_camera_and_audio">${app_name} tarvitsee käyttöluvan kameraan ja mikrofoniin suorittakseen videopuheluita.
|
||||
|
|
@ -887,7 +887,7 @@
|
|||
<string name="settings_discovery_disconnect_with_bound_pid">Jaat sähköpostiosoitteita tai puhelinnumeroita identiteettipalvelimella %1$s. Sinun täytyy yhdistää uudelleen palvelimeen %2$s, jotta voit lopettaa niiden jakamisen.</string>
|
||||
<string name="settings_agree_to_terms">Hyväksy identiteettipalvelimen (%s) käyttöehdot salliaksesi, että sinut voi löytää sähköpostiosoitteen tai puhelinnumeron perusteella.</string>
|
||||
<string name="settings_discovery_disconnect_identity_server_info">Yhteyden katkaiseminen identiteettipalvelimeesi tarkoittaa, että muut käyttäjät eivät voi etsiä sinua etkä voi kutsua muita sähköpostin tai puhelinnumeron perusteella.</string>
|
||||
<string name="settings_discovery_confirm_mail">Lähetimme sinulle vahvistussähköpostin osoitteeseen %s, tarkista sähköpostisi ja klikkaa vahvistuslinkkiä</string>
|
||||
<string name="settings_discovery_confirm_mail">Lähetimme sinulle sähköpostia osoitteeseen %s. Tarkista sähköpostisi ja klikkaa vahvistuslinkkiä.</string>
|
||||
<string name="labs_allow_extended_logging">Ota yksityiskohtaiset lokit käyttöön.</string>
|
||||
<string name="error_terms_not_accepted">Yritä uudelleen, kun olet hyväksynyt kotipalvelimesi käyttöehdot.</string>
|
||||
<string name="error_network_timeout">Palvelimen vastaus näyttäisi olevan liian hidas. Tämä voi johtua kehnosta yhteydestä tai palvelimella olevasta ongelmasta. Yritä hetken kuluttua uudelleen.</string>
|
||||
|
|
@ -1026,7 +1026,7 @@
|
|||
<string name="login_signin_to">Kirjaudu sisään palvelimeen %1$s</string>
|
||||
<string name="login_signup">Rekisteröidy</string>
|
||||
<string name="login_signin">Kirjaudu sisään</string>
|
||||
<string name="login_signin_sso">Jatka kertakirjautumiseen</string>
|
||||
<string name="login_signin_sso">Jatka kertakirjautumisella</string>
|
||||
<string name="login_server_url_form_modular_hint">Element Matrix Services in osoite</string>
|
||||
<string name="login_server_url_form_other_hint">Osoite</string>
|
||||
<string name="login_server_url_form_modular_text">Korkealuokkaista isännöintiä organisaatioille</string>
|
||||
|
|
@ -1097,8 +1097,8 @@
|
|||
<string name="login_validation_code_is_not_correct">Syöttämäsi koodi ei ole kelvollinen. Tarkista se.</string>
|
||||
<string name="login_error_outdated_homeserver_title">Vanhentunut kotipalvelin</string>
|
||||
<plurals name="login_error_limit_exceeded_retry_after">
|
||||
<item quantity="one">Liian monta pyyntöä lähetettiin. Voit yrittää uudelleen 1 sekunnissa…</item>
|
||||
<item quantity="other">Liian monta pyyntöä lähetettiin. Voit yrittää uudelleen %1$d sekunnissa…</item>
|
||||
<item quantity="one">Liian monta pyyntöä lähetettiin. Voit yrittää uudelleen sekunnin kuluttua…</item>
|
||||
<item quantity="other">Liian monta pyyntöä lähetettiin. Voit yrittää uudelleen %1$d sekunnin kuluttua…</item>
|
||||
</plurals>
|
||||
<string name="seen_by">Nähneet</string>
|
||||
<string name="signed_out_title">Olet kirjautunut ulos</string>
|
||||
|
|
@ -2068,7 +2068,7 @@
|
|||
<string name="ftue_account_created_congratulations_title">Onnittelut!</string>
|
||||
<string name="ftue_account_created_personalize">Personoi profiili</string>
|
||||
<string name="ftue_auth_use_case_skip_partial">ohittaa tämän kysymyksen</string>
|
||||
<string name="ftue_auth_use_case_skip">Ei varmuutta vielä\? Voit %s</string>
|
||||
<string name="ftue_auth_use_case_skip">Etkö ole vielä varma\? Voit %s</string>
|
||||
<string name="settings_discovery_no_policy_provided">Identiteettipalvelin ei tarjoa käytäntöä</string>
|
||||
<string name="settings_discovery_hide_identity_server_policy_title">Piilota identiteettipalvelimen käytäntö</string>
|
||||
<string name="settings_discovery_show_identity_server_policy_title">Näytä identiteettipalvelimen käytäntö</string>
|
||||
|
|
@ -2307,4 +2307,54 @@
|
|||
<item quantity="one">%1$d valittu</item>
|
||||
<item quantity="other">%1$d valittu</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
<string name="voice_broadcast_buffering">Puskuroidaan…</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Ääniviestiä ei voi aloittaa</string>
|
||||
<string name="room_using_unstable_room_version">Tässä huoneessa on käytössä huoneversio %s, jonka tämä kotipalvelin on merkinnyt epävakaaksi.</string>
|
||||
<string name="space_leave_radio_button_none">Älä poistu mistään</string>
|
||||
<string name="space_leave_radio_button_all">Poistu kaikista</string>
|
||||
<string name="a11y_delete_avatar">Poista profiilikuva</string>
|
||||
<string name="a11y_change_avatar">Vaihda profiilikuva</string>
|
||||
<string name="call_dial_pad_lookup_error">Puhelinnumeron haussa tapahtui virhe</string>
|
||||
<plurals name="invitations_sent_to_one_and_more_users">
|
||||
<item quantity="one">Kutsut lähetetty käyttäjälle %1$s ja yhdelle muulle</item>
|
||||
<item quantity="other">Kutsut lähetetty käyttäjälle %1$s ja %2$d muulle</item>
|
||||
</plurals>
|
||||
<string name="invitations_sent_to_two_users">Kutsu lähetetty käyttäjille %1$s ja %2$s</string>
|
||||
<string name="invitation_sent_to_one_user">Kutsu lähetetty käyttäjälle %1$s</string>
|
||||
<string name="send_your_first_msg_to_invite">Kutsu %s keskusteluun lähettämällä ensimmäinen viesti</string>
|
||||
<string name="this_is_the_beginning_of_dm">Tästä alkaa yksityisviestihistoriasi sinun ja käyttäjän %s välillä.</string>
|
||||
<string name="this_is_the_beginning_of_room">%s alkaa tästä.</string>
|
||||
<string name="encryption_misconfigured">Salaus on säädetty väärin</string>
|
||||
<string name="encryption_has_been_misconfigured">Salaus on säädetty väärin.</string>
|
||||
<string name="login_error_outdated_homeserver_warning_content">Tällä kotipalvelimella on vanha versio. Pyydä kotipalvelimesi ylläpitäjää päivittämään se. Voit jatkaa, mutta jotkin ominaisuudet eivät välttämättä toimi oikein.</string>
|
||||
<string name="ftue_auth_choose_server_ems_cta">Ota yhteyttä</string>
|
||||
<string name="login_social_continue_with">Jatka %s-kirjautumisella</string>
|
||||
<string name="ftue_auth_create_account_sso_section_header">tai</string>
|
||||
<string name="ftue_auth_sign_in_choose_server_header">Keskustelujesi koti</string>
|
||||
<string name="ftue_auth_create_account_choose_server_header">Keskustelujesi koti</string>
|
||||
<string name="ftue_auth_use_case_subtitle">Laitetaan yhteydet kuntoon</string>
|
||||
<string name="ftue_auth_use_case_title">Kenen kanssa juttelet eniten\?</string>
|
||||
<string name="ftue_auth_carousel_workplace_body">${app_name} toimii mainiosti työpaikallakin. Siihen luottavat maailman turvallisimmat organisaatiot.</string>
|
||||
<string name="jitsi_leave_conf_to_join_another_one_content">Poistutaanko nykyisestä ryhmäpuhelusta ja vaihdetaan toiseen\?</string>
|
||||
<string name="directory_add_a_new_server_error_already_added">Tämä palvelin on jo luettelossa</string>
|
||||
<string name="directory_add_a_new_server_error">Tätä palvelinta tai sen huoneluetteloa ei löydy</string>
|
||||
<string name="room_settings_room_access_entry_knock">Kuka vain voi koputtaa huoneeseen ja jäsenet voivat sen jälkeen hyväksyä tai hylätä</string>
|
||||
<string name="room_alias_unpublish_confirmation">Poista osoitteen \"%1$s\" julkaiseminen\?</string>
|
||||
<string name="room_settings_room_notifications_encryption_notice">Huomaa, että maininnat ja avainsanailmoitukset eivät ole käytössä salausta käyttävissä huoneissa mobiililaitteilla.</string>
|
||||
<string name="settings_enable_direct_share_title">Ota suora jako käyttöön</string>
|
||||
<string name="settings_autoplay_animated_images_summary">Toista aikajanalla olevat animoidut kuvat heti, kun ne näkyvät</string>
|
||||
<string name="settings_autoplay_animated_images_title">Toista animoidut kuvat automaattisesti</string>
|
||||
<string name="settings_mentions_and_keywords_encryption_notice">Et saa ilmoituksia maininnoista ja avainsanoista salausta käyttävissä huoneissa mobiililaitteilla.</string>
|
||||
<string name="settings_room_upgrades">Huonepäivitykset</string>
|
||||
<string name="settings_messages_by_bot">Botin lähettämät viestit</string>
|
||||
<string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} tarvitsee luvan ilmoitusten näyttämiseen.
|
||||
\nAnna lupa.</string>
|
||||
<string name="room_permissions_upgrade_the_room">Päivitä huone</string>
|
||||
<string name="labs_enable_deferred_dm_title">Ota lykätyt yksityisviestit käyttöön</string>
|
||||
<string name="action_deselect_all">Poista valinta kaikista</string>
|
||||
<string name="action_select_all">Valitse kaikki</string>
|
||||
<string name="denied_permission_voice_message">Anna mikrofonin käyttöoikeus ääniviestien lähettämiseksi.</string>
|
||||
<string name="denied_permission_camera">Anna kameran käyttöoikeus järjestelmän asetuksista tämän toiminnon suorittamiseksi.</string>
|
||||
<string name="denied_permission_generic">Tämän toiminnon suorittaminen vaatii enemmän oikeuksia. Anna oikeudet järjestelmän asetuksista.</string>
|
||||
<string name="notification_listening_for_notifications">Kuunnellaan ilmoituksia</string>
|
||||
</resources>
|
||||
|
|
@ -2919,4 +2919,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress_message">Vous ne pouvez pas commencer un message vocal car vous êtes en train d’enregistrer une diffusion en direct. Veuillez terminer cette diffusion pour commencer un message vocal</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Impossible de démarrer un message vocal</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Erreur de connexion – Enregistrement en pause</string>
|
||||
<string name="rich_text_editor_inline_code">Appliquer le formatage de code en ligne</string>
|
||||
</resources>
|
||||
|
|
@ -2919,4 +2919,5 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
|
|||
<string name="error_voice_message_broadcast_in_progress_message">Nem lehet hang üzenetet indítani élő közvetítés felvétele közben. Az élő közvetítés bejezése szükséges a hang üzenet indításához</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Hang üzenetet nem lehet elindítani</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Kapcsolódási hiba – Felvétel szüneteltetve</string>
|
||||
<string name="rich_text_editor_inline_code">Beágyazott kód formátum alkalmazása</string>
|
||||
</resources>
|
||||
|
|
@ -2861,4 +2861,5 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
|
|||
<string name="error_voice_broadcast_no_connection_recording">Kesalahan koneksi - Perekaman dijeda</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">Anda tidak dapat memulai sebuah pesan suara karena Anda saat ini merekam sebuah siaran langsung. Silakan mengakhiri siaran langsung Anda untuk memulai merekam sebuah pesan suara</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Tidak dapat memulai pesan suara</string>
|
||||
<string name="rich_text_editor_inline_code">Terapkan format kode dalam baris</string>
|
||||
</resources>
|
||||
|
|
@ -2382,4 +2382,44 @@
|
|||
<string name="action_got_it">Náði því</string>
|
||||
<string name="notice_voice_broadcast_ended_by_you">Þú endaðir talútsendingu.</string>
|
||||
<string name="notice_voice_broadcast_ended">%1$s endaði talútsendingu.</string>
|
||||
</resources>
|
||||
<string name="rich_text_editor_full_screen_toggle">Víxla heilskjásham af/á</string>
|
||||
<string name="rich_text_editor_bullet_list">Víxla punktalista af/á</string>
|
||||
<string name="rich_text_editor_numbered_list">Víxla tölusettum lista af/á</string>
|
||||
<string name="rich_text_editor_link">Setja tengil</string>
|
||||
<string name="rich_text_editor_format_underline">Virkja undirstrikun</string>
|
||||
<string name="rich_text_editor_format_strikethrough">Virkja yfirstrikun</string>
|
||||
<string name="rich_text_editor_format_italic">Virkja skáletrað snið</string>
|
||||
<string name="rich_text_editor_format_bold">Virkja feitletrað snið</string>
|
||||
<string name="device_manager_other_sessions_description_unverified_current_session">Óstaðfest · Núverandi setan þín</string>
|
||||
<string name="device_manager_other_sessions_description_unverified">Óstaðfest - Síðasta virkni %1$s</string>
|
||||
<string name="device_manager_other_sessions_description_verified">Staðfest - Síðasta virkni %1$s</string>
|
||||
<string name="settings_troubleshoot_test_current_gateway">Núverandi gátt: %s</string>
|
||||
<string name="settings_troubleshoot_test_current_endpoint_failed">Finn ekki endapunktinn.</string>
|
||||
<string name="settings_troubleshoot_test_current_endpoint_success">Núverandi endapunktur: %s</string>
|
||||
<string name="settings_troubleshoot_test_current_endpoint_title">Endapunktur</string>
|
||||
<string name="settings_troubleshoot_test_distributors_title">Tiltækar aðferðir</string>
|
||||
<string name="stop_voice_broadcast_content">Ertu viss um að þú viljir stöðva þessa beinu útsendingu\? Þetta mun stöðva útsendinguna og full skráning hennar verður tiltæk á spjallrásinni.</string>
|
||||
<string name="stop_voice_broadcast_dialog_title">Stöðva beina útsendingu\?</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Villa í tengingu - Upptaka í bið</string>
|
||||
<string name="error_voice_broadcast_unable_to_play">Tekst ekki að spila þessa talútsendingu.</string>
|
||||
<string name="error_voice_broadcast_unauthorized_title">Get ekki byrjað nýja talútsendingu</string>
|
||||
<string name="a11y_pause_voice_broadcast">setja talútsendingu í bið</string>
|
||||
<string name="a11y_play_voice_broadcast">Spila eða halda áfram með talútsendingu</string>
|
||||
<string name="a11y_stop_voice_broadcast_record">Stöðva upptöku á talútsendingu</string>
|
||||
<string name="a11y_pause_voice_broadcast_record">Setja upptöku á talútsendingu í bið</string>
|
||||
<string name="a11y_resume_voice_broadcast_record">Halda áfram með upptöku á talútsendingu</string>
|
||||
<string name="settings_security_incognito_keyboard_title">Nafnlaust lyklaborð</string>
|
||||
<string name="delete_event_dialog_reason_checkbox">Tilgreindu ástæðu</string>
|
||||
<string name="settings_server_upload_size_title">Takmörk netþjóns á innsendingum skráa</string>
|
||||
<string name="settings_rageshake_detection_threshold">Takmörk fyrir greiningu</string>
|
||||
<string name="uploads_files_no_result">Það eru engar skrár í þessari spjallrás</string>
|
||||
<string name="a11y_create_message">Útbúa nýtt samtal eða spjallrás</string>
|
||||
<string name="settings_text_message_sent_wrong_code">Staðfestingarkóðinn er ekki réttur.</string>
|
||||
<string name="settings_discovery_msisdn_title">Uppgötvanleg símanúmer</string>
|
||||
<string name="send_feedback_threads_title">Umsögn um beta-útgáfu spjallþráða</string>
|
||||
<string name="settings_show_avatar_display_name_changes_messages_summary">Innifelur breytingar á auðkennismynd og birtingarnafni.</string>
|
||||
<string name="settings_show_avatar_display_name_changes_messages">Birta atburði notandaaðgangs</string>
|
||||
<string name="settings_enable_direct_share_title">Virkja beina deilingu</string>
|
||||
<string name="threads_labs_enable_notice_title">Beta-útgáfa spjallþráða</string>
|
||||
<string name="threads_beta_enable_notice_title">Beta-útgáfa spjallþráða</string>
|
||||
</resources>
|
||||
|
|
@ -2909,4 +2909,6 @@
|
|||
</plurals>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">Non puoi iniziare un messaggio vocale perché stai registrando una trasmissione in diretta. Termina la trasmissione per potere iniziare un messaggio vocale</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Impossibile iniziare il messaggio vocale</string>
|
||||
</resources>
|
||||
<string name="rich_text_editor_inline_code">Applica formato codice interlinea</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Errore di connessione - Registrazione in pausa</string>
|
||||
</resources>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -345,7 +345,7 @@
|
|||
<string name="encryption_import_room_keys_summary">Importuj klucze z lokalnego pliku</string>
|
||||
<string name="encryption_import_import">Importuj</string>
|
||||
<string name="encryption_never_send_to_unverified_devices_title">Szyfruj wiadomości tylko do zaufanych sesji</string>
|
||||
<string name="encryption_never_send_to_unverified_devices_summary">Nigdy nie wysyłaj szyfrowanych wiadomości do niezweryfikowanych sesji (bez zielonej tarczy) z tego urządzenia.</string>
|
||||
<string name="encryption_never_send_to_unverified_devices_summary">Nigdy nie wysyłaj szyfrowanych wiadomości do niezweryfikowanych sesji (bez zielonej tarczy) z tej sesji.</string>
|
||||
<string name="encryption_information_verify_device_warning">Aby sprawdzić czy ta sesja jest zaufana, skontaktuj się z jej właścicielem używając innych form (np. osobiście lub telefonicznie) i zapytaj czy klucz, który widzą w ustawieniach użytkownika dla tego urządzenia pasuje do klucza poniżej:</string>
|
||||
<string name="encryption_information_verify_device_warning2">Jeśli klucz pasuje, potwierdź to przyciskiem poniżej. Jeśli nie, to ktoś inny najprawdopodobniej przejmuje lub podszywa się pod tą sesję i powinieneś dodać tę sesję do czarnej listy. W przyszłości proces weryfikacji będzie bardziej skomplikowany.</string>
|
||||
<string name="title_activity_choose_sticker">Wyślij naklejkę</string>
|
||||
|
|
|
|||
|
|
@ -2540,7 +2540,7 @@
|
|||
<string name="error_forbidden_digits_only_username">Домашний сервер не принимает имя пользователя, состоящее только из цифр.</string>
|
||||
<string name="ftue_personalize_skip_this_step">Пропустить этот шаг</string>
|
||||
<string name="ftue_personalize_submit">Сохранить и продолжить</string>
|
||||
<string name="ftue_personalize_complete_subtitle">Зайдите в настройки чтобы изменить Ваш профиль</string>
|
||||
<string name="ftue_personalize_complete_subtitle">Ваши предпочтения были сохранены</string>
|
||||
<string name="ftue_personalize_complete_title">Выглядит хорошо!</string>
|
||||
<string name="ftue_auth_carousel_workplace_body">${app_name} также отлично подходит для работы. Ему доверяют самые надёжные организации в мире.</string>
|
||||
<string name="keys_backup_settings_signature_from_this_user">Резервная копия имеет действительную подпись для данного пользователя.</string>
|
||||
|
|
|
|||
|
|
@ -2979,4 +2979,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress_message">Nemôžete spustiť hlasovú správu, pretože práve nahrávate živé vysielanie. Ukončite prosím živé vysielanie, aby ste mohli začať nahrávať hlasovú správu</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Nemožno spustiť hlasovú správu</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Chyba pripojenia - nahrávanie pozastavené</string>
|
||||
<string name="rich_text_editor_inline_code">Použiť formát riadkového kódu</string>
|
||||
</resources>
|
||||
|
|
@ -2887,4 +2887,23 @@
|
|||
<string name="error_voice_broadcast_unable_to_play">S’arrihet të luhet ky transmetim zanor.</string>
|
||||
<string name="started_a_voice_broadcast">Nisni një transmetim zanor</string>
|
||||
<string name="thread_list_not_available">Shërbyesi juaj Home s’mbulon ende paraqitje rrjedhash.</string>
|
||||
</resources>
|
||||
<string name="rich_text_editor_inline_code">Apliko format kodi brendazi</string>
|
||||
<string name="room_polls_loading_error">Gabim në sjellje pyetësorësh.</string>
|
||||
<string name="room_polls_load_more">Ngarko më tepër pyetësorë</string>
|
||||
<string name="room_polls_wait_for_display">Shfaqje pyetësorësh</string>
|
||||
<plurals name="room_polls_ended_no_item_for_loaded_period">
|
||||
<item quantity="one">S’ka pyetësorë të kaluar për ditën e kaluar.
|
||||
\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë.</item>
|
||||
<item quantity="other">S’ka pyetësorë aktivë për %1$d ditët e kaluara.
|
||||
\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë.</item>
|
||||
</plurals>
|
||||
<plurals name="room_polls_active_no_item_for_loaded_period">
|
||||
<item quantity="one">S’ka pyetësorë aktivë për ditën e kaluar.
|
||||
\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë.</item>
|
||||
<item quantity="other">S’ka pyetësorë aktivë për%1$d ditët e kaluara.
|
||||
\nQë të shihni pyetësorë për ditët e kaluara, ngarkoni më tepër pyetësorë.</item>
|
||||
</plurals>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Gabim lidhjeje - Incizimi u ndal</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">S’mund të nisni një mesazh zanor teksa jeni aktualisht duke incizuar një transmetim të drejtpërdrejtë. Ju lutemi, përfundoni transmetimin tuaj të drejtpërdrejtë, që të mund të nisni incizimin e një mesazhi zanor</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">S’niset dot mesazh zanor</string>
|
||||
</resources>
|
||||
|
|
@ -2898,4 +2898,26 @@
|
|||
<string name="room_profile_section_more_polls">Omröstningshistorik</string>
|
||||
<string name="thread_list_not_available">Din hemserver har inte stöd för att lista trådar än.</string>
|
||||
<string name="action_stop">Ja, sluta</string>
|
||||
</resources>
|
||||
<string name="room_polls_loading_error">Fel vid hämtning av omröstningar.</string>
|
||||
<string name="room_polls_load_more">Laddar fler omröstning</string>
|
||||
<string name="room_polls_wait_for_display">Visar omröstningar</string>
|
||||
<plurals name="room_polls_active_no_item_for_loaded_period">
|
||||
<item quantity="one">Det finns inga aktiva omröstningar från förra dagen.
|
||||
\nLadda fler omröstningar för att se omröstningar från tidigare dagar.</item>
|
||||
<item quantity="other">Det finns inga aktiva omröstningar från senaste %1$d dagarna.
|
||||
\nLadda fler omröstningar för att se omröstningar från tidigare dagar.</item>
|
||||
</plurals>
|
||||
<plurals name="room_polls_ended_no_item_for_loaded_period">
|
||||
<item quantity="one">Det finns inga omröstningar från förra dagen.
|
||||
\nLadda fler omröstningar för att se omröstningar från tidigare dagar.</item>
|
||||
<item quantity="other">Det finns inga omröstningar från senaste %1$d dagarna.
|
||||
\nLadda fler omröstningar för att se omröstningar från tidigare dagar.</item>
|
||||
</plurals>
|
||||
<string name="unable_to_decrypt_some_events_in_poll">På grund av avkrypteringsfel så kanske vissa röster inte räknas</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Anslutningsfel - Inspelning pausad</string>
|
||||
<string name="error_voice_broadcast_unable_to_play">Kan inte spela den här röstsändningen.</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">Du kan inte påbörja ett röstmeddelande eftersom du för närvarande spelar in en röstsändning. Vänligen avsluta din röstsändning för att börja spela in ett röstmeddelande</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Kan inte starta röstsändning</string>
|
||||
<string name="started_a_voice_broadcast">Startade en röstsändning</string>
|
||||
<string name="rich_text_editor_inline_code">Använd inline-kodformat</string>
|
||||
</resources>
|
||||
|
|
@ -3039,4 +3039,5 @@
|
|||
<string name="error_voice_message_broadcast_in_progress_message">Ви не можете розпочати запис голосового повідомлення, оскільки ви записуєте трансляцію наживо. Будь ласка, заверште її, щоб розпочати запис голосового повідомлення</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">Не вдалося розпочати запис голосового повідомлення</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Помилка з\'єднання - Запис призупинено</string>
|
||||
<string name="rich_text_editor_inline_code">Застосовувати вбудований формат коду</string>
|
||||
</resources>
|
||||
|
|
@ -1803,7 +1803,7 @@
|
|||
<item quantity="other">%d 个条目</item>
|
||||
</plurals>
|
||||
<string name="not_a_valid_qr_code">这不是有效的 Matrix QR码</string>
|
||||
<string name="user_code_scan">扫描二维码</string>
|
||||
<string name="user_code_scan">扫描QR码</string>
|
||||
<string name="add_people">添加人员</string>
|
||||
<string name="invite_friends">邀请朋友</string>
|
||||
<string name="settings_server_version">服务器版本</string>
|
||||
|
|
@ -2819,4 +2819,5 @@
|
|||
<string name="error_voice_broadcast_unable_to_play">无法播放此语音广播。</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">你无法启动语音消息因为你正在录制实时广播。请终止实时广播以开始录制语音消息</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">无法启动语音消息</string>
|
||||
</resources>
|
||||
<string name="ended_poll_indicator">结束了投票。</string>
|
||||
</resources>
|
||||
|
|
@ -2856,4 +2856,8 @@
|
|||
<item quantity="other">過去 %1$d 天沒有活躍的投票。
|
||||
\n載入更多投票以檢視過去幾天的投票。</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
<string name="error_voice_broadcast_no_connection_recording">連線錯誤 - 錄製已暫停</string>
|
||||
<string name="error_voice_message_broadcast_in_progress_message">您無法開始語音訊息,因為您目前正在錄製直播。請結束您的直播以開始錄製語音訊息</string>
|
||||
<string name="error_voice_message_broadcast_in_progress">無法開始語音訊息</string>
|
||||
<string name="rich_text_editor_inline_code">套用內嵌程式碼格式</string>
|
||||
</resources>
|
||||
|
|
@ -1063,6 +1063,9 @@
|
|||
<string name="settings_discovery_category">Discovery</string>
|
||||
<string name="settings_discovery_manage">Manage your discovery settings.</string>
|
||||
|
||||
<string name="settings_external_account_management_title">Account</string>
|
||||
<string name="settings_external_account_management">Your account details are managed separately at %1$s.</string>
|
||||
|
||||
<!-- analytics -->
|
||||
<string name="settings_analytics">Analytics</string>
|
||||
<string name="settings_opt_in_of_analytics">Send analytics data</string>
|
||||
|
|
@ -3120,6 +3123,7 @@
|
|||
<string name="error_voice_broadcast_already_in_progress_message">You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.</string>
|
||||
<string name="error_voice_broadcast_unable_to_play">Unable to play this voice broadcast.</string>
|
||||
<string name="error_voice_broadcast_no_connection_recording">Connection error - Recording paused</string>
|
||||
<string name="error_voice_broadcast_unable_to_decrypt">Unable to decrypt this voice broadcast.</string>
|
||||
<!-- Examples of usage: 6h 15min 30sec left / 15min 30sec left / 30sec left -->
|
||||
<string name="voice_broadcast_recording_time_left">%1$s left</string>
|
||||
<string name="stop_voice_broadcast_dialog_title">Stop live broadcasting?</string>
|
||||
|
|
@ -3207,6 +3211,7 @@
|
|||
<string name="room_polls_wait_for_display">Displaying polls</string>
|
||||
<string name="room_polls_load_more">Load more polls</string>
|
||||
<string name="room_polls_loading_error">Error fetching polls.</string>
|
||||
<string name="room_poll_details_go_to_timeline">View poll in timeline</string>
|
||||
|
||||
<!-- Location -->
|
||||
<string name="location_activity_title_static_sharing">Share location</string>
|
||||
|
|
@ -3502,7 +3507,11 @@
|
|||
<string name="rich_text_editor_link">Set link</string>
|
||||
<string name="rich_text_editor_numbered_list">Toggle numbered list</string>
|
||||
<string name="rich_text_editor_bullet_list">Toggle bullet list</string>
|
||||
<string name="rich_text_editor_indent">Indent</string>
|
||||
<string name="rich_text_editor_unindent">Unindent</string>
|
||||
<string name="rich_text_editor_quote">Toggle quote</string>
|
||||
<string name="rich_text_editor_inline_code">Apply inline code format</string>
|
||||
<string name="rich_text_editor_code_block">Toggle code block</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">Toggle full screen mode</string>
|
||||
|
||||
<string name="set_link_text">Text</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue