Merge branch 'develop' into feature/fga/improve_node_architecture
This commit is contained in:
commit
7f3679a15e
463 changed files with 3133 additions and 1555 deletions
|
|
@ -14,6 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix
|
||||
// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
|
||||
@Suppress("DSL_SCOPE_VIOLATION")
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
}
|
||||
|
||||
internal const val LOG_TAG = "Matrix"
|
||||
android {
|
||||
namespace = "io.element.android.libraries.dateformatter.api"
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter
|
||||
package io.element.android.libraries.dateformatter.api
|
||||
|
||||
interface DaySeparatorFormatter {
|
||||
fun format(timestamp: Long): String
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter
|
||||
package io.element.android.libraries.dateformatter.api
|
||||
|
||||
interface LastMessageFormatter {
|
||||
fun format(timestamp: Long?): String
|
||||
1
libraries/dateformatter/impl/.gitignore
vendored
Normal file
1
libraries/dateformatter/impl/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -27,17 +27,19 @@ anvil {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.dateformatter"
|
||||
namespace = "io.element.android.libraries.dateformatter.impl"
|
||||
|
||||
dependencies {
|
||||
anvil(projects.anvilcodegen)
|
||||
implementation(libs.dagger)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(projects.anvilannotations)
|
||||
|
||||
implementation(projects.libraries.dateformatter.api)
|
||||
api(libs.datetime)
|
||||
ksp(libs.showkase.processor)
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.test.truth)
|
||||
testImplementation(projects.libraries.dateformatter.test)
|
||||
}
|
||||
}
|
||||
0
libraries/dateformatter/impl/consumer-rules.pro
Normal file
0
libraries/dateformatter/impl/consumer-rules.pro
Normal file
21
libraries/dateformatter/impl/proguard-rules.pro
vendored
Normal file
21
libraries/dateformatter/impl/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
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2023 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -14,5 +13,4 @@
|
|||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest/>
|
||||
<manifest />
|
||||
|
|
@ -39,17 +39,17 @@ class DateFormatters @Inject constructor(
|
|||
|
||||
private val onlyTimeFormatter: DateTimeFormatter by lazy {
|
||||
val pattern = DateFormat.getBestDateTimePattern(locale, "HH:mm") ?: "HH:mm"
|
||||
DateTimeFormatter.ofPattern(pattern)
|
||||
DateTimeFormatter.ofPattern(pattern, locale)
|
||||
}
|
||||
|
||||
private val dateWithMonthFormatter: DateTimeFormatter by lazy {
|
||||
val pattern = DateFormat.getBestDateTimePattern(locale, "d MMM") ?: "d MMM"
|
||||
DateTimeFormatter.ofPattern(pattern)
|
||||
DateTimeFormatter.ofPattern(pattern, locale)
|
||||
}
|
||||
|
||||
private val dateWithYearFormatter: DateTimeFormatter by lazy {
|
||||
val pattern = DateFormat.getBestDateTimePattern(locale, "dd.MM.yyyy") ?: "dd.MM.yyyy"
|
||||
DateTimeFormatter.ofPattern(pattern)
|
||||
DateTimeFormatter.ofPattern(pattern, locale)
|
||||
}
|
||||
|
||||
internal fun formatTime(localDateTime: LocalDateTime): String {
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.dateformatter.DaySeparatorFormatter
|
||||
import io.element.android.libraries.dateformatter.api.DaySeparatorFormatter
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
||||
import io.element.android.libraries.dateformatter.api.LastMessageFormatter
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter.di
|
||||
package io.element.android.libraries.dateformatter.impl.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
|
|
@ -17,7 +17,8 @@
|
|||
package io.element.android.libraries.dateformatter.impl
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
||||
import io.element.android.libraries.dateformatter.api.LastMessageFormatter
|
||||
import io.element.android.libraries.dateformatter.test.FakeClock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.TimeZone
|
||||
import org.junit.Test
|
||||
1
libraries/dateformatter/test/.gitignore
vendored
Normal file
1
libraries/dateformatter/test/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
30
libraries/dateformatter/test/build.gradle.kts
Normal file
30
libraries/dateformatter/test/build.gradle.kts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.dateformatter.test"
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.dateformatter.api)
|
||||
api(libs.datetime)
|
||||
}
|
||||
}
|
||||
0
libraries/dateformatter/test/consumer-rules.pro
Normal file
0
libraries/dateformatter/test/consumer-rules.pro
Normal file
21
libraries/dateformatter/test/proguard-rules.pro
vendored
Normal file
21
libraries/dateformatter/test/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/test/src/main/AndroidManifest.xml
Normal file
16
libraries/dateformatter/test/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 />
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.dateformatter.impl
|
||||
package io.element.android.libraries.dateformatter.test
|
||||
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.test
|
||||
|
||||
import io.element.android.libraries.dateformatter.api.DaySeparatorFormatter
|
||||
|
||||
class FakeDaySeparatorFormatter : DaySeparatorFormatter {
|
||||
|
||||
private var format = ""
|
||||
|
||||
fun givenFormat(format: String) {
|
||||
this.format = format
|
||||
}
|
||||
|
||||
override fun format(timestamp: Long): String {
|
||||
return format
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,22 @@ val SystemGrey5Dark = Color(0xFF2C2C2E)
|
|||
val SystemGrey6Light = Color(0xFFF2F2F7)
|
||||
val SystemGrey6Dark = Color(0xFF1C1C1E)
|
||||
|
||||
// For light themes
|
||||
val Gray_25 = Color(0xFFF4F6FA)
|
||||
val Gray_50 = Color(0xFFE3E8F0)
|
||||
val Gray_100 = Color(0xFFC1C6CD)
|
||||
val Gray_150 = Color(0xFF8D97A5)
|
||||
val Gray_200 = Color(0xFF737D8C)
|
||||
val Black_900 = Color(0xFF17191C)
|
||||
|
||||
// For dark themes
|
||||
val Gray_250 = Color(0xFFA9B2BC)
|
||||
val Gray_300 = Color(0xFF8E99A4)
|
||||
val Gray_400 = Color(0xFF6F7882)
|
||||
val Gray_450 = Color(0xFF394049)
|
||||
val Black_800 = Color(0xFF15191E)
|
||||
val Black_950 = Color(0xFF21262C)
|
||||
|
||||
val Azure = Color(0xFF368BD6)
|
||||
val Kiwi = Color(0xFF74D12C)
|
||||
val Grape = Color(0xFFAC3BA8)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ import androidx.compose.ui.unit.sp
|
|||
// TODO Remove
|
||||
object ElementTextStyles {
|
||||
|
||||
val Button = TextStyle(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
lineHeight = 22.sp,
|
||||
fontStyle = FontStyle.Normal,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
object Bold {
|
||||
val largeTitle = TextStyle(
|
||||
fontSize = 34.sp,
|
||||
|
|
@ -180,6 +188,14 @@ object ElementTextStyles {
|
|||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
val formHeader = TextStyle(
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontStyle = FontStyle.Normal,
|
||||
lineHeight = 20.sp,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
|
||||
val footnote = TextStyle(
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
|
|
|
|||
|
|
@ -17,13 +17,12 @@
|
|||
package io.element.android.libraries.designsystem.components.dialogs
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.AlertDialogDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -31,10 +30,8 @@ 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
|
||||
|
||||
|
|
@ -67,43 +64,24 @@ fun ConfirmationDialog(
|
|||
Text(content)
|
||||
},
|
||||
dismissButton = {
|
||||
Row(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Column {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
onCancelClicked()
|
||||
}) {
|
||||
Text(cancelText)
|
||||
}
|
||||
if (thirdButtonText != null) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
onThirdButtonClicked()
|
||||
}) {
|
||||
Text(thirdButtonText)
|
||||
}
|
||||
if (thirdButtonText != null) {
|
||||
// If there is a 3rd item it should be at the end of the dialog
|
||||
// Having this 3rd action is discouraged, see https://m3.material.io/components/dialogs/guidelines#e13b68f5-e367-4275-ad6f-c552ee8e358f
|
||||
TextButton(onClick = onThirdButtonClicked) {
|
||||
Text(thirdButtonText)
|
||||
}
|
||||
}
|
||||
TextButton(onClick = onCancelClicked) {
|
||||
Text(cancelText)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Row(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
onSubmitClicked()
|
||||
}
|
||||
) {
|
||||
Text(submitText)
|
||||
TextButton(
|
||||
onClick = {
|
||||
onSubmitClicked()
|
||||
}
|
||||
) {
|
||||
Text(submitText)
|
||||
}
|
||||
},
|
||||
shape = shape,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -55,24 +56,14 @@ fun ErrorDialog(
|
|||
modifier = modifier,
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(text = title)
|
||||
Text(title)
|
||||
},
|
||||
text = {
|
||||
Text(content)
|
||||
},
|
||||
confirmButton = {
|
||||
Row(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
onDismiss()
|
||||
}
|
||||
) {
|
||||
Text(submitText)
|
||||
}
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(submitText)
|
||||
}
|
||||
},
|
||||
shape = shape,
|
||||
|
|
|
|||
|
|
@ -16,12 +16,9 @@
|
|||
|
||||
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
|
||||
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||
|
||||
@Composable
|
||||
fun ElementPreviewLight(
|
||||
|
|
@ -55,9 +52,8 @@ private fun ElementPreview(
|
|||
) {
|
||||
ElementTheme(darkTheme = darkTheme) {
|
||||
if (showBackground) {
|
||||
Box(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
||||
content()
|
||||
}
|
||||
// If we have a proper contentColor applied we need a Surface instead of a Box
|
||||
Surface { content() }
|
||||
} else {
|
||||
content()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ 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.Black_800
|
||||
import io.element.android.libraries.designsystem.Black_950
|
||||
import io.element.android.libraries.designsystem.DarkGrey
|
||||
import io.element.android.libraries.designsystem.Gray_400
|
||||
import io.element.android.libraries.designsystem.Gray_450
|
||||
import io.element.android.libraries.designsystem.SystemGrey5Dark
|
||||
import io.element.android.libraries.designsystem.SystemGrey6Dark
|
||||
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
|
||||
|
|
@ -30,6 +34,8 @@ fun elementColorsDark() = ElementColors(
|
|||
messageFromMeBackground = SystemGrey5Dark,
|
||||
messageFromOtherBackground = SystemGrey6Dark,
|
||||
messageHighlightedBackground = Azure,
|
||||
quaternary = Gray_400,
|
||||
quinary = Gray_450,
|
||||
isLight = false,
|
||||
)
|
||||
|
||||
|
|
@ -48,12 +54,12 @@ val materialColorSchemeDark = darkColorScheme(
|
|||
// TODO onTertiary = ColorDarkTokens.OnTertiary,
|
||||
// TODO tertiaryContainer = ColorDarkTokens.TertiaryContainer,
|
||||
// TODO onTertiaryContainer = ColorDarkTokens.OnTertiaryContainer,
|
||||
background = Color.Black,
|
||||
background = Black_800,
|
||||
onBackground = Color.White,
|
||||
surface = Color.Black,
|
||||
surface = Black_800,
|
||||
onSurface = Color.White,
|
||||
surfaceVariant = SystemGrey5Dark,
|
||||
// TODO onSurfaceVariant = ColorDarkTokens.OnSurfaceVariant,
|
||||
surfaceVariant = Black_950,
|
||||
onSurfaceVariant = Color.White,
|
||||
// TODO surfaceTint = primary,
|
||||
// TODO inverseSurface = ColorDarkTokens.InverseSurface,
|
||||
// TODO inverseOnSurface = ColorDarkTokens.InverseOnSurface,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,12 @@ 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.Black_900
|
||||
import io.element.android.libraries.designsystem.Gray_100
|
||||
import io.element.android.libraries.designsystem.Gray_150
|
||||
import io.element.android.libraries.designsystem.Gray_200
|
||||
import io.element.android.libraries.designsystem.Gray_25
|
||||
import io.element.android.libraries.designsystem.Gray_50
|
||||
import io.element.android.libraries.designsystem.SystemGrey5Light
|
||||
import io.element.android.libraries.designsystem.SystemGrey6Light
|
||||
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
|
||||
|
|
@ -30,21 +35,23 @@ fun elementColorsLight() = ElementColors(
|
|||
messageFromMeBackground = SystemGrey5Light,
|
||||
messageFromOtherBackground = SystemGrey6Light,
|
||||
messageHighlightedBackground = Azure,
|
||||
quaternary = Gray_100,
|
||||
quinary = Gray_50,
|
||||
isLight = true,
|
||||
)
|
||||
|
||||
// TODO Lots of colors are missing
|
||||
val materialColorSchemeLight = lightColorScheme(
|
||||
primary = Color.Black,
|
||||
primary = Black_900,
|
||||
onPrimary = Color.White,
|
||||
// TODO primaryContainer = ColorLightTokens.PrimaryContainer,
|
||||
// TODO onPrimaryContainer = ColorLightTokens.OnPrimaryContainer,
|
||||
// TODO inversePrimary = ColorLightTokens.InversePrimary,
|
||||
secondary = LightGrey,
|
||||
secondary = Gray_200,
|
||||
// TODO onSecondary = ColorLightTokens.OnSecondary,
|
||||
// TODO secondaryContainer = ColorLightTokens.SecondaryContainer,
|
||||
// TODO onSecondaryContainer = ColorLightTokens.OnSecondaryContainer,
|
||||
tertiary = Color.Black,
|
||||
tertiary = Gray_150,
|
||||
// TODO onTertiary = ColorLightTokens.OnTertiary,
|
||||
// TODO tertiaryContainer = ColorLightTokens.TertiaryContainer,
|
||||
// TODO onTertiaryContainer = ColorLightTokens.OnTertiaryContainer,
|
||||
|
|
@ -52,8 +59,8 @@ val materialColorSchemeLight = lightColorScheme(
|
|||
onBackground = Color.Black,
|
||||
surface = Color.White,
|
||||
onSurface = Color.Black,
|
||||
surfaceVariant = SystemGrey5Light,
|
||||
onSurfaceVariant = Color.Black,
|
||||
surfaceVariant = Gray_25,
|
||||
onSurfaceVariant = Gray_150,
|
||||
// TODO surfaceTint = primary,
|
||||
// TODO inverseSurface = ColorLightTokens.InverseSurface,
|
||||
// TODO inverseOnSurface = ColorLightTokens.InverseOnSurface,
|
||||
|
|
|
|||
|
|
@ -16,15 +16,19 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.theme
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@Stable
|
||||
class ElementColors(
|
||||
messageFromMeBackground: Color,
|
||||
messageFromOtherBackground: Color,
|
||||
messageHighlightedBackground: Color,
|
||||
quaternary: Color,
|
||||
quinary: Color,
|
||||
isLight: Boolean,
|
||||
) {
|
||||
var messageFromMeBackground by mutableStateOf(messageFromMeBackground)
|
||||
|
|
@ -34,6 +38,12 @@ class ElementColors(
|
|||
var messageHighlightedBackground by mutableStateOf(messageHighlightedBackground)
|
||||
private set
|
||||
|
||||
var quaternary by mutableStateOf(quaternary)
|
||||
private set
|
||||
|
||||
var quinary by mutableStateOf(quinary)
|
||||
private set
|
||||
|
||||
var isLight by mutableStateOf(isLight)
|
||||
private set
|
||||
|
||||
|
|
@ -41,11 +51,15 @@ class ElementColors(
|
|||
messageFromMeBackground: Color = this.messageFromMeBackground,
|
||||
messageFromOtherBackground: Color = this.messageFromOtherBackground,
|
||||
messageHighlightedBackground: Color = this.messageHighlightedBackground,
|
||||
quaternary: Color = this.quaternary,
|
||||
quinary: Color = this.quinary,
|
||||
isLight: Boolean = this.isLight,
|
||||
) = ElementColors(
|
||||
messageFromMeBackground = messageFromMeBackground,
|
||||
messageFromOtherBackground = messageFromOtherBackground,
|
||||
messageHighlightedBackground = messageHighlightedBackground,
|
||||
quaternary = quaternary,
|
||||
quinary = quinary,
|
||||
isLight = isLight,
|
||||
)
|
||||
|
||||
|
|
@ -53,6 +67,8 @@ class ElementColors(
|
|||
messageFromMeBackground = other.messageFromMeBackground
|
||||
messageFromOtherBackground = other.messageFromOtherBackground
|
||||
messageHighlightedBackground = other.messageHighlightedBackground
|
||||
quaternary = other.quaternary
|
||||
quinary = other.quinary
|
||||
isLight = other.isLight
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,15 +49,16 @@ val LocalColors = staticCompositionLocalOf { elementColorsLight() }
|
|||
fun ElementTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
dynamicColor: Boolean = false, /* true to enable MaterialYou */
|
||||
lightColors: ElementColors = elementColorsLight(),
|
||||
darkColors: ElementColors = elementColorsDark(),
|
||||
colors: ElementColors = if (darkTheme) elementColorsDark() else elementColorsLight(),
|
||||
materialLightColors: ColorScheme = materialColorSchemeLight,
|
||||
materialDarkColors: ColorScheme = materialColorSchemeDark,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val useDarkIcons = !darkTheme
|
||||
val currentColor = remember(darkTheme) { if (darkTheme) darkColors else lightColors }
|
||||
val currentColor = remember(darkTheme) {
|
||||
colors.copy()
|
||||
}.apply { updateColorsFrom(colors) }
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -75,9 +76,8 @@ fun ElementTheme(
|
|||
darkIcons = useDarkIcons
|
||||
)
|
||||
}
|
||||
val rememberedColors = remember { currentColor.copy() }.apply { updateColorsFrom(currentColor) }
|
||||
CompositionLocalProvider(
|
||||
LocalColors provides rememberedColors,
|
||||
LocalColors provides currentColor,
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
|
|
|
|||
|
|
@ -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.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.ui.strings.R.string as StringR
|
||||
|
||||
@Composable
|
||||
fun BackButton(
|
||||
action: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
icon: ImageVector = Icons.Default.ArrowBack,
|
||||
contentDescription: String = stringResource(StringR.action_back),
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
IconButton(
|
||||
modifier = modifier,
|
||||
onClick = action,
|
||||
enabled = enabled,
|
||||
) {
|
||||
Icon(imageVector = icon, contentDescription = contentDescription)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun BackButtonPreviewLight() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun BackButtonPreviewDark() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Column {
|
||||
BackButton(action = { }, enabled = true, contentDescription = "Back")
|
||||
BackButton(action = { }, enabled = false, contentDescription = "Back")
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
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
|
||||
|
||||
|
|
@ -37,11 +38,11 @@ fun Button(
|
|||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
shape: Shape = ButtonDefaults.shape,
|
||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
||||
shape: Shape = ElementButtonDefaults.shape,
|
||||
colors: ButtonColors = ElementButtonDefaults.buttonColors(),
|
||||
elevation: ButtonElevation? = ElementButtonDefaults.buttonElevation(),
|
||||
border: BorderStroke? = null,
|
||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||
contentPadding: PaddingValues = ElementButtonDefaults.ContentPadding,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
content: @Composable RowScope.() -> Unit
|
||||
) {
|
||||
|
|
@ -59,6 +60,17 @@ fun Button(
|
|||
)
|
||||
}
|
||||
|
||||
object ElementButtonDefaults {
|
||||
val ContentPadding = PaddingValues(horizontal = 24.dp, vertical = 14.dp)
|
||||
val shape: Shape @Composable get() = ButtonDefaults.shape
|
||||
@Composable
|
||||
fun buttonElevation(): ButtonElevation = ButtonDefaults.buttonElevation()
|
||||
|
||||
@Composable
|
||||
fun buttonColors(): ButtonColors = ButtonDefaults.buttonColors()
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ButtonsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
|
|
|||
|
|
@ -29,8 +29,17 @@ import androidx.compose.material3.TextFieldColors
|
|||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.focus.FocusManager
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -40,7 +49,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
|||
import io.element.android.libraries.designsystem.utils.allBooleans
|
||||
import io.element.android.libraries.designsystem.utils.asInt
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun OutlinedTextField(
|
||||
value: String,
|
||||
|
|
@ -88,6 +97,16 @@ fun OutlinedTextField(
|
|||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
fun Modifier.onTabOrEnterKeyFocusNext(focusManager: FocusManager): Modifier = onPreviewKeyEvent { event ->
|
||||
if (event.type == KeyEventType.KeyUp && (event.key == Key.Tab || event.key == Key.Enter)) {
|
||||
focusManager.moveFocus(FocusDirection.Down)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun OutlinedTextFieldsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
|
|
|||
37
libraries/encrypted-db/build.gradle.kts
Normal file
37
libraries/encrypted-db/build.gradle.kts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.encrypteddb"
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
consumerProguardFiles("consumer-proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.sqldelight.driver.android)
|
||||
implementation(libs.sqlcipher)
|
||||
implementation(libs.sqlite)
|
||||
implementation(libs.androidx.security.crypto)
|
||||
}
|
||||
25
libraries/encrypted-db/consumer-proguard-rules.pro
Normal file
25
libraries/encrypted-db/consumer-proguard-rules.pro
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# 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
|
||||
|
||||
# Prevent ProGuard from renaming internal SQLCipher classes, which breaks the library.
|
||||
# From https://github.com/sqlcipher/android-database-sqlcipher#proguard
|
||||
-keep class net.sqlcipher.** { *; }
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.encrypteddb
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import io.element.encrypteddb.passphrase.PassphraseProvider
|
||||
import net.sqlcipher.database.SupportFactory
|
||||
|
||||
/**
|
||||
* Creates an encrypted version of the [SqlDriver] using SQLCipher's [SupportFactory].
|
||||
* @param passphraseProvider Provides the passphrase needed to use the SQLite database with SQLCipher.
|
||||
*/
|
||||
class SqlCipherDriverFactory(
|
||||
private val passphraseProvider: PassphraseProvider,
|
||||
) {
|
||||
/**
|
||||
* Returns a valid [SqlDriver] with SQLCipher support.
|
||||
* @param schema The SQLite DB schema.
|
||||
* @param name The name of the database to create.
|
||||
* @param context Android [Context], used to instantiate the driver.
|
||||
*/
|
||||
fun create(schema: SqlDriver.Schema, name: String, context: Context): SqlDriver {
|
||||
val passphrase = passphraseProvider.getPassphrase()
|
||||
val factory = SupportFactory(passphrase)
|
||||
return AndroidSqliteDriver(schema = schema, context = context, name = name, factory = factory)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.encrypteddb.passphrase
|
||||
|
||||
/**
|
||||
* An abstraction to implement secure providers for SQLCipher passphrases.
|
||||
*/
|
||||
interface PassphraseProvider {
|
||||
/**
|
||||
* Returns a passphrase for SQLCipher in [ByteArray] format.
|
||||
*/
|
||||
fun getPassphrase(): ByteArray
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.encrypteddb.passphrase
|
||||
|
||||
import android.content.Context
|
||||
import androidx.security.crypto.EncryptedFile
|
||||
import java.io.File
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
* Provides a secure passphrase for SQLCipher by generating a random secret and storing it into an [EncryptedFile].
|
||||
* @param context Android [Context], used by [EncryptedFile] for cryptographic operations.
|
||||
* @param file Destination file where the key will be stored.
|
||||
* @param alias Alias of the key used to encrypt & decrypt the [EncryptedFile]'s contents.
|
||||
* @param secretSize Length of the generated secret.
|
||||
*/
|
||||
class RandomSecretPassphraseProvider(
|
||||
private val context: Context,
|
||||
private val file: File,
|
||||
private val alias: String,
|
||||
private val secretSize: Int = 256,
|
||||
) : PassphraseProvider {
|
||||
|
||||
override fun getPassphrase(): ByteArray {
|
||||
val encryptedFile = EncryptedFile.Builder(
|
||||
file,
|
||||
context,
|
||||
alias,
|
||||
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
|
||||
).build()
|
||||
return if (!file.exists()) {
|
||||
val secret = generateSecret()
|
||||
encryptedFile.openFileOutput().use { it.write(secret) }
|
||||
secret
|
||||
} else {
|
||||
encryptedFile.openFileInput().use { it.readBytes() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSecret(): ByteArray {
|
||||
val buffer = ByteArray(size = secretSize)
|
||||
SecureRandom().nextBytes(buffer)
|
||||
return buffer
|
||||
}
|
||||
}
|
||||
44
libraries/matrix/api/build.gradle.kts
Normal file
44
libraries/matrix/api/build.gradle.kts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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")
|
||||
id("kotlin-parcelize")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.10"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.matrix.api"
|
||||
}
|
||||
|
||||
anvil {
|
||||
generateDaggerFactories.set(true)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// api(projects.libraries.rustsdk)
|
||||
api(libs.matrix.sdk)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(libs.dagger)
|
||||
implementation(projects.libraries.core)
|
||||
implementation("net.java.dev.jna:jna:5.13.0@aar")
|
||||
implementation(libs.serialization.json)
|
||||
api(projects.libraries.sessionStorage.api)
|
||||
implementation(libs.coroutines.core)
|
||||
}
|
||||
|
|
@ -14,14 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix
|
||||
package io.element.android.libraries.matrix.api
|
||||
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import org.matrix.rustcomponents.sdk.MediaSource
|
||||
import java.io.Closeable
|
||||
|
||||
|
|
@ -33,7 +32,6 @@ interface MatrixClient : Closeable {
|
|||
fun roomSummaryDataSource(): RoomSummaryDataSource
|
||||
fun mediaResolver(): MediaResolver
|
||||
suspend fun logout()
|
||||
fun userId(): UserId
|
||||
suspend fun loadUserDisplayName(): Result<String>
|
||||
suspend fun loadUserAvatarURLString(): Result<String>
|
||||
suspend fun loadMediaContentForSource(source: MediaSource): Result<ByteArray>
|
||||
|
|
@ -14,18 +14,18 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.auth
|
||||
package io.element.android.libraries.matrix.api.auth
|
||||
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface MatrixAuthenticationService {
|
||||
fun isLoggedIn(): Flow<Boolean>
|
||||
suspend fun getLatestSessionId(): SessionId?
|
||||
suspend fun restoreSession(sessionId: SessionId): MatrixClient?
|
||||
fun getHomeserver(): String?
|
||||
fun getHomeserverOrDefault(): String
|
||||
fun getHomeserverDetails(): StateFlow<MatrixHomeServerDetails?>
|
||||
suspend fun setHomeserver(homeserver: String)
|
||||
suspend fun login(username: String, password: String): SessionId
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.matrix.api.auth
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.rustcomponents.sdk.HomeserverLoginDetails
|
||||
|
||||
@Parcelize
|
||||
data class MatrixHomeServerDetails(
|
||||
val url: String,
|
||||
val supportsPasswordLogin: Boolean,
|
||||
val authenticationIssuer: String?
|
||||
): Parcelable {
|
||||
constructor(homeserverLoginDetails: HomeserverLoginDetails) : this(
|
||||
homeserverLoginDetails.url(),
|
||||
homeserverLoginDetails.supportsPasswordLogin(),
|
||||
homeserverLoginDetails.authenticationIssuer()
|
||||
)
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.core
|
||||
package io.element.android.libraries.matrix.api.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.core
|
||||
package io.element.android.libraries.matrix.api.core
|
||||
|
||||
import io.element.android.libraries.matrix.BuildConfig
|
||||
import io.element.android.libraries.matrix.api.BuildConfig
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.core
|
||||
package io.element.android.libraries.matrix.api.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
|
|
@ -14,9 +14,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.core
|
||||
package io.element.android.libraries.matrix.api.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
@JvmInline
|
||||
value class SessionId(val value: String) : Serializable
|
||||
typealias SessionId = UserId
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.core
|
||||
package io.element.android.libraries.matrix.api.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.media
|
||||
package io.element.android.libraries.matrix.api.media
|
||||
|
||||
import org.matrix.rustcomponents.sdk.MediaSource
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.permalink
|
||||
package io.element.android.libraries.matrix.api.permalink
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.permalink
|
||||
package io.element.android.libraries.matrix.api.permalink
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.permalink
|
||||
package io.element.android.libraries.matrix.api.permalink
|
||||
|
||||
import android.net.Uri
|
||||
import android.net.UrlQuerySanitizer
|
||||
import io.element.android.libraries.matrix.core.MatrixPatterns
|
||||
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
||||
import timber.log.Timber
|
||||
import java.net.URLDecoder
|
||||
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room
|
||||
package io.element.android.libraries.matrix.api.room
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface MatrixRoom {
|
||||
|
|
@ -46,5 +46,4 @@ interface MatrixRoom {
|
|||
suspend fun replyMessage(eventId: EventId, message: String): Result<Unit>
|
||||
|
||||
suspend fun redactEvent(eventId: EventId, reason: String? = null): Result<Unit>
|
||||
|
||||
}
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room
|
||||
package io.element.android.libraries.matrix.api.room
|
||||
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
sealed interface RoomSummary {
|
||||
data class Empty(val identifier: String) : RoomSummary
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.matrix.api.room
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface RoomSummaryDataSource {
|
||||
fun roomSummaries(): StateFlow<List<RoomSummary>>
|
||||
fun setSlidingSyncRange(range: IntRange)
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room.message
|
||||
package io.element.android.libraries.matrix.api.room.message
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
|
||||
data class RoomMessage(
|
||||
val eventId: EventId,
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.timeline
|
||||
package io.element.android.libraries.matrix.api.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
|
|
@ -14,11 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.timeline
|
||||
package io.element.android.libraries.matrix.api.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import org.matrix.rustcomponents.sdk.EventTimelineItem
|
||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||
import org.matrix.rustcomponents.sdk.VirtualTimelineItem
|
||||
|
||||
sealed interface MatrixTimelineItem {
|
||||
|
|
@ -31,14 +30,3 @@ sealed interface MatrixTimelineItem {
|
|||
object Other : MatrixTimelineItem
|
||||
}
|
||||
|
||||
fun TimelineItem.asMatrixTimelineItem(): MatrixTimelineItem {
|
||||
val asEvent = asEvent()
|
||||
if (asEvent != null) {
|
||||
return MatrixTimelineItem.Event(asEvent)
|
||||
}
|
||||
val asVirtual = asVirtual()
|
||||
if (asVirtual != null) {
|
||||
return MatrixTimelineItem.Virtual(asVirtual)
|
||||
}
|
||||
return MatrixTimelineItem.Other
|
||||
}
|
||||
|
|
@ -14,9 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.tracing
|
||||
|
||||
import timber.log.Timber
|
||||
package io.element.android.libraries.matrix.api.tracing
|
||||
|
||||
data class TracingConfiguration(
|
||||
val overrides: Map<Target, LogLevel> = emptyMap()
|
||||
|
|
@ -74,12 +72,6 @@ sealed class LogLevel(val filter: String) {
|
|||
object Error : LogLevel("error")
|
||||
}
|
||||
|
||||
fun setupTracing(tracingConfiguration: TracingConfiguration) {
|
||||
val filter = tracingConfiguration.filter
|
||||
Timber.v("Tracing config filter = $filter")
|
||||
org.matrix.rustcomponents.sdk.setupTracing(filter)
|
||||
}
|
||||
|
||||
object TracingConfigurations {
|
||||
val release = TracingConfiguration(overrides = mapOf(Target.Common to LogLevel.Info))
|
||||
val debug = TracingConfiguration(overrides = mapOf(Target.Common to LogLevel.Info))
|
||||
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.matrix"
|
||||
namespace = "io.element.android.libraries.matrix.impl"
|
||||
}
|
||||
|
||||
anvil {
|
||||
|
|
@ -34,6 +34,7 @@ dependencies {
|
|||
// api(projects.libraries.rustsdk)
|
||||
api(libs.matrix.sdk)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(libs.dagger)
|
||||
implementation(projects.libraries.core)
|
||||
implementation("net.java.dev.jna:jna:5.13.0@aar")
|
||||
22
libraries/matrix/impl/src/main/AndroidManifest.xml
Normal file
22
libraries/matrix/impl/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
</manifest>
|
||||
|
|
@ -14,21 +14,20 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix
|
||||
package io.element.android.libraries.matrix.impl
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.media.RustMediaResolver
|
||||
import io.element.android.libraries.matrix.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.room.RustMatrixRoom
|
||||
import io.element.android.libraries.matrix.room.RustRoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.session.SessionStore
|
||||
import io.element.android.libraries.matrix.session.sessionId
|
||||
import io.element.android.libraries.matrix.sync.SlidingSyncObserverProxy
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.impl.media.RustMediaResolver
|
||||
import io.element.android.libraries.matrix.impl.room.RustMatrixRoom
|
||||
import io.element.android.libraries.matrix.impl.room.RustRoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.impl.sync.SlidingSyncObserverProxy
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
|
|
@ -51,7 +50,7 @@ class RustMatrixClient constructor(
|
|||
private val baseDirectory: File,
|
||||
) : MatrixClient {
|
||||
|
||||
override val sessionId: SessionId = client.session().sessionId()
|
||||
override val sessionId: UserId = UserId(client.userId())
|
||||
|
||||
private val clientDelegate = object : ClientDelegate {
|
||||
override fun didReceiveAuthError(isSoftLogout: Boolean) {
|
||||
|
|
@ -174,11 +173,9 @@ class RustMatrixClient constructor(
|
|||
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
|
||||
}
|
||||
baseDirectory.deleteSessionDirectory(userID = client.userId())
|
||||
sessionStore.reset()
|
||||
sessionStore.removeSession(client.userId())
|
||||
}
|
||||
|
||||
override fun userId(): UserId = UserId(client.userId())
|
||||
|
||||
override suspend fun loadUserDisplayName(): Result<String> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
client.displayName()
|
||||
|
|
@ -14,28 +14,36 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.auth
|
||||
package io.element.android.libraries.matrix.impl.auth
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.RustMatrixClient
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrix.session.SessionStore
|
||||
import io.element.android.libraries.matrix.session.sessionId
|
||||
import io.element.android.libraries.matrix.util.logError
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.impl.RustMatrixClient
|
||||
import io.element.android.libraries.matrix.impl.util.logError
|
||||
import io.element.android.libraries.sessionstorage.api.SessionData
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.AuthenticationService
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
import org.matrix.rustcomponents.sdk.ClientBuilder
|
||||
import org.matrix.rustcomponents.sdk.Session
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
@SingleIn(AppScope::class)
|
||||
class RustMatrixAuthenticationService @Inject constructor(
|
||||
private val baseDirectory: File,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
|
|
@ -44,23 +52,25 @@ class RustMatrixAuthenticationService @Inject constructor(
|
|||
private val authService: AuthenticationService,
|
||||
) : MatrixAuthenticationService {
|
||||
|
||||
private var currentHomeserver = MutableStateFlow<MatrixHomeServerDetails?>(null)
|
||||
|
||||
override fun isLoggedIn(): Flow<Boolean> {
|
||||
return sessionStore.isLoggedIn()
|
||||
}
|
||||
|
||||
override suspend fun getLatestSessionId(): SessionId? = withContext(coroutineDispatchers.io) {
|
||||
sessionStore.getLatestSession()?.sessionId()
|
||||
sessionStore.getLatestSession()?.userId?.let { UserId(it) }
|
||||
}
|
||||
|
||||
override suspend fun restoreSession(sessionId: SessionId) = withContext(coroutineDispatchers.io) {
|
||||
sessionStore.getSession(sessionId)
|
||||
?.let { session ->
|
||||
sessionStore.getSession(sessionId.value)
|
||||
?.let { sessionData ->
|
||||
try {
|
||||
ClientBuilder()
|
||||
.basePath(baseDirectory.absolutePath)
|
||||
.username(session.userId)
|
||||
.username(sessionData.userId)
|
||||
.build().apply {
|
||||
restoreSession(session)
|
||||
restoreSession(sessionData.toSession())
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
logError(throwable)
|
||||
|
|
@ -71,13 +81,15 @@ class RustMatrixAuthenticationService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getHomeserver(): String? = authService.homeserverDetails()?.url()
|
||||
|
||||
override fun getHomeserverOrDefault(): String = getHomeserver() ?: "matrix.org"
|
||||
override fun getHomeserverDetails(): StateFlow<MatrixHomeServerDetails?> = currentHomeserver
|
||||
|
||||
override suspend fun setHomeserver(homeserver: String) {
|
||||
withContext(coroutineDispatchers.io) {
|
||||
authService.configureHomeserver(homeserver)
|
||||
val homeServerDetails = authService.homeserverDetails()?.use { MatrixHomeServerDetails(it) }
|
||||
if (homeServerDetails != null) {
|
||||
currentHomeserver.value = homeServerDetails.copy(url = homeserver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,8 +102,8 @@ class RustMatrixAuthenticationService @Inject constructor(
|
|||
throw failure
|
||||
}
|
||||
val session = client.session()
|
||||
sessionStore.storeData(session)
|
||||
session.sessionId()
|
||||
sessionStore.storeData(session.toSessionData())
|
||||
SessionId(session.userId)
|
||||
}
|
||||
|
||||
private fun createMatrixClient(client: Client): MatrixClient {
|
||||
|
|
@ -104,3 +116,23 @@ class RustMatrixAuthenticationService @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SessionData.toSession() = Session(
|
||||
accessToken = accessToken,
|
||||
refreshToken = refreshToken,
|
||||
userId = userId,
|
||||
deviceId = deviceId,
|
||||
homeserverUrl = homeserverUrl,
|
||||
isSoftLogout = isSoftLogout,
|
||||
slidingSyncProxy = slidingSyncProxy,
|
||||
)
|
||||
|
||||
private fun Session.toSessionData() = SessionData(
|
||||
userId = userId,
|
||||
deviceId = deviceId,
|
||||
accessToken = accessToken,
|
||||
refreshToken = refreshToken,
|
||||
homeserverUrl = homeserverUrl,
|
||||
isSoftLogout = isSoftLogout,
|
||||
slidingSyncProxy = slidingSyncProxy,
|
||||
)
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.di
|
||||
package io.element.android.libraries.matrix.impl.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
|
|
@ -14,9 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.media
|
||||
package io.element.android.libraries.matrix.impl.media
|
||||
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
|
||||
|
||||
internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver {
|
||||
|
|
@ -28,13 +29,14 @@ internal class RustMediaResolver(private val client: MatrixClient) : MediaResolv
|
|||
}
|
||||
|
||||
override suspend fun resolve(meta: MediaResolver.Meta): ByteArray? {
|
||||
if (meta.source == null) return null
|
||||
return when (meta.kind) {
|
||||
is MediaResolver.Kind.Content -> client.loadMediaContentForSource(meta.source)
|
||||
val source = meta.source ?: return null
|
||||
val kind = meta.kind
|
||||
return when (kind) {
|
||||
is MediaResolver.Kind.Content -> client.loadMediaContentForSource(source)
|
||||
is MediaResolver.Kind.Thumbnail -> client.loadMediaThumbnailForSource(
|
||||
meta.source,
|
||||
meta.kind.width.toLong(),
|
||||
meta.kind.height.toLong()
|
||||
source,
|
||||
kind.width.toLong(),
|
||||
kind.height.toLong()
|
||||
)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
|
@ -14,10 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.room.message.RoomMessageFactory
|
||||
import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDetails
|
||||
import org.matrix.rustcomponents.sdk.Room
|
||||
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
|
||||
|
||||
|
|
@ -14,13 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.timeline.RustMatrixTimeline
|
||||
import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
|
@ -32,7 +33,6 @@ import org.matrix.rustcomponents.sdk.SlidingSyncRoom
|
|||
import org.matrix.rustcomponents.sdk.UpdateSummary
|
||||
import org.matrix.rustcomponents.sdk.genTransactionId
|
||||
import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown
|
||||
import timber.log.Timber
|
||||
|
||||
class RustMatrixRoom(
|
||||
private val slidingSyncUpdateFlow: Flow<UpdateSummary>,
|
||||
|
|
@ -14,11 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.sync.roomListDiff
|
||||
import io.element.android.libraries.matrix.sync.state
|
||||
import io.element.android.libraries.matrix.impl.sync.roomListDiff
|
||||
import io.element.android.libraries.matrix.impl.sync.state
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
|
|
@ -39,11 +41,6 @@ import timber.log.Timber
|
|||
import java.io.Closeable
|
||||
import java.util.UUID
|
||||
|
||||
interface RoomSummaryDataSource {
|
||||
fun roomSummaries(): StateFlow<List<RoomSummary>>
|
||||
fun setSlidingSyncRange(range: IntRange)
|
||||
}
|
||||
|
||||
internal class RustRoomSummaryDataSource(
|
||||
private val slidingSyncUpdateFlow: Flow<UpdateSummary>,
|
||||
private val slidingSync: SlidingSync,
|
||||
|
|
@ -14,10 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.room.message
|
||||
package io.element.android.libraries.matrix.impl.room.message
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
import org.matrix.rustcomponents.sdk.EventTimelineItem
|
||||
|
||||
class RoomMessageFactory {
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.sync
|
||||
package io.element.android.libraries.matrix.impl.sync
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.sync
|
||||
package io.element.android.libraries.matrix.impl.sync
|
||||
|
||||
import io.element.android.libraries.matrix.util.mxCallbackFlow
|
||||
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -14,8 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.timeline
|
||||
package io.element.android.libraries.matrix.impl.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||
|
||||
fun TimelineItem.asMatrixTimelineItem(): MatrixTimelineItem {
|
||||
val asEvent = asEvent()
|
||||
if (asEvent != null) {
|
||||
return MatrixTimelineItem.Event(asEvent)
|
||||
}
|
||||
val asVirtual = asVirtual()
|
||||
if (asVirtual != null) {
|
||||
return MatrixTimelineItem.Virtual(asVirtual)
|
||||
}
|
||||
return MatrixTimelineItem.Other
|
||||
}
|
||||
|
|
@ -14,12 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.timeline
|
||||
package io.element.android.libraries.matrix.impl.timeline
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.util.TaskHandleBag
|
||||
import io.element.android.libraries.matrix.impl.util.TaskHandleBag
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.tracing
|
||||
|
||||
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
|
||||
import timber.log.Timber
|
||||
|
||||
fun setupTracing(tracingConfiguration: TracingConfiguration) {
|
||||
val filter = tracingConfiguration.filter
|
||||
Timber.v("Tracing config filter = $filter")
|
||||
org.matrix.rustcomponents.sdk.setupTracing(filter)
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.util
|
||||
package io.element.android.libraries.matrix.impl.util
|
||||
|
||||
import kotlinx.coroutines.channels.ProducerScope
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.util
|
||||
package io.element.android.libraries.matrix.impl.util
|
||||
|
||||
import org.matrix.rustcomponents.sdk.ClientException
|
||||
import timber.log.Timber
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.util
|
||||
package io.element.android.libraries.matrix.impl.util
|
||||
|
||||
import org.matrix.rustcomponents.sdk.TaskHandle
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.session
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.matrix.rustcomponents.sdk.Session
|
||||
import javax.inject.Inject
|
||||
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_sessions")
|
||||
|
||||
// TODO It contains the access token, so it has to be stored in a more secured storage.
|
||||
private val sessionKey = stringPreferencesKey("session")
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class PreferencesSessionStore @Inject constructor(
|
||||
@ApplicationContext context: Context
|
||||
) : SessionStore {
|
||||
@Serializable
|
||||
data class SessionData(
|
||||
val accessToken: String,
|
||||
val deviceId: String,
|
||||
val homeserverUrl: String,
|
||||
val isSoftLogout: Boolean,
|
||||
val refreshToken: String?,
|
||||
val userId: String,
|
||||
val slidingSyncProxy: String?
|
||||
)
|
||||
|
||||
private val store = context.dataStore
|
||||
|
||||
override fun isLoggedIn(): Flow<Boolean> {
|
||||
return store.data.map { prefs ->
|
||||
prefs[sessionKey] != null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeData(session: Session) {
|
||||
store.edit { prefs ->
|
||||
val sessionData = SessionData(
|
||||
accessToken = session.accessToken,
|
||||
deviceId = session.deviceId,
|
||||
homeserverUrl = session.homeserverUrl,
|
||||
isSoftLogout = session.isSoftLogout,
|
||||
refreshToken = session.refreshToken,
|
||||
userId = session.userId,
|
||||
slidingSyncProxy = session.slidingSyncProxy
|
||||
)
|
||||
val encodedSession = Json.encodeToString(sessionData)
|
||||
prefs[sessionKey] = encodedSession
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getLatestSession(): Session? {
|
||||
return store.data.firstOrNull()?.let { prefs ->
|
||||
val encodedSession = prefs[sessionKey] ?: return@let null
|
||||
val sessionData = Json.decodeFromString<SessionData>(encodedSession)
|
||||
Session(
|
||||
accessToken = sessionData.accessToken,
|
||||
deviceId = sessionData.deviceId,
|
||||
homeserverUrl = sessionData.homeserverUrl,
|
||||
isSoftLogout = sessionData.isSoftLogout,
|
||||
refreshToken = sessionData.refreshToken,
|
||||
userId = sessionData.userId,
|
||||
slidingSyncProxy = sessionData.slidingSyncProxy
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSession(sessionId: SessionId): Session? {
|
||||
//TODO we should have a proper session management
|
||||
return getLatestSession()
|
||||
}
|
||||
|
||||
override suspend fun reset() {
|
||||
store.edit { it.clear() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
* 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.
|
||||
|
|
@ -25,6 +25,6 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.libraries.matrix)
|
||||
api(projects.libraries.matrix.api)
|
||||
api(libs.coroutines.core)
|
||||
}
|
||||
22
libraries/matrix/test/src/main/AndroidManifest.xml
Normal file
22
libraries/matrix/test/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
</manifest>
|
||||
|
|
@ -14,23 +14,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest
|
||||
package io.element.android.libraries.matrix.test
|
||||
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
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.FakeRoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaResolver
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeRoomSummaryDataSource
|
||||
import kotlinx.coroutines.delay
|
||||
import org.matrix.rustcomponents.sdk.MediaSource
|
||||
|
||||
class FakeMatrixClient(
|
||||
override val sessionId: SessionId = SessionId(A_SESSION_ID),
|
||||
override val 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()
|
||||
|
|
@ -63,8 +62,6 @@ class FakeMatrixClient(
|
|||
logoutFailure?.let { throw it }
|
||||
}
|
||||
|
||||
override fun userId(): UserId = A_USER_ID
|
||||
|
||||
override suspend fun loadUserDisplayName(): Result<String> {
|
||||
return userDisplayName
|
||||
}
|
||||
|
|
@ -14,16 +14,19 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest
|
||||
package io.element.android.libraries.matrix.test
|
||||
|
||||
import io.element.android.libraries.matrix.core.EventId
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
|
||||
const val A_USER_NAME = "alice"
|
||||
const val A_PASSWORD = "password"
|
||||
|
||||
val A_USER_ID = UserId("@alice:server.org")
|
||||
val A_SESSION_ID = SessionId(A_USER_ID.value)
|
||||
val A_ROOM_ID = RoomId("!aRoomId")
|
||||
val AN_EVENT_ID = EventId("\$anEventId")
|
||||
|
||||
|
|
@ -32,9 +35,10 @@ 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 A_HOMESERVER_URL = "matrix.org"
|
||||
const val A_HOMESERVER_URL_2 = "matrix-client.org"
|
||||
|
||||
val A_HOMESERVER = MatrixHomeServerDetails(A_HOMESERVER_URL, true, null)
|
||||
|
||||
const val AN_AVATAR_URL = "mxc://data"
|
||||
|
||||
|
|
@ -14,20 +14,24 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.auth
|
||||
package io.element.android.libraries.matrix.test.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 io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
class FakeAuthenticationService : MatrixAuthenticationService {
|
||||
private var homeserver: String = A_HOMESERVER
|
||||
private var homeserver = MutableStateFlow<MatrixHomeServerDetails?>(null)
|
||||
private var loginError: Throwable? = null
|
||||
private var changeServerError: Throwable? = null
|
||||
|
||||
override fun isLoggedIn(): Flow<Boolean> {
|
||||
return flowOf(false)
|
||||
|
|
@ -41,29 +45,30 @@ class FakeAuthenticationService : MatrixAuthenticationService {
|
|||
return null
|
||||
}
|
||||
|
||||
override fun getHomeserver(): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun givenHomeserver(homeserver: String) {
|
||||
this.homeserver = homeserver
|
||||
}
|
||||
|
||||
override fun getHomeserverOrDefault(): String {
|
||||
override fun getHomeserverDetails(): StateFlow<MatrixHomeServerDetails?> {
|
||||
return homeserver
|
||||
}
|
||||
|
||||
fun givenHomeserver(homeserver: MatrixHomeServerDetails) {
|
||||
this.homeserver.value = homeserver
|
||||
}
|
||||
|
||||
override suspend fun setHomeserver(homeserver: String) {
|
||||
changeServerError?.let { throw it }
|
||||
delay(100)
|
||||
}
|
||||
|
||||
override suspend fun login(username: String, password: String): SessionId {
|
||||
delay(100)
|
||||
loginError?.let { throw it }
|
||||
return SessionId(A_SESSION_ID)
|
||||
return A_USER_ID
|
||||
}
|
||||
|
||||
fun givenLoginError(throwable: Throwable?) {
|
||||
loginError = throwable
|
||||
}
|
||||
|
||||
fun givenChangeServerError(throwable: Throwable?) {
|
||||
changeServerError = throwable
|
||||
}
|
||||
}
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.media
|
||||
package io.element.android.libraries.matrix.test.media
|
||||
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
|
||||
class FakeMediaResolver : MediaResolver {
|
||||
override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? {
|
||||
|
|
@ -14,14 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.room
|
||||
package io.element.android.libraries.matrix.test.room
|
||||
|
||||
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 io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.room
|
||||
package io.element.android.libraries.matrix.test.room
|
||||
|
||||
import io.element.android.libraries.matrix.room.RoomSummary
|
||||
import io.element.android.libraries.matrix.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
|
|
@ -14,14 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.room
|
||||
package io.element.android.libraries.matrix.test.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
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDetails
|
||||
import io.element.android.libraries.matrix.test.A_MESSAGE
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
|
||||
fun aRoomSummaryFilled(
|
||||
roomId: RoomId = A_ROOM_ID,
|
||||
|
|
@ -14,11 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrixtest.timeline
|
||||
package io.element.android.libraries.matrix.test.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 io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -35,7 +35,7 @@ dependencies {
|
|||
anvil(projects.anvilcodegen)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.matrix)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(libs.coil.compose)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.matrix.ui
|
|||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -38,13 +38,13 @@ class MatrixItemHelper @Inject constructor(
|
|||
val userDisplayName = client.loadUserDisplayName().getOrNull()
|
||||
val avatarData =
|
||||
AvatarData(
|
||||
client.userId().value,
|
||||
client.sessionId.value,
|
||||
userDisplayName,
|
||||
userAvatarUrl,
|
||||
avatarSize
|
||||
)
|
||||
MatrixUser(
|
||||
id = client.userId(),
|
||||
id = client.sessionId,
|
||||
username = userDisplayName,
|
||||
avatarData = avatarData,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.matrix.ui.components
|
|||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
|
||||
import io.element.android.libraries.matrix.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
|
||||
open class MatrixUserProvider : PreviewParameterProvider<MatrixUser> {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
package io.element.android.libraries.matrix.ui.media
|
||||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
|
||||
|
||||
fun AvatarData.toMetadata(): MediaResolver.Meta {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import android.content.Context
|
|||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoggedInImageLoaderFactory @Inject constructor(
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import coil.fetch.FetchResult
|
|||
import coil.fetch.Fetcher
|
||||
import coil.request.Options
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
internal class MediaFetcher(
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package io.element.android.libraries.matrix.ui.media
|
|||
import coil.key.Keyer
|
||||
import coil.request.Options
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.media.MediaResolver
|
||||
import io.element.android.libraries.matrix.api.media.MediaResolver
|
||||
|
||||
internal class AvatarKeyer : Keyer<AvatarData> {
|
||||
override fun key(data: AvatarData, options: Options): String? {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue