Format project

This commit is contained in:
Benoit Marty 2022-12-09 10:25:11 +01:00
parent 8a3435ff63
commit d6058716c6
142 changed files with 840 additions and 518 deletions

View file

@ -6,7 +6,7 @@ indent_style = space
insert_final_newline = true insert_final_newline = true
max_line_length = 160 max_line_length = 160
tab_width = 4 tab_width = 4
ij_continuation_indent_size = 8 ij_continuation_indent_size = 4
ij_formatter_off_tag = @formatter:off ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false ij_formatter_tags_enabled = false
@ -105,7 +105,7 @@ ij_java_for_statement_wrap = off
ij_java_generate_final_locals = false ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false ij_java_generate_final_parameters = false
ij_java_if_brace_force = never ij_java_if_brace_force = never
ij_java_imports_layout = $android.**,$androidx.**,$com.**,$junit.**,$net.**,$org.**,$java.**,$javax.**,$*,|,android.**,|,androidx.**,|,com.**,|,junit.**,|,net.**,|,org.**,|,java.**,|,javax.**,|,*,| ij_java_imports_layout = $android.**, $androidx.**, $com.**, $junit.**, $net.**, $org.**, $java.**, $javax.**, $*, |, android.**, |, androidx.**, |, com.**, |, junit.**, |, net.**, |, org.**, |, java.**, |, javax.**, |, *, |
ij_java_indent_case_from_switch = true ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true ij_java_insert_override_annotation = true
@ -640,7 +640,7 @@ ij_groovy_for_statement_right_paren_on_new_line = false
ij_groovy_for_statement_wrap = off ij_groovy_for_statement_wrap = off
ij_groovy_if_brace_force = never ij_groovy_if_brace_force = never
ij_groovy_import_annotation_wrap = 2 ij_groovy_import_annotation_wrap = 2
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$* ij_groovy_imports_layout = *, |, javax.**, java.**, |, $*
ij_groovy_indent_case_from_switch = true ij_groovy_indent_case_from_switch = true
ij_groovy_indent_label_blocks = true ij_groovy_indent_label_blocks = true
ij_groovy_insert_inner_class_imports = false ij_groovy_insert_inner_class_imports = false
@ -797,7 +797,7 @@ ij_kotlin_field_annotation_wrap = normal
ij_kotlin_finally_on_new_line = false ij_kotlin_finally_on_new_line = false
ij_kotlin_if_rparen_on_new_line = false ij_kotlin_if_rparen_on_new_line = false
ij_kotlin_import_nested_classes = false ij_kotlin_import_nested_classes = false
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
ij_kotlin_keep_blank_lines_before_right_brace = 0 ij_kotlin_keep_blank_lines_before_right_brace = 0
ij_kotlin_keep_blank_lines_in_code = 1 ij_kotlin_keep_blank_lines_in_code = 1
@ -860,22 +860,22 @@ ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false ij_json_wrap_long_lines = false
[{*.htm,*.html,*.sht,*.shtm,*.shtml}] [{*.htm,*.html,*.sht,*.shtm,*.shtml}]
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true ij_html_align_attributes = true
ij_html_align_text = false ij_html_align_text = false
ij_html_attribute_wrap = normal ij_html_attribute_wrap = normal
ij_html_block_comment_at_first_column = true ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0 ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
ij_html_enforce_quotes = false ij_html_enforce_quotes = false
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
ij_html_keep_blank_lines = 2 ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span,pre,textarea ij_html_keep_whitespaces_inside = span, pre, textarea
ij_html_line_comment_at_first_column = true ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never ij_html_new_line_before_first_attribute = never

View file

@ -2,7 +2,7 @@ name: Move labelled issues to correct boards and columns
on: on:
issues: issues:
types: [labeled] types: [ labeled ]
jobs: jobs:
move_element_x_issues: move_element_x_issues:

125
.idea/codeStyles/Project.xml generated Normal file
View file

@ -0,0 +1,125 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View file

@ -1,4 +1,5 @@
# element-x-android-poc # element-x-android-poc
Proof Of Concept to run a Matrix client on Android devices using the Matrix Rust Sdk and Jetpack compose. Proof Of Concept to run a Matrix client on Android devices using the Matrix Rust Sdk and Jetpack compose.
The plan is [here](https://github.com/vector-im/element-x-android-poc/issues/1)! The plan is [here](https://github.com/vector-im/element-x-android-poc/issues/1)!

View file

@ -29,12 +29,12 @@ android {
} }
register("nightly") { register("nightly") {
keyAlias = System.getenv("ELEMENT_ANDROID_NIGHTLY_KEYID") keyAlias = System.getenv("ELEMENT_ANDROID_NIGHTLY_KEYID")
?: project.property("signing.element.nightly.keyId") as? String? ?: project.property("signing.element.nightly.keyId") as? String?
keyPassword = System.getenv("ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD") keyPassword = System.getenv("ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD")
?: project.property("signing.element.nightly.keyPassword") as? String? ?: project.property("signing.element.nightly.keyPassword") as? String?
storeFile = file("./signature/nightly.keystore") storeFile = file("./signature/nightly.keystore")
storePassword = System.getenv("ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD") storePassword = System.getenv("ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD")
?: project.property("signing.element.nightly.storePassword") as? String? ?: project.property("signing.element.nightly.storePassword") as? String?
} }
} }
@ -80,7 +80,6 @@ android {
appId = "1:912726360885:android:e17435e0beb0303000427c" appId = "1:912726360885:android:e17435e0beb0303000427c"
} }
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
@ -135,29 +134,29 @@ android {
exclude { element -> element.file.path.contains("$buildDir/generated/") } exclude { element -> element.file.path.contains("$buildDir/generated/") }
} }
disabledRules.set( disabledRules.set(
setOf( setOf(
// TODO Re-enable these 4 rules after reformatting project // TODO Re-enable these 4 rules after reformatting project
"indent", "indent",
"experimental:argument-list-wrapping", "experimental:argument-list-wrapping",
"max-line-length", "max-line-length",
"parameter-list-wrapping", "parameter-list-wrapping",
"spacing-between-declarations-with-comments", "spacing-between-declarations-with-comments",
"no-multi-spaces", "no-multi-spaces",
"experimental:spacing-between-declarations-with-annotations", "experimental:spacing-between-declarations-with-annotations",
"experimental:annotation", "experimental:annotation",
// - Missing newline after "(" // - Missing newline after "("
// - Missing newline before ")" // - Missing newline before ")"
"wrapping", "wrapping",
// - Unnecessary trailing comma before ")" // - Unnecessary trailing comma before ")"
"experimental:trailing-comma", "experimental:trailing-comma",
// - A block comment in between other elements on the same line is disallowed // - A block comment in between other elements on the same line is disallowed
"experimental:comment-wrapping", "experimental:comment-wrapping",
// - A KDoc comment after any other element on the same line must be separated by a new line // - A KDoc comment after any other element on the same line must be separated by a new line
"experimental:kdoc-wrapping", "experimental:kdoc-wrapping",
// Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt" // Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt"
"string-template", "string-template",
) )
) )
} }
} }

View file

@ -19,8 +19,15 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.* import androidx.compose.material3.Button
import androidx.compose.runtime.* import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -106,7 +113,6 @@ class MainActivity : ComponentActivity() {
OnLifecycleEvent { _, event -> OnLifecycleEvent { _, event ->
Timber.v("OnLifecycleEvent: $event") Timber.v("OnLifecycleEvent: $event")
} }
} }
@Composable @Composable
@ -165,5 +171,4 @@ class MainActivity : ComponentActivity() {
fun MainContentPreview() { fun MainContentPreview() {
MainContent(startRoute = OnBoardingScreenNavigationDestination) MainContent(startRoute = OnBoardingScreenNavigationDestination)
} }
} }

View file

@ -13,14 +13,14 @@ class MainViewModel : ViewModel() {
return matrix.isLoggedIn().first() return matrix.isLoggedIn().first()
} }
fun startSyncIfLogged(){ fun startSyncIfLogged() {
viewModelScope.launch { viewModelScope.launch {
if(!isLoggedIn()) return@launch if (!isLoggedIn()) return@launch
matrix.activeClient().startSync() matrix.activeClient().startSync()
} }
} }
fun stopSyncIfLogged(){ fun stopSyncIfLogged() {
viewModelScope.launch { viewModelScope.launch {
if (!isLoggedIn()) return@launch if (!isLoggedIn()) return@launch
matrix.activeClient().stopSync() matrix.activeClient().stopSync()

View file

@ -77,6 +77,3 @@ fun RoomListScreenNavigation(navigator: DestinationsNavigator) {
fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) { fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) {
MessagesScreen(roomId, navigator::navigateUp) MessagesScreen(roomId, navigator::navigateUp)
} }

View file

@ -3,25 +3,26 @@
android:height="108dp" android:height="108dp"
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<group android:scaleX="0.675" <group
android:scaleY="0.675" android:scaleX="0.675"
android:translateX="32.4" android:scaleY="0.675"
android:translateY="32.4"> android:translateX="32.4"
<path android:translateY="32.4">
android:pathData="M23.04,3.84C23.04,1.7192 24.7593,0 26.88,0C41.0185,0 52.48,11.4615 52.48,25.6C52.48,27.7208 50.7608,29.44 48.64,29.44C46.5193,29.44 44.8,27.7208 44.8,25.6C44.8,15.7031 36.777,7.68 26.88,7.68C24.7593,7.68 23.04,5.9608 23.04,3.84Z" <path
android:fillColor="#FFF" android:pathData="M23.04,3.84C23.04,1.7192 24.7593,0 26.88,0C41.0185,0 52.48,11.4615 52.48,25.6C52.48,27.7208 50.7608,29.44 48.64,29.44C46.5193,29.44 44.8,27.7208 44.8,25.6C44.8,15.7031 36.777,7.68 26.88,7.68C24.7593,7.68 23.04,5.9608 23.04,3.84Z"
android:fillType="evenOdd"/> android:fillColor="#FFF"
<path android:fillType="evenOdd" />
android:pathData="M40.96,60.16C40.96,62.2808 39.2407,64 37.12,64C22.9815,64 11.52,52.5385 11.52,38.4C11.52,36.2792 13.2392,34.56 15.36,34.56C17.4807,34.56 19.2,36.2792 19.2,38.4C19.2,48.2969 27.223,56.32 37.12,56.32C39.2407,56.32 40.96,58.0392 40.96,60.16Z" <path
android:fillColor="#FFF" android:pathData="M40.96,60.16C40.96,62.2808 39.2407,64 37.12,64C22.9815,64 11.52,52.5385 11.52,38.4C11.52,36.2792 13.2392,34.56 15.36,34.56C17.4807,34.56 19.2,36.2792 19.2,38.4C19.2,48.2969 27.223,56.32 37.12,56.32C39.2407,56.32 40.96,58.0392 40.96,60.16Z"
android:fillType="evenOdd"/> android:fillColor="#FFF"
<path android:fillType="evenOdd" />
android:pathData="M3.84,40.96C1.7192,40.96 -0,39.2407 -0,37.12C-0,22.9815 11.4615,11.52 25.6,11.52C27.7208,11.52 29.44,13.2392 29.44,15.36C29.44,17.4807 27.7208,19.2 25.6,19.2C15.7031,19.2 7.68,27.223 7.68,37.12C7.68,39.2407 5.9608,40.96 3.84,40.96Z" <path
android:fillColor="#FFF" android:pathData="M3.84,40.96C1.7192,40.96 -0,39.2407 -0,37.12C-0,22.9815 11.4615,11.52 25.6,11.52C27.7208,11.52 29.44,13.2392 29.44,15.36C29.44,17.4807 27.7208,19.2 25.6,19.2C15.7031,19.2 7.68,27.223 7.68,37.12C7.68,39.2407 5.9608,40.96 3.84,40.96Z"
android:fillType="evenOdd"/> android:fillColor="#FFF"
<path android:fillType="evenOdd" />
android:pathData="M60.16,23.04C62.2808,23.04 64,24.7593 64,26.88C64,41.0185 52.5385,52.48 38.4,52.48C36.2792,52.48 34.56,50.7608 34.56,48.64C34.56,46.5193 36.2792,44.8 38.4,44.8C48.2969,44.8 56.32,36.777 56.32,26.88C56.32,24.7593 58.0392,23.04 60.16,23.04Z" <path
android:fillColor="#FFF" android:pathData="M60.16,23.04C62.2808,23.04 64,24.7593 64,26.88C64,41.0185 52.5385,52.48 38.4,52.48C36.2792,52.48 34.56,50.7608 34.56,48.64C34.56,46.5193 36.2792,44.8 38.4,44.8C48.2969,44.8 56.32,36.777 56.32,26.88C56.32,24.7593 58.0392,23.04 60.16,23.04Z"
android:fillType="evenOdd"/> android:fillColor="#FFF"
</group> android:fillType="evenOdd" />
</group>
</vector> </vector>

View file

@ -1,8 +1,5 @@
### VersionCatalog ### VersionCatalog
### Jetpack Compose ### Jetpack Compose
https://developer.android.com/jetpack/compose/mental-model https://developer.android.com/jetpack/compose/mental-model

View file

@ -1,13 +1,11 @@
package io.element.android.x.features.login package io.element.android.x.features.login
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View file

@ -2,7 +2,13 @@
package io.element.android.x.features.login package io.element.android.x.features.login
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@ -10,8 +16,21 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.* import androidx.compose.material3.Button
import androidx.compose.runtime.* import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@ -55,7 +74,6 @@ fun LoginScreen(
) )
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun LoginContent( fun LoginContent(

View file

@ -22,5 +22,4 @@ data class LoginFormState(
companion object { companion object {
val Default = LoginFormState("", "") val Default = LoginFormState("", "")
} }
} }

View file

@ -3,13 +3,27 @@
package io.element.android.x.features.login.changeserver package io.element.android.x.features.login.changeserver
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.* import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -45,7 +59,6 @@ fun ChangeServerScreen(
) )
} }
@Composable @Composable
fun ChangeServerContent( fun ChangeServerContent(
state: ChangeServerViewState, state: ChangeServerViewState,
@ -101,7 +114,7 @@ fun ChangeServerContent(
) )
Text( Text(
text = "A server is a home for all your data.\n" + text = "A server is a home for all your data.\n" +
"You choose your server and its easy to make one.", // TODO "Learn more.", "You choose your server and its easy to make one.", // TODO "Learn more.",
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.align(Alignment.CenterHorizontally) .align(Alignment.CenterHorizontally)

View file

@ -6,17 +6,17 @@
<path <path
android:pathData="M23.04,3.84C23.04,1.7192 24.7593,0 26.88,0C41.0185,0 52.48,11.4615 52.48,25.6C52.48,27.7208 50.7608,29.44 48.64,29.44C46.5193,29.44 44.8,27.7208 44.8,25.6C44.8,15.7031 36.777,7.68 26.88,7.68C24.7593,7.68 23.04,5.9608 23.04,3.84Z" android:pathData="M23.04,3.84C23.04,1.7192 24.7593,0 26.88,0C41.0185,0 52.48,11.4615 52.48,25.6C52.48,27.7208 50.7608,29.44 48.64,29.44C46.5193,29.44 44.8,27.7208 44.8,25.6C44.8,15.7031 36.777,7.68 26.88,7.68C24.7593,7.68 23.04,5.9608 23.04,3.84Z"
android:fillColor="#0DBD8B" android:fillColor="#0DBD8B"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
<path <path
android:pathData="M40.96,60.16C40.96,62.2808 39.2407,64 37.12,64C22.9815,64 11.52,52.5385 11.52,38.4C11.52,36.2792 13.2392,34.56 15.36,34.56C17.4807,34.56 19.2,36.2792 19.2,38.4C19.2,48.2969 27.223,56.32 37.12,56.32C39.2407,56.32 40.96,58.0392 40.96,60.16Z" android:pathData="M40.96,60.16C40.96,62.2808 39.2407,64 37.12,64C22.9815,64 11.52,52.5385 11.52,38.4C11.52,36.2792 13.2392,34.56 15.36,34.56C17.4807,34.56 19.2,36.2792 19.2,38.4C19.2,48.2969 27.223,56.32 37.12,56.32C39.2407,56.32 40.96,58.0392 40.96,60.16Z"
android:fillColor="#0DBD8B" android:fillColor="#0DBD8B"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
<path <path
android:pathData="M3.84,40.96C1.7192,40.96 -0,39.2407 -0,37.12C-0,22.9815 11.4615,11.52 25.6,11.52C27.7208,11.52 29.44,13.2392 29.44,15.36C29.44,17.4807 27.7208,19.2 25.6,19.2C15.7031,19.2 7.68,27.223 7.68,37.12C7.68,39.2407 5.9608,40.96 3.84,40.96Z" android:pathData="M3.84,40.96C1.7192,40.96 -0,39.2407 -0,37.12C-0,22.9815 11.4615,11.52 25.6,11.52C27.7208,11.52 29.44,13.2392 29.44,15.36C29.44,17.4807 27.7208,19.2 25.6,19.2C15.7031,19.2 7.68,27.223 7.68,37.12C7.68,39.2407 5.9608,40.96 3.84,40.96Z"
android:fillColor="#0DBD8B" android:fillColor="#0DBD8B"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
<path <path
android:pathData="M60.16,23.04C62.2808,23.04 64,24.7593 64,26.88C64,41.0185 52.5385,52.48 38.4,52.48C36.2792,52.48 34.56,50.7608 34.56,48.64C34.56,46.5193 36.2792,44.8 38.4,44.8C48.2969,44.8 56.32,36.777 56.32,26.88C56.32,24.7593 58.0392,23.04 60.16,23.04Z" android:pathData="M60.16,23.04C62.2808,23.04 64,24.7593 64,26.88C64,41.0185 52.5385,52.48 38.4,52.48C36.2792,52.48 34.56,50.7608 34.56,48.64C34.56,46.5193 36.2792,44.8 38.4,44.8C48.2969,44.8 56.32,36.777 56.32,26.88C56.32,24.7593 58.0392,23.04 60.16,23.04Z"
android:fillColor="#0DBD8B" android:fillColor="#0DBD8B"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
</vector> </vector>

View file

@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000" <vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24" android:tint="#000000"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24"
<path android:fillColor="@android:color/white" android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM11,17H7v-4h4V17zM11,11H7V7h4V11zM17,17h-4v-4h4V17zM17,11h-4V7h4V11z"/> android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM11,17H7v-4h4V17zM11,11H7V7h4V11zM17,17h-4v-4h4V17zM17,11h-4V7h4V11z" />
</vector> </vector>

View file

@ -1,9 +1,8 @@
package io.element.android.x.features.login package io.element.android.x.features.login
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.Assert.*
/** /**
* Example local unit test, which will execute on the development machine (host). * Example local unit test, which will execute on the development machine (host).
* *

View file

@ -1,13 +1,11 @@
package io.element.android.x.features.messages package io.element.android.x.features.messages
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View file

@ -9,7 +9,14 @@ import io.element.android.x.features.messages.model.AggregatedReaction
import io.element.android.x.features.messages.model.MessagesItemGroupPosition import io.element.android.x.features.messages.model.MessagesItemGroupPosition
import io.element.android.x.features.messages.model.MessagesItemReactionState import io.element.android.x.features.messages.model.MessagesItemReactionState
import io.element.android.x.features.messages.model.MessagesTimelineItemState import io.element.android.x.features.messages.model.MessagesTimelineItemState
import io.element.android.x.features.messages.model.content.* import io.element.android.x.features.messages.model.content.MessagesTimelineItemContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemEmoteContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemEncryptedContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemNoticeContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemUnknownContent
import io.element.android.x.features.messages.util.invalidateLast import io.element.android.x.features.messages.util.invalidateLast
import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.media.MediaResolver import io.element.android.x.matrix.media.MediaResolver
@ -83,7 +90,6 @@ class MessageTimelineItemStateFactory(
timelineItemStates.emit(newTimelineItemStates) timelineItemStates.emit(newTimelineItemStates)
} }
private fun calculateAndApplyDiff(newTimelineItems: List<MatrixTimelineItem>) { private fun calculateAndApplyDiff(newTimelineItems: List<MatrixTimelineItem>) {
val timeToDiff = measureTimeMillis { val timeToDiff = measureTimeMillis {
val diffCallback = val diffCallback =
@ -232,5 +238,4 @@ class MessageTimelineItemStateFactory(
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value)) .resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
return AvatarData(name, model, size) return AvatarData(name, model, size)
} }
} }

View file

@ -8,7 +8,25 @@ package io.element.android.x.features.messages
import Avatar import Avatar
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@ -20,8 +38,24 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowDownward
import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.* import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.* import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.End import androidx.compose.ui.Alignment.Companion.End
import androidx.compose.ui.Alignment.Companion.Start import androidx.compose.ui.Alignment.Companion.Start
@ -42,9 +76,27 @@ import io.element.android.x.core.compose.LogCompositions
import io.element.android.x.core.compose.PairCombinedPreviewParameter import io.element.android.x.core.compose.PairCombinedPreviewParameter
import io.element.android.x.core.data.StableCharSequence import io.element.android.x.core.data.StableCharSequence
import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.features.messages.components.* import io.element.android.x.features.messages.components.MessageEventBubble
import io.element.android.x.features.messages.model.* import io.element.android.x.features.messages.components.MessagesReactionsView
import io.element.android.x.features.messages.model.content.* import io.element.android.x.features.messages.components.MessagesTimelineItemEncryptedView
import io.element.android.x.features.messages.components.MessagesTimelineItemImageView
import io.element.android.x.features.messages.components.MessagesTimelineItemRedactedView
import io.element.android.x.features.messages.components.MessagesTimelineItemTextView
import io.element.android.x.features.messages.components.MessagesTimelineItemUnknownView
import io.element.android.x.features.messages.components.TimelineItemActionsScreen
import io.element.android.x.features.messages.model.AggregatedReaction
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
import io.element.android.x.features.messages.model.MessagesItemGroupPositionProvider
import io.element.android.x.features.messages.model.MessagesItemReactionState
import io.element.android.x.features.messages.model.MessagesTimelineItemState
import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.features.messages.model.content.MessagesTimelineItemContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemContentProvider
import io.element.android.x.features.messages.model.content.MessagesTimelineItemEncryptedContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemUnknownContent
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
import io.element.android.x.features.messages.textcomposer.MessageComposerViewState import io.element.android.x.features.messages.textcomposer.MessageComposerViewState
import io.element.android.x.textcomposer.MessageComposerMode import io.element.android.x.textcomposer.MessageComposerMode
@ -322,7 +374,6 @@ fun TimelineItems(
onLoadMore = onReachedLoadMore onLoadMore = onReachedLoadMore
) )
} }
} }
private fun MessagesTimelineItemState.key(): String { private fun MessagesTimelineItemState.key(): String {
@ -339,7 +390,6 @@ private fun MessagesTimelineItemState.contentType(): Int {
} }
} }
@Composable @Composable
fun TimelineItemRow( fun TimelineItemRow(
timelineItem: MessagesTimelineItemState, timelineItem: MessagesTimelineItemState,
@ -526,7 +576,6 @@ internal fun BoxScope.MessagesScrollHelper(
Icon(Icons.Default.ArrowDownward, "") Icon(Icons.Default.ArrowDownward, "")
} }
} }
} }
@Composable @Composable
@ -543,7 +592,6 @@ internal fun MessagesLoadingMoreIndicator() {
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
} }
} }
class MessagesItemGroupPositionToMessagesTimelineItemContentProvider : class MessagesItemGroupPositionToMessagesTimelineItemContentProvider :

View file

@ -13,7 +13,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.x.designsystem.* import io.element.android.x.designsystem.LocalIsDarkTheme
import io.element.android.x.designsystem.MessageHighlightDark
import io.element.android.x.designsystem.MessageHighlightLight
import io.element.android.x.designsystem.SystemGrey5Dark
import io.element.android.x.designsystem.SystemGrey5Light
import io.element.android.x.designsystem.SystemGrey6Dark
import io.element.android.x.designsystem.SystemGrey6Light
import io.element.android.x.features.messages.model.MessagesItemGroupPosition import io.element.android.x.features.messages.model.MessagesItemGroupPosition
private val BUBBLE_RADIUS = 16.dp private val BUBBLE_RADIUS = 16.dp

View file

@ -24,7 +24,7 @@ fun MessagesReactionsView(
reactionsState: MessagesItemReactionState, reactionsState: MessagesItemReactionState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
if(reactionsState.reactions.isEmpty()) return if (reactionsState.reactions.isEmpty()) return
FlowRow( FlowRow(
modifier = modifier, modifier = modifier,
mainAxisSpacing = 2.dp, mainAxisSpacing = 2.dp,

View file

@ -3,14 +3,28 @@
package io.element.android.x.features.messages.components package io.element.android.x.features.messages.components
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.* import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.* import androidx.compose.material.ListItem
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ModalBottomSheetLayout
import androidx.compose.material.ModalBottomSheetState
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.collectAsState
import io.element.android.x.designsystem.components.VectorIcon import io.element.android.x.designsystem.components.VectorIcon
@ -21,7 +35,6 @@ import io.element.android.x.features.messages.model.MessagesTimelineItemState
import io.element.android.x.features.messages.model.MessagesViewState import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -71,11 +84,12 @@ fun TimelineItemActionsScreen(
SheetContent( SheetContent(
actionsSheetState = itemActionsSheetState(), actionsSheetState = itemActionsSheetState(),
onActionClicked = ::onItemActionClicked, onActionClicked = ::onItemActionClicked,
modifier = Modifier.navigationBarsPadding().imePadding() modifier = Modifier
.navigationBarsPadding()
.imePadding()
) )
} }
) {} ) {}
} }
@Composable @Composable

View file

@ -6,7 +6,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -16,7 +15,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import coil.request.ImageRequest import coil.request.ImageRequest
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
@ -26,9 +24,9 @@ fun MessagesTimelineItemImageView(
content: MessagesTimelineItemImageContent, content: MessagesTimelineItemImageContent,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val widthPercent = if(content.aspectRatio > 1f){ val widthPercent = if (content.aspectRatio > 1f) {
1f 1f
}else { } else {
0.7f 0.7f
} }
Box( Box(

View file

@ -9,17 +9,25 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material3.* import androidx.compose.material3.ColorScheme
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.* import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.google.accompanist.flowlayout.FlowRow import com.google.accompanist.flowlayout.FlowRow
@ -268,7 +276,6 @@ private fun HtmlBlockquote(
} }
} }
@Composable @Composable
private fun HtmlHeading( private fun HtmlHeading(
heading: Element, heading: Element,
@ -402,7 +409,6 @@ private fun HtmlUnorderedList(
} }
} }
@Composable @Composable
private fun HtmlListItems( private fun HtmlListItems(
list: Element, list: Element,
@ -426,7 +432,6 @@ private fun HtmlListItems(
) )
} }
} }
} }
} }
} }
@ -452,7 +457,6 @@ private fun AnnotatedString.Builder.appendInlineChildrenElements(
} }
} }
private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors: ColorScheme) { private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors: ColorScheme) {
when (element.normalName()) { when (element.normalName()) {
"br" -> { "br" -> {
@ -490,7 +494,6 @@ private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors
appendInlineChildrenElements(element.childNodes(), colors) appendInlineChildrenElements(element.childNodes(), colors)
} }
} }
} }
private fun AnnotatedString.Builder.appendLink(link: Element) { private fun AnnotatedString.Builder.appendLink(link: Element) {

View file

@ -37,5 +37,4 @@ internal class CacheInvalidator(private val itemStatesCache: MutableList<Message
itemStatesCache.removeAt(position) itemStatesCache.removeAt(position)
} }
} }
} }

View file

@ -31,5 +31,4 @@ internal class MatrixTimelineItemsDiffCallback(
val newItem = newList.getOrNull(newItemPosition) val newItem = newList.getOrNull(newItemPosition)
return oldItem == newItem return oldItem == newItem
} }
} }

View file

@ -12,7 +12,6 @@ sealed interface MessagesItemGroupPosition {
First, None -> true First, None -> true
else -> false else -> false
} }
} }
internal class MessagesItemGroupPositionProvider : PreviewParameterProvider<MessagesItemGroupPosition> { internal class MessagesItemGroupPositionProvider : PreviewParameterProvider<MessagesItemGroupPosition> {

View file

@ -6,6 +6,7 @@ import androidx.compose.runtime.Stable
data class MessagesItemReactionState( data class MessagesItemReactionState(
val reactions: List<AggregatedReaction> val reactions: List<AggregatedReaction>
) )
@Stable @Stable
data class AggregatedReaction( data class AggregatedReaction(
val key: String, val key: String,

View file

@ -23,10 +23,7 @@ sealed interface MessagesTimelineItemState {
val showSenderInformation = groupPosition.isNew() && !isMine val showSenderInformation = groupPosition.isNew() && !isMine
val safeSenderName: String = senderDisplayName ?: senderId val safeSenderName: String = senderDisplayName ?: senderId
} }
} }

View file

@ -2,8 +2,6 @@ package io.element.android.x.features.messages.model.content
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import org.matrix.rustcomponents.sdk.EncryptedMessage import org.matrix.rustcomponents.sdk.EncryptedMessage
import org.matrix.rustcomponents.sdk.FormattedBody
import org.matrix.rustcomponents.sdk.MessageFormat
sealed interface MessagesTimelineItemContent sealed interface MessagesTimelineItemContent

View file

@ -7,7 +7,6 @@ import io.element.android.x.core.data.StableCharSequence
import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.MatrixInstance import io.element.android.x.matrix.MatrixInstance
class MessageComposerViewModel( class MessageComposerViewModel(
private val client: MatrixClient, private val client: MatrixClient,
private val initialState: MessageComposerViewState private val initialState: MessageComposerViewState

View file

@ -1,9 +1,8 @@
package io.element.android.x.features.messages package io.element.android.x.features.messages
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.Assert.*
/** /**
* Example local unit test, which will execute on the development machine (host). * Example local unit test, which will execute on the development machine (host).
* *

View file

@ -1,13 +1,11 @@
package io.element.android.x.features.login package io.element.android.x.features.login
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View file

@ -3,12 +3,24 @@
package io.element.android.x.features.onboarding package io.element.android.x.features.onboarding
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment.Companion.CenterHorizontally import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -42,7 +54,6 @@ fun OnBoardingScreen(
) )
} }
@OptIn(ExperimentalPagerApi::class) @OptIn(ExperimentalPagerApi::class)
@Composable @Composable
fun OnBoardingContent( fun OnBoardingContent(

View file

@ -20,12 +20,12 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
data class SplashCarouselState( data class SplashCarouselState(
val items: List<Item> val items: List<Item>
) { ) {
data class Item( data class Item(
@StringRes val title: Int, @StringRes val title: Int,
@StringRes val body: Int, @StringRes val body: Int,
@DrawableRes val image: Int, @DrawableRes val image: Int,
@DrawableRes val pageBackground: Int @DrawableRes val pageBackground: Int
) )
} }

View file

@ -1,9 +1,8 @@
package io.element.android.x.features.login package io.element.android.x.features.login
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.Assert.*
/** /**
* Example local unit test, which will execute on the development machine (host). * Example local unit test, which will execute on the development machine (host).
* *

View file

@ -1,13 +1,11 @@
package io.element.android.x.features.roomlist package io.element.android.x.features.roomlist
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View file

@ -2,11 +2,17 @@ package io.element.android.x.features.roomlist
import android.text.format.DateFormat import android.text.format.DateFormat
import android.text.format.DateUtils import android.text.format.DateUtils
import kotlinx.datetime.* import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.datetime.toJavaLocalDate
import kotlinx.datetime.toJavaLocalDateTime
import kotlinx.datetime.toLocalDateTime
import java.time.Period import java.time.Period
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.* import java.util.Locale
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
class LastMessageFormatter( class LastMessageFormatter(
@ -29,7 +35,6 @@ class LastMessageFormatter(
DateTimeFormatter.ofPattern(pattern) DateTimeFormatter.ofPattern(pattern)
} }
fun format(timestamp: Long?): String { fun format(timestamp: Long?): String {
if (timestamp == null) return "" if (timestamp == null) return ""
val now: Instant = clock.now() val now: Instant = clock.now()
@ -77,6 +82,4 @@ class LastMessageFormatter(
DateUtils.FORMAT_SHOW_WEEKDAY DateUtils.FORMAT_SHOW_WEEKDAY
).toString() ).toString()
} }
} }

View file

@ -1,6 +1,10 @@
package io.element.android.x.features.roomlist package io.element.android.x.features.roomlist
import com.airbnb.mvrx.* import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import io.element.android.x.core.data.parallelMap import io.element.android.x.core.data.parallelMap
import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.designsystem.components.avatar.AvatarSize import io.element.android.x.designsystem.components.avatar.AvatarSize
@ -118,8 +122,8 @@ class RoomListViewModel(
copy( copy(
rooms = when { rooms = when {
it is Loading || it is Loading ||
// Note: this second case will prevent to handle correctly the empty case // Note: this second case will prevent to handle correctly the empty case
(it is Success && it().isEmpty() && filter.isEmpty()) -> { (it is Success && it().isEmpty() && filter.isEmpty()) -> {
// Show fake placeholders to avoid having empty screen // Show fake placeholders to avoid having empty screen
Loading(RoomListRoomSummaryPlaceholders.createFakeList(size = 16)) Loading(RoomListRoomSummaryPlaceholders.createFakeList(size = 16))
} }
@ -164,5 +168,4 @@ class RoomListViewModel(
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value)) .resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
return AvatarData(name, model, size) return AvatarData(name, model, size)
} }
} }

View file

@ -11,9 +11,23 @@ import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Logout import androidx.compose.material.icons.filled.Logout
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.* import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.* import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
@ -65,7 +79,6 @@ fun RoomListTopBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
) )
} }
} }
@Composable @Composable
@ -83,8 +96,8 @@ fun SearchRoomListTopBar(
title = { title = {
TextField( TextField(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.focusRequester(focusRequester), .focusRequester(focusRequester),
value = filterState, value = filterState,
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 17.sp fontSize = 17.sp

View file

@ -4,13 +4,21 @@ import Avatar
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Alignment.Companion.CenterVertically
@ -57,7 +65,6 @@ internal fun RoomSummaryRow(
) { ) {
DefaultRoomSummaryRow(room = room) DefaultRoomSummaryRow(room = room)
} }
} }
@Composable @Composable

View file

@ -13,4 +13,5 @@ data class RoomListRoomSummary(
val timestamp: String? = null, val timestamp: String? = null,
val lastMessage: CharSequence? = null, val lastMessage: CharSequence? = null,
val avatarData: AvatarData = AvatarData(), val avatarData: AvatarData = AvatarData(),
val isPlaceholder: Boolean = false,) val isPlaceholder: Boolean = false,
)

View file

@ -2,7 +2,6 @@ package io.element.android.x.features.roomlist.model
import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarData
object RoomListRoomSummaryPlaceholders { object RoomListRoomSummaryPlaceholders {
fun create(id: String): RoomListRoomSummary { fun create(id: String): RoomListRoomSummary {
@ -23,6 +22,5 @@ object RoomListRoomSummaryPlaceholders {
} }
} }
} }
} }

View file

@ -1,9 +1,8 @@
package io.element.android.x.features.roomlist package io.element.android.x.features.roomlist
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.Assert.*
/** /**
* Example local unit test, which will execute on the development machine (host). * Example local unit test, which will execute on the development machine (host).
* *

View file

@ -21,7 +21,6 @@ kotlin.code.style=official
# resources declared in the library itself and none from the library's dependencies, # resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true
# Dummy values for signing secrets / nightly # Dummy values for signing secrets / nightly
signing.element.nightly.storePassword=Secret signing.element.nightly.storePassword=Secret
signing.element.nightly.keyId=Secret signing.element.nightly.keyId=Secret

View file

@ -6,7 +6,6 @@ import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import io.element.android.x.core.BuildConfig import io.element.android.x.core.BuildConfig
// Note the inline function below which ensures that this function is essentially // Note the inline function below which ensures that this function is essentially
// copied at the call site to ensure that its logging only recompositions from the // copied at the call site to ensure that its logging only recompositions from the
// original call site. // original call site.

View file

@ -5,7 +5,6 @@ import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@Composable @Composable
public fun textFieldState(stateValue: String): MutableState<String> = public fun textFieldState(stateValue: String): MutableState<String> =
remember(stateValue) { mutableStateOf(stateValue) } remember(stateValue) { mutableStateOf(stateValue) }

View file

@ -24,18 +24,18 @@ class DimensionConverter(val resources: Resources) {
@Px @Px
fun dpToPx(dp: Int): Int { fun dpToPx(dp: Int): Int {
return TypedValue.applyDimension( return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, TypedValue.COMPLEX_UNIT_DIP,
dp.toFloat(), dp.toFloat(),
resources.displayMetrics resources.displayMetrics
).toInt() ).toInt()
} }
@Px @Px
fun spToPx(sp: Int): Int { fun spToPx(sp: Int): Int {
return TypedValue.applyDimension( return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, TypedValue.COMPLEX_UNIT_SP,
sp.toFloat(), sp.toFloat(),
resources.displayMetrics resources.displayMetrics
).toInt() ).toInt()
} }

View file

@ -35,9 +35,9 @@ fun View.showKeyboard(andRequestFocus: Boolean = false) {
fun View.setHorizontalPadding(padding: Int) { fun View.setHorizontalPadding(padding: Int) {
setPadding( setPadding(
padding, padding,
paddingTop, paddingTop,
padding, padding,
paddingBottom paddingBottom
) )
} }

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View file

@ -5,6 +5,7 @@ import com.airbnb.android.showkase.annotation.ShowkaseColor
@ShowkaseColor(name = "LightGrey", group = "Material Design") @ShowkaseColor(name = "LightGrey", group = "Material Design")
val LightGrey = Color(0x993C3C43) val LightGrey = Color(0x993C3C43)
@ShowkaseColor(name = "DarkGrey", group = "Material Design") @ShowkaseColor(name = "DarkGrey", group = "Material Design")
val DarkGrey = Color(0x99EBEBF5) val DarkGrey = Color(0x99EBEBF5)
@ -37,6 +38,7 @@ val Vermilion = Color(0xFFFF5B55)
// TODO Update color // TODO Update color
val MessageHighlightLight = Azure val MessageHighlightLight = Azure
// TODO Update color // TODO Update color
val MessageHighlightDark = Azure val MessageHighlightDark = Azure

View file

@ -2,7 +2,11 @@ package io.element.android.x.designsystem
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.* import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
@ -81,7 +85,6 @@ fun ElementXTheme(
content = content content = content
) )
} }
} }

View file

@ -9,7 +9,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.airbnb.android.showkase.annotation.ShowkaseTypography import com.airbnb.android.showkase.annotation.ShowkaseTypography
@ShowkaseTypography(name = "Body Large", group = "Element") @ShowkaseTypography(name = "Body Large", group = "Element")
val bodyLarge = TextStyle( val bodyLarge = TextStyle(
fontFamily = FontFamily.Default, fontFamily = FontFamily.Default,
@ -231,6 +230,4 @@ object ElementTextStyles {
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
} }
} }

View file

@ -5,7 +5,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@Composable @Composable
fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
Button( Button(

View file

@ -6,7 +6,6 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun VectorTextField(value: String, onValueChange: (String) -> Unit, isError: Boolean = false) { fun VectorTextField(value: String, onValueChange: (String) -> Unit, isError: Boolean = false) {

View file

@ -52,7 +52,6 @@ private fun ImageAvatar(
) )
} }
@Composable @Composable
private fun InitialsAvatar( private fun InitialsAvatar(
initials: String, initials: String,

View file

@ -30,5 +30,4 @@ data class AvatarData(
result = 31 * result + size.value result = 31 * result + size.value
return result return result
} }
} }

View file

@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000" <vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24" android:tint="#000000"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24"
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8,9h8v10L8,19L8,9zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/> android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8,9h8v10L8,19L8,9zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z" />
</vector> </vector>

View file

@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000" <vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24" android:tint="#000000"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24"
<path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector> </vector>

View file

@ -1,5 +1,11 @@
<vector android:autoMirrored="true" android:height="24dp" <vector android:autoMirrored="true"
android:tint="#000000" android:viewportHeight="24" android:height="24dp"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:tint="#000000"
<path android:fillColor="@android:color/white" android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z"/> android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z" />
</vector> </vector>

View file

@ -1,5 +1,11 @@
<vector android:autoMirrored="true" android:height="24dp" <vector android:autoMirrored="true"
android:tint="#000000" android:viewportHeight="24" android:height="24dp"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:tint="#000000"
<path android:fillColor="@android:color/white" android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/> android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z" />
</vector> </vector>

View file

@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000" <vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24" android:tint="#000000"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24"
<path android:fillColor="@android:color/white" android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/> android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
</vector> </vector>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest>
</manifest> </manifest>

View file

@ -3,18 +3,18 @@
android:height="22dp" android:height="22dp"
android:viewportWidth="22" android:viewportWidth="22"
android:viewportHeight="22"> android:viewportHeight="22">
<path <path
android:pathData="M11,11m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0" android:pathData="M11,11m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#979797" android:strokeColor="#979797"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
<path <path
android:pathData="M7.667,7.667L14.333,14.333M14.333,7.667L7.667,14.333" android:pathData="M7.667,7.667L14.333,14.333M14.333,7.667L7.667,14.333"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#9E9E9E" android:strokeColor="#9E9E9E"
android:fillType="evenOdd" android:fillType="evenOdd"
android:strokeLineCap="round"/> android:strokeLineCap="round" />
</vector> </vector>

View file

@ -3,8 +3,8 @@
android:height="44dp" android:height="44dp"
android:viewportWidth="44" android:viewportWidth="44"
android:viewportHeight="44"> android:viewportHeight="44">
<path <path
android:pathData="M16,14.5C16,13.672 16.672,13 17.5,13H22.288C25.139,13 27.25,15.466 27.25,18.25C27.25,19.38 26.902,20.458 26.298,21.34C27.765,22.268 28.75,23.882 28.75,25.75C28.75,28.689 26.311,31 23.393,31H17.5C16.672,31 16,30.328 16,29.5V14.5ZM19,16V20.5H22.288C23.261,20.5 24.25,19.608 24.25,18.25C24.25,16.892 23.261,16 22.288,16H19ZM19,23.5V28H23.393C24.735,28 25.75,26.953 25.75,25.75C25.75,24.547 24.735,23.5 23.393,23.5H19Z" android:pathData="M16,14.5C16,13.672 16.672,13 17.5,13H22.288C25.139,13 27.25,15.466 27.25,18.25C27.25,19.38 26.902,20.458 26.298,21.34C27.765,22.268 28.75,23.882 28.75,25.75C28.75,28.689 26.311,31 23.393,31H17.5C16.672,31 16,30.328 16,29.5V14.5ZM19,16V20.5H22.288C23.261,20.5 24.25,19.608 24.25,18.25C24.25,16.892 23.261,16 22.288,16H19ZM19,23.5V28H23.393C24.735,28 25.75,26.953 25.75,25.75C25.75,24.547 24.735,23.5 23.393,23.5H19Z"
android:fillColor="#8D97A5" android:fillColor="#8D97A5"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
</vector> </vector>

View file

@ -3,7 +3,7 @@
android:height="48dp" android:height="48dp"
android:viewportWidth="48" android:viewportWidth="48"
android:viewportHeight="48"> android:viewportHeight="48">
<path <path
android:pathData="M17.125,31.5C16.944,31.5 16.795,31.441 16.677,31.323C16.559,31.205 16.5,31.056 16.5,30.875V25.875C16.5,25.694 16.559,25.545 16.677,25.427C16.795,25.309 16.944,25.25 17.125,25.25C17.306,25.25 17.455,25.309 17.573,25.427C17.691,25.545 17.75,25.694 17.75,25.875V29.375L29.375,17.75H25.875C25.694,17.75 25.545,17.691 25.427,17.573C25.309,17.455 25.25,17.306 25.25,17.125C25.25,16.944 25.309,16.795 25.427,16.677C25.545,16.559 25.694,16.5 25.875,16.5H30.875C31.056,16.5 31.205,16.559 31.323,16.677C31.441,16.795 31.5,16.944 31.5,17.125V22.125C31.5,22.306 31.441,22.455 31.323,22.573C31.205,22.691 31.056,22.75 30.875,22.75C30.694,22.75 30.545,22.691 30.427,22.573C30.309,22.455 30.25,22.306 30.25,22.125V18.625L18.625,30.25H22.125C22.306,30.25 22.455,30.309 22.573,30.427C22.691,30.545 22.75,30.694 22.75,30.875C22.75,31.056 22.691,31.205 22.573,31.323C22.455,31.441 22.306,31.5 22.125,31.5H17.125Z" android:pathData="M17.125,31.5C16.944,31.5 16.795,31.441 16.677,31.323C16.559,31.205 16.5,31.056 16.5,30.875V25.875C16.5,25.694 16.559,25.545 16.677,25.427C16.795,25.309 16.944,25.25 17.125,25.25C17.306,25.25 17.455,25.309 17.573,25.427C17.691,25.545 17.75,25.694 17.75,25.875V29.375L29.375,17.75H25.875C25.694,17.75 25.545,17.691 25.427,17.573C25.309,17.455 25.25,17.306 25.25,17.125C25.25,16.944 25.309,16.795 25.427,16.677C25.545,16.559 25.694,16.5 25.875,16.5H30.875C31.056,16.5 31.205,16.559 31.323,16.677C31.441,16.795 31.5,16.944 31.5,17.125V22.125C31.5,22.306 31.441,22.455 31.323,22.573C31.205,22.691 31.056,22.75 30.875,22.75C30.694,22.75 30.545,22.691 30.427,22.573C30.309,22.455 30.25,22.306 30.25,22.125V18.625L18.625,30.25H22.125C22.306,30.25 22.455,30.309 22.573,30.427C22.691,30.545 22.75,30.694 22.75,30.875C22.75,31.056 22.691,31.205 22.573,31.323C22.455,31.441 22.306,31.5 22.125,31.5H17.125Z"
android:fillColor="#C1C6CD"/> android:fillColor="#C1C6CD" />
</vector> </vector>

View file

@ -3,8 +3,8 @@
android:height="44dp" android:height="44dp"
android:viewportWidth="44" android:viewportWidth="44"
android:viewportHeight="44"> android:viewportHeight="44">
<path <path
android:pathData="M22.619,14.999L19.747,29.005H17.2C16.758,29.005 16.4,29.363 16.4,29.805C16.4,30.247 16.758,30.605 17.2,30.605H20.389C20.397,30.605 20.405,30.605 20.412,30.605H23.6C24.042,30.605 24.4,30.247 24.4,29.805C24.4,29.363 24.042,29.005 23.6,29.005H21.381L24.253,14.999H26.8C27.242,14.999 27.6,14.64 27.6,14.199C27.6,13.757 27.242,13.399 26.8,13.399H23.615C23.604,13.398 23.594,13.398 23.583,13.399H20.4C19.958,13.399 19.6,13.757 19.6,14.199C19.6,14.64 19.958,14.999 20.4,14.999H22.619Z" android:pathData="M22.619,14.999L19.747,29.005H17.2C16.758,29.005 16.4,29.363 16.4,29.805C16.4,30.247 16.758,30.605 17.2,30.605H20.389C20.397,30.605 20.405,30.605 20.412,30.605H23.6C24.042,30.605 24.4,30.247 24.4,29.805C24.4,29.363 24.042,29.005 23.6,29.005H21.381L24.253,14.999H26.8C27.242,14.999 27.6,14.64 27.6,14.199C27.6,13.757 27.242,13.399 26.8,13.399H23.615C23.604,13.398 23.594,13.398 23.583,13.399H20.4C19.958,13.399 19.6,13.757 19.6,14.199C19.6,14.64 19.958,14.999 20.4,14.999H22.619Z"
android:fillColor="#8D97A5" android:fillColor="#8D97A5"
android:fillType="evenOdd"/> android:fillType="evenOdd" />
</vector> </vector>

View file

@ -3,10 +3,10 @@
android:height="44dp" android:height="44dp"
android:viewportWidth="44" android:viewportWidth="44"
android:viewportHeight="44"> android:viewportHeight="44">
<path <path
android:pathData="M24.897,17.154C24.235,15.821 22.876,15.21 21.374,15.372C19.05,15.622 18.44,17.423 18.722,18.592C19.032,19.872 20.046,20.37 21.839,20.826H29.92C30.517,20.826 31,21.351 31,22C31,22.648 30.517,23.174 29.92,23.174H14.08C13.483,23.174 13,22.648 13,22C13,21.351 13.483,20.826 14.08,20.826H17.355C17.041,20.377 16.791,19.839 16.633,19.189C16.003,16.581 17.554,13.424 21.16,13.036C23.285,12.807 25.615,13.661 26.798,16.038C27.081,16.608 26.886,17.32 26.361,17.629C25.836,17.937 25.181,17.725 24.897,17.154Z" android:pathData="M24.897,17.154C24.235,15.821 22.876,15.21 21.374,15.372C19.05,15.622 18.44,17.423 18.722,18.592C19.032,19.872 20.046,20.37 21.839,20.826H29.92C30.517,20.826 31,21.351 31,22C31,22.648 30.517,23.174 29.92,23.174H14.08C13.483,23.174 13,22.648 13,22C13,21.351 13.483,20.826 14.08,20.826H17.355C17.041,20.377 16.791,19.839 16.633,19.189C16.003,16.581 17.554,13.424 21.16,13.036C23.285,12.807 25.615,13.661 26.798,16.038C27.081,16.608 26.886,17.32 26.361,17.629C25.836,17.937 25.181,17.725 24.897,17.154Z"
android:fillColor="#8D97A5"/> android:fillColor="#8D97A5" />
<path <path
android:pathData="M25.427,25.13H27.67C27.888,26.306 27.721,27.56 27.05,28.632C26.114,30.125 24.37,31 21.985,31C18.076,31 16.279,28.584 15.912,26.986C15.768,26.357 16.12,25.72 16.698,25.563C17.277,25.406 17.863,25.788 18.008,26.417C18.119,26.902 19.002,28.652 21.985,28.652C23.907,28.652 24.854,27.965 25.264,27.31C25.642,26.707 25.708,25.909 25.427,25.13Z" android:pathData="M25.427,25.13H27.67C27.888,26.306 27.721,27.56 27.05,28.632C26.114,30.125 24.37,31 21.985,31C18.076,31 16.279,28.584 15.912,26.986C15.768,26.357 16.12,25.72 16.698,25.563C17.277,25.406 17.863,25.788 18.008,26.417C18.119,26.902 19.002,28.652 21.985,28.652C23.907,28.652 24.854,27.965 25.264,27.31C25.642,26.707 25.708,25.909 25.427,25.13Z"
android:fillColor="#8D97A5"/> android:fillColor="#8D97A5" />
</vector> </vector>

View file

@ -3,11 +3,10 @@
android:height="44dp" android:height="44dp"
android:viewportWidth="44" android:viewportWidth="44"
android:viewportHeight="44"> android:viewportHeight="44">
<group> <group>
<clip-path <clip-path android:pathData="M10,10h24v24h-24z" />
android:pathData="M10,10h24v24h-24z"/> <path
<path android:pathData="M22.79,26.95C25.82,26.56 28,23.84 28,20.79V14.25C28,13.56 27.44,13 26.75,13C26.06,13 25.5,13.56 25.5,14.25V20.9C25.5,22.57 24.37,24.09 22.73,24.42C20.48,24.89 18.5,23.17 18.5,21V14.25C18.5,13.56 17.94,13 17.25,13C16.56,13 16,13.56 16,14.25V21C16,24.57 19.13,27.42 22.79,26.95ZM15,30C15,30.55 15.45,31 16,31H28C28.55,31 29,30.55 29,30C29,29.45 28.55,29 28,29H16C15.45,29 15,29.45 15,30Z"
android:pathData="M22.79,26.95C25.82,26.56 28,23.84 28,20.79V14.25C28,13.56 27.44,13 26.75,13C26.06,13 25.5,13.56 25.5,14.25V20.9C25.5,22.57 24.37,24.09 22.73,24.42C20.48,24.89 18.5,23.17 18.5,21V14.25C18.5,13.56 17.94,13 17.25,13C16.56,13 16,13.56 16,14.25V21C16,24.57 19.13,27.42 22.79,26.95ZM15,30C15,30.55 15.45,31 16,31H28C28.55,31 29,30.55 29,30C29,29.45 28.55,29 28,29H16C15.45,29 15,29.45 15,30Z" android:fillColor="#8D97A5" />
android:fillColor="#8D97A5"/> </group>
</group>
</vector> </vector>

View file

@ -3,18 +3,18 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:pathData="M4,18.6666L20,18.6666" android:pathData="M4,18.6666L20,18.6666"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="round"/> android:strokeLineCap="round" />
<path <path
android:pathData="M6.6667,14L16.0001,4.6666" android:pathData="M6.6667,14L16.0001,4.6666"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="round"/> android:strokeLineCap="round" />
</vector> </vector>

View file

@ -1,5 +1,10 @@
<vector android:autoMirrored="true" android:height="20dp" <vector android:autoMirrored="true"
android:viewportHeight="20" android:viewportWidth="20" android:height="20dp"
android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="20"
<path android:fillColor="#ffffff" android:pathData="M18.7922,11.1454L2.3564,19.3594C1.2489,19.9131 0.0966,18.7254 0.6379,17.6419C0.6379,17.6419 2.675,13.5282 3.2353,12.4507C3.7956,11.3731 4.437,11.1866 10.3935,10.4168C10.6139,10.3883 10.7943,10.2219 10.7943,9.9998C10.7943,9.778 10.6139,9.6117 10.3935,9.5832C4.437,8.8133 3.7956,8.6268 3.2353,7.5493C2.675,6.4721 0.6379,2.358 0.6379,2.358C0.0966,1.2749 1.2489,0.0869 2.3564,0.6405L18.7922,8.8549C19.7359,9.3262 19.7359,10.6738 18.7922,11.1454Z"/> android:viewportWidth="20"
android:width="20dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#ffffff"
android:pathData="M18.7922,11.1454L2.3564,19.3594C1.2489,19.9131 0.0966,18.7254 0.6379,17.6419C0.6379,17.6419 2.675,13.5282 3.2353,12.4507C3.7956,11.3731 4.437,11.1866 10.3935,10.4168C10.6139,10.3883 10.7943,10.2219 10.7943,9.9998C10.7943,9.778 10.6139,9.6117 10.3935,9.5832C4.437,8.8133 3.7956,8.6268 3.2353,7.5493C2.675,6.4721 0.6379,2.358 0.6379,2.358C0.0966,1.2749 1.2489,0.0869 2.3564,0.6405L18.7922,8.8549C19.7359,9.3262 19.7359,10.6738 18.7922,11.1454Z" />
</vector> </vector>

View file

@ -2,10 +2,11 @@
The transitions which us used for the entrance and exit of shared elements. Here we declare The transitions which us used for the entrance and exit of shared elements. Here we declare
two different transitions which are targeting specific views. two different transitions which are targeting specific views.
--> -->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:duration="200"> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200">
<!-- changeBounds is used for the TextViews which are shared --> <!-- changeBounds is used for the TextViews which are shared -->
<changeBounds/> <changeBounds />
<!-- changeImageTransform is used for the ImageViews which are shared --> <!-- changeImageTransform is used for the ImageViews which are shared -->
<changeImageTransform /> <changeImageTransform />

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Widget.Vector.ActionButton" parent="Widget.AppCompat.ActionButton"> <style name="Widget.Vector.ActionButton" parent="Widget.AppCompat.ActionButton">
<item name="android:paddingStart">5dp</item> <item name="android:paddingStart">5dp</item>
<item name="android:paddingEnd">5dp</item> <item name="android:paddingEnd">5dp</item>

View file

@ -2,15 +2,15 @@
<resources> <resources>
<style name="Widget.Vector.SnackBar" parent="@style/Widget.MaterialComponents.Snackbar"> <style name="Widget.Vector.SnackBar" parent="@style/Widget.MaterialComponents.Snackbar">
<!-- <item name="android:background">@color/notification_accent_color</item>--> <!-- <item name="android:background">@color/notification_accent_color</item>-->
</style> </style>
<style name="Widget.Vector.SnackBar.Button" parent="@style/Widget.Vector.Button.Text.OnPrimary"> <style name="Widget.Vector.SnackBar.Button" parent="@style/Widget.Vector.Button.Text.OnPrimary">
<!-- <item name="android:textColor">@color/white</item>--> <!-- <item name="android:textColor">@color/white</item>-->
</style> </style>
<style name="Widget.Vector.SnackBar.TextView" parent="@style/Widget.MaterialComponents.Snackbar.TextView"> <style name="Widget.Vector.SnackBar.TextView" parent="@style/Widget.MaterialComponents.Snackbar.TextView">
<!-- <item name="android:textColor">@color/white</item>--> <!-- <item name="android:textColor">@color/white</item>-->
</style> </style>
</resources> </resources>

View file

@ -10,14 +10,18 @@ import io.element.android.x.matrix.util.logError
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.AuthenticationService import org.matrix.rustcomponents.sdk.AuthenticationService
import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.ClientBuilder
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.util.* import java.util.Optional
import java.util.concurrent.Executors import java.util.concurrent.Executors
class Matrix( class Matrix(

View file

@ -11,7 +11,13 @@ import io.element.android.x.matrix.session.SessionStore
import io.element.android.x.matrix.sync.SlidingSyncObserverProxy import io.element.android.x.matrix.sync.SlidingSyncObserverProxy
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.* import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientDelegate
import org.matrix.rustcomponents.sdk.MediaSource
import org.matrix.rustcomponents.sdk.RequiredState
import org.matrix.rustcomponents.sdk.SlidingSyncMode
import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder
import org.matrix.rustcomponents.sdk.StoppableSpawn
import timber.log.Timber import timber.log.Timber
import java.io.Closeable import java.io.Closeable
import java.io.File import java.io.File
@ -78,7 +84,7 @@ class MatrixClient internal constructor(
client.setDelegate(clientDelegate) client.setDelegate(clientDelegate)
} }
private fun onRestartSync(){ private fun onRestartSync() {
slidingSyncObserverToken = slidingSync.sync() slidingSyncObserverToken = slidingSync.sync()
} }

View file

@ -7,7 +7,6 @@ import io.element.android.x.matrix.tracing.setupTracing
import io.element.android.x.sdk.matrix.BuildConfig import io.element.android.x.sdk.matrix.BuildConfig
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
object MatrixInstance { object MatrixInstance {
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
private lateinit var instance: Matrix private lateinit var instance: Matrix

View file

@ -80,15 +80,15 @@ object MatrixPatterns {
// list of patterns to find some matrix item. // list of patterns to find some matrix item.
val MATRIX_PATTERNS = listOf( val MATRIX_PATTERNS = listOf(
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS, PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_ALIAS, PATTERN_CONTAIN_MATRIX_ALIAS,
PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER, PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
) )
/** /**
@ -129,9 +129,9 @@ object MatrixPatterns {
*/ */
fun isEventId(str: String?): Boolean { fun isEventId(str: String?): Boolean {
return str != null && return str != null &&
(str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER || (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 || str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4) str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
} }
/** /**

View file

@ -3,4 +3,4 @@ package io.element.android.x.matrix.core
import java.io.Serializable import java.io.Serializable
@JvmInline @JvmInline
value class RoomId(val value: String): Serializable value class RoomId(val value: String) : Serializable

View file

@ -3,4 +3,4 @@ package io.element.android.x.matrix.core
import java.io.Serializable import java.io.Serializable
@JvmInline @JvmInline
value class UserId(val value: String): Serializable value class UserId(val value: String) : Serializable

View file

@ -24,7 +24,6 @@ interface MediaResolver {
suspend fun resolve(meta: Meta): ByteArray? suspend fun resolve(meta: Meta): ByteArray?
} }
internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver { internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver {
override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? { override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? {
@ -43,6 +42,4 @@ internal class RustMediaResolver(private val client: MatrixClient) : MediaResolv
) )
}.getOrNull() }.getOrNull()
} }
} }

View file

@ -43,12 +43,12 @@ object PermalinkParser {
// we are limiting to 2 params // we are limiting to 2 params
val params = safeFragment val params = safeFragment
.split(MatrixPatterns.SEP_REGEX) .split(MatrixPatterns.SEP_REGEX)
.filter { it.isNotEmpty() } .filter { it.isNotEmpty() }
.take(2) .take(2)
val decodedParams = params val decodedParams = params
.map { URLDecoder.decode(it, "UTF-8") } .map { URLDecoder.decode(it, "UTF-8") }
val identifier = params.getOrNull(0) val identifier = params.getOrNull(0)
val decodedIdentifier = decodedParams.getOrNull(0) val decodedIdentifier = decodedParams.getOrNull(0)
@ -61,10 +61,10 @@ object PermalinkParser {
} }
MatrixPatterns.isRoomAlias(decodedIdentifier) -> { MatrixPatterns.isRoomAlias(decodedIdentifier) -> {
PermalinkData.RoomLink( PermalinkData.RoomLink(
roomIdOrAlias = decodedIdentifier, roomIdOrAlias = decodedIdentifier,
isRoomAlias = true, isRoomAlias = true,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters viaParameters = viaQueryParameters
) )
} }
else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier)) else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
@ -83,16 +83,16 @@ object PermalinkParser {
val token = signValidUri.getQueryParameter("token") ?: throw IllegalArgumentException() val token = signValidUri.getQueryParameter("token") ?: throw IllegalArgumentException()
val privateKey = signValidUri.getQueryParameter("private_key") ?: throw IllegalArgumentException() val privateKey = signValidUri.getQueryParameter("private_key") ?: throw IllegalArgumentException()
PermalinkData.RoomEmailInviteLink( PermalinkData.RoomEmailInviteLink(
roomId = identifier, roomId = identifier,
email = email!!, email = email!!,
signUrl = signUrl!!, signUrl = signUrl!!,
roomName = paramList.firstOrNull { it.first == "room_name" }?.second, roomName = paramList.firstOrNull { it.first == "room_name" }?.second,
inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second, inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second,
roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second, roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second,
roomType = paramList.firstOrNull { it.first == "room_type" }?.second, roomType = paramList.firstOrNull { it.first == "room_type" }?.second,
identityServer = identityServerHost, identityServer = identityServerHost,
token = token, token = token,
privateKey = privateKey privateKey = privateKey
) )
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.i("## Permalink: Failed to parse permalink $signUrl") Timber.i("## Permalink: Failed to parse permalink $signUrl")
@ -100,29 +100,29 @@ object PermalinkParser {
} }
} else { } else {
PermalinkData.RoomLink( PermalinkData.RoomLink(
roomIdOrAlias = identifier, roomIdOrAlias = identifier,
isRoomAlias = false, isRoomAlias = false,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters viaParameters = viaQueryParameters
) )
} }
} }
private fun safeExtractParams(fragment: String) = private fun safeExtractParams(fragment: String) =
fragment.substringAfter("?").split('&').mapNotNull { fragment.substringAfter("?").split('&').mapNotNull {
val splitNameValue = it.split("=") val splitNameValue = it.split("=")
if (splitNameValue.size == 2) { if (splitNameValue.size == 2) {
Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8")) Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8"))
} else null } else null
} }
private fun String.getViaParameters(): List<String> { private fun String.getViaParameters(): List<String> {
return UrlQuerySanitizer(this) return UrlQuerySanitizer(this)
.parameterList .parameterList
.filter { .filter {
it.mParameter == "via" it.mParameter == "via"
}.map { }.map {
URLDecoder.decode(it.mValue, "UTF-8") URLDecoder.decode(it.mValue, "UTF-8")
} }
} }
} }

View file

@ -9,7 +9,11 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.* import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
import org.matrix.rustcomponents.sdk.UpdateSummary
import org.matrix.rustcomponents.sdk.genTransactionId
import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown
class MatrixRoom( class MatrixRoom(
private val slidingSyncUpdateFlow: Flow<UpdateSummary>, private val slidingSyncUpdateFlow: Flow<UpdateSummary>,
@ -98,7 +102,7 @@ class MatrixRoom(
} }
} }
suspend fun redactEvent(eventId: String, reason: String? = null, ) = withContext(coroutineDispatchers.io) { suspend fun redactEvent(eventId: String, reason: String? = null) = withContext(coroutineDispatchers.io) {
val transactionId = genTransactionId() val transactionId = genTransactionId()
runCatching { runCatching {
room.redact(eventId, reason, transactionId) room.redact(eventId, reason, transactionId)

View file

@ -9,7 +9,6 @@ import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineDiff
import org.matrix.rustcomponents.sdk.TimelineListener import org.matrix.rustcomponents.sdk.TimelineListener
fun Room.timelineDiff(scope: CoroutineScope): Flow<TimelineDiff> = callbackFlow { fun Room.timelineDiff(scope: CoroutineScope): Flow<TimelineDiff> = callbackFlow {
val listener = object : TimelineListener { val listener = object : TimelineListener {
override fun onUpdate(update: TimelineDiff) { override fun onUpdate(update: TimelineDiff) {

View file

@ -2,7 +2,6 @@ package io.element.android.x.matrix.room
import io.element.android.x.matrix.core.RoomId import io.element.android.x.matrix.core.RoomId
sealed interface RoomSummary { sealed interface RoomSummary {
data class Empty(val identifier: String) : RoomSummary data class Empty(val identifier: String) : RoomSummary
data class Filled(val details: RoomSummaryDetails) : RoomSummary data class Filled(val details: RoomSummaryDetails) : RoomSummary
@ -13,7 +12,6 @@ sealed interface RoomSummary {
is Filled -> details.roomId.value is Filled -> details.roomId.value
} }
} }
} }
data class RoomSummaryDetails( data class RoomSummaryDetails(

View file

@ -3,12 +3,27 @@ package io.element.android.x.matrix.room
import io.element.android.x.core.coroutine.CoroutineDispatchers import io.element.android.x.core.coroutine.CoroutineDispatchers
import io.element.android.x.matrix.sync.roomListDiff import io.element.android.x.matrix.sync.roomListDiff
import io.element.android.x.matrix.sync.state import io.element.android.x.matrix.sync.state
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.* import kotlinx.coroutines.SupervisorJob
import org.matrix.rustcomponents.sdk.* import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.RoomListEntry
import org.matrix.rustcomponents.sdk.SlidingSync
import org.matrix.rustcomponents.sdk.SlidingSyncState
import org.matrix.rustcomponents.sdk.SlidingSyncView
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff
import org.matrix.rustcomponents.sdk.UpdateSummary
import timber.log.Timber import timber.log.Timber
import java.io.Closeable import java.io.Closeable
import java.util.* import java.util.Collections
import java.util.UUID
interface RoomSummaryDataSource { interface RoomSummaryDataSource {
fun roomSummaries(): Flow<List<RoomSummary>> fun roomSummaries(): Flow<List<RoomSummary>>
@ -56,7 +71,6 @@ internal class RustRoomSummaryDataSource(
Timber.v("New sliding sync state: $slidingSyncState") Timber.v("New sliding sync state: $slidingSyncState")
state.value = slidingSyncState state.value = slidingSyncState
}.launchIn(coroutineScope) }.launchIn(coroutineScope)
} }
fun stopSync() { fun stopSync() {

View file

@ -7,7 +7,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncRoom
class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) { class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) {
fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails{ fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails {
val latestRoomMessage = slidingSyncRoom.latestRoomMessage()?.let { val latestRoomMessage = slidingSyncRoom.latestRoomMessage()?.let {
roomMessageFactory.create(it) roomMessageFactory.create(it)
} }
@ -17,14 +17,13 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto
else -> "${latestRoomMessage.sender.value}: ${latestRoomMessage.body}" else -> "${latestRoomMessage.sender.value}: ${latestRoomMessage.body}"
} }
return RoomSummaryDetails( return RoomSummaryDetails(
roomId = RoomId(slidingSyncRoom.roomId()), roomId = RoomId(slidingSyncRoom.roomId()),
name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(), name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(),
isDirect = slidingSyncRoom.isDm() ?: false, isDirect = slidingSyncRoom.isDm() ?: false,
avatarURLString = room?.avatarUrl(), avatarURLString = room?.avatarUrl(),
unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(), unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(),
lastMessage = computedLastMessage, lastMessage = computedLastMessage,
lastMessageTimestamp = latestRoomMessage?.originServerTs lastMessageTimestamp = latestRoomMessage?.originServerTs
) )
} }
} }

View file

@ -14,5 +14,4 @@ class RoomMessageFactory {
originServerTs = eventTimelineItem.originServerTs()?.toLong() ?: 0L originServerTs = eventTimelineItem.originServerTs()?.toLong() ?: 0L
) )
} }
} }

View file

@ -10,7 +10,8 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.* import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.matrix.rustcomponents.sdk.Session import org.matrix.rustcomponents.sdk.Session

View file

@ -11,6 +11,7 @@ import org.matrix.rustcomponents.sdk.UpdateSummary
// Sounds like a reasonable buffer size before it suspends emitting new items. // Sounds like a reasonable buffer size before it suspends emitting new items.
private const val BUFFER_SIZE = 64 private const val BUFFER_SIZE = 64
class SlidingSyncObserverProxy( class SlidingSyncObserverProxy(
private val coroutineScope: CoroutineScope, private val coroutineScope: CoroutineScope,
private val coroutineDispatchers: CoroutineDispatchers private val coroutineDispatchers: CoroutineDispatchers
@ -26,5 +27,4 @@ class SlidingSyncObserverProxy(
updateSummaryMutableFlow.emit(summary) updateSummaryMutableFlow.emit(summary)
} }
} }
} }

View file

@ -4,7 +4,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mxCallbackFlow import mxCallbackFlow
import org.matrix.rustcomponents.sdk.* import org.matrix.rustcomponents.sdk.SlidingSyncState
import org.matrix.rustcomponents.sdk.SlidingSyncView
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomListObserver
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsCountObserver
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff
import org.matrix.rustcomponents.sdk.SlidingSyncViewStateObserver
fun SlidingSyncView.roomListDiff(scope: CoroutineScope): Flow<SlidingSyncViewRoomsListDiff> = fun SlidingSyncView.roomListDiff(scope: CoroutineScope): Flow<SlidingSyncViewRoomsListDiff> =
mxCallbackFlow { mxCallbackFlow {

View file

@ -8,9 +8,14 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.sample import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.* import org.matrix.rustcomponents.sdk.PaginationOutcome
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
import org.matrix.rustcomponents.sdk.TimelineChange
import org.matrix.rustcomponents.sdk.TimelineDiff
import org.matrix.rustcomponents.sdk.TimelineListener
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Collections
class MatrixTimeline( class MatrixTimeline(
private val matrixRoom: MatrixRoom, private val matrixRoom: MatrixRoom,
@ -31,7 +36,6 @@ class MatrixTimeline(
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> = private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
MutableStateFlow(emptyList()) MutableStateFlow(emptyList())
fun timelineItems(): Flow<List<MatrixTimelineItem>> { fun timelineItems(): Flow<List<MatrixTimelineItem>> {
return timelineItems.sample(50) return timelineItems.sample(50)
} }
@ -41,7 +45,6 @@ class MatrixTimeline(
return paginationOutcome.value.moreMessages return paginationOutcome.value.moreMessages
} }
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) { private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) {
when (diff.change()) { when (diff.change()) {
TimelineChange.PUSH -> { TimelineChange.PUSH -> {
@ -140,5 +143,4 @@ class MatrixTimeline(
} }
} }
} }
} }

View file

@ -9,7 +9,6 @@ data class TracingConfiguration(
targets.map { "${it.key.filter}=${it.value.filter}" }.joinToString(separator = ",") targets.map { "${it.key.filter}=${it.value.filter}" }.joinToString(separator = ",")
}" }"
sealed class Target(open val filter: String) { sealed class Target(open val filter: String) {
object Hyper : Target("hyper") object Hyper : Target("hyper")
object Sled : Target("sled") object Sled : Target("sled")
@ -31,7 +30,6 @@ data class TracingConfiguration(
object Debug : LogLevel("debug") object Debug : LogLevel("debug")
object Error : LogLevel("error") object Error : LogLevel("error")
} }
} }
fun setupTracing(tracingConfiguration: TracingConfiguration) { fun setupTracing(tracingConfiguration: TracingConfiguration) {

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