Update plugin ktlint to v12.1.0 (#2200)
* Update plugin ktlint to v12.1.0 * Run `./gradlew ktlintFormat` and fix some issues manually. * Fix other issues reproted by Ktlint * Limit false positives, KtLint removes unnecessary curly brace in String templates. * Remove useless Unit * Minor improvements over ktlint changes * Restore `AlertDialogContent` behaviour * Update screenshots --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Benoit Marty <benoit@matrix.org> Co-authored-by: Jorge Martín <jorgem@element.io> Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
parent
675cc525cf
commit
7e9cda3aa9
442 changed files with 1091 additions and 1081 deletions
|
|
@ -17,7 +17,7 @@ ij_wrap_on_typing = false
|
||||||
# Ktlint rule, for more information see https://pinterest.github.io/ktlint/faq/#why-is-editorconfig-property-disabled_rules-deprecated-and-how-do-i-resolve-this
|
# Ktlint rule, for more information see https://pinterest.github.io/ktlint/faq/#why-is-editorconfig-property-disabled_rules-deprecated-and-how-do-i-resolve-this
|
||||||
ktlint_standard_wrapping = disabled
|
ktlint_standard_wrapping = disabled
|
||||||
ktlint_standard_trailing-comma-on-call-site = disabled
|
ktlint_standard_trailing-comma-on-call-site = disabled
|
||||||
|
ktlint_standard_spacing-between-declarations-with-annotations = disabled
|
||||||
|
|
||||||
[*.java]
|
[*.java]
|
||||||
ij_java_align_consecutive_assignments = false
|
ij_java_align_consecutive_assignments = false
|
||||||
|
|
|
||||||
|
|
@ -68,5 +68,4 @@ class MainNode(
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
object RootNavTarget : Parcelable
|
object RootNavTarget : Parcelable
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ interface AppComponent : NodeFactoriesBindings {
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(@ApplicationContext @BindsInstance context: Context): AppComponent
|
fun create(
|
||||||
|
@ApplicationContext @BindsInstance
|
||||||
|
context: Context
|
||||||
|
): AppComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,3 @@ fun <T : Any> BackStack<T>.removeLast(element: T) {
|
||||||
} ?: return
|
} ?: return
|
||||||
accept(Remove(lastExpectedNavElement.key))
|
accept(Remove(lastExpectedNavElement.key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,4 +274,3 @@ class RootFlowNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,9 @@ class MatrixClientsHolder @Inject constructor(private val authenticationService:
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun restoreWithSavedState(state: SavedStateMap?) {
|
fun restoreWithSavedState(state: SavedStateMap?) {
|
||||||
Timber.d("Restore state")
|
Timber.d("Restore state")
|
||||||
if (state == null || sessionIdsToMatrixClient.isNotEmpty()) return Unit.also {
|
if (state == null || sessionIdsToMatrixClient.isNotEmpty()) {
|
||||||
Timber.w("Restore with non-empty map")
|
Timber.w("Restore with non-empty map")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
val sessionIds = state[SAVE_INSTANCE_KEY] as? Array<SessionId>
|
val sessionIds = state[SAVE_INSTANCE_KEY] as? Array<SessionId>
|
||||||
Timber.d("Restore matrix session keys = ${sessionIds?.map { it.value }}")
|
Timber.d("Restore matrix session keys = ${sessionIds?.map { it.value }}")
|
||||||
|
|
|
||||||
|
|
@ -136,4 +136,3 @@ class RoomFlowNode @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,13 +216,15 @@ subprojects {
|
||||||
if (project.findProperty("composeCompilerReports") == "true") {
|
if (project.findProperty("composeCompilerReports") == "true") {
|
||||||
freeCompilerArgs += listOf(
|
freeCompilerArgs += listOf(
|
||||||
"-P",
|
"-P",
|
||||||
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
|
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
|
||||||
|
"${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (project.findProperty("composeCompilerMetrics") == "true") {
|
if (project.findProperty("composeCompilerMetrics") == "true") {
|
||||||
freeCompilerArgs += listOf(
|
freeCompilerArgs += listOf(
|
||||||
"-P",
|
"-P",
|
||||||
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
|
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
|
||||||
|
"${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
||||||
import io.element.android.features.analytics.api.R
|
import io.element.android.features.analytics.api.R
|
||||||
import io.element.android.libraries.designsystem.components.LINK_TAG
|
import io.element.android.libraries.designsystem.components.LINK_TAG
|
||||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
||||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||||
import io.element.android.libraries.designsystem.theme.components.ListSupportingText
|
import io.element.android.libraries.designsystem.theme.components.ListSupportingText
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@ package io.element.android.features.analytics.impl
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
open class AnalyticsOptInStateProvider @Inject constructor(
|
open class AnalyticsOptInStateProvider @Inject constructor() : PreviewParameterProvider<AnalyticsOptInState> {
|
||||||
) : PreviewParameterProvider<AnalyticsOptInState> {
|
|
||||||
override val values: Sequence<AnalyticsOptInState>
|
override val values: Sequence<AnalyticsOptInState>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aAnalyticsOptInState(),
|
aAnalyticsOptInState(),
|
||||||
|
|
|
||||||
|
|
@ -70,4 +70,3 @@ class AnalyticsOptInPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,4 +82,3 @@ class AnalyticsPreferencesPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ data class WidgetMessage(
|
||||||
enum class Direction {
|
enum class Direction {
|
||||||
@SerialName("fromWidget")
|
@SerialName("fromWidget")
|
||||||
FromWidget,
|
FromWidget,
|
||||||
|
|
||||||
@SerialName("toWidget")
|
@SerialName("toWidget")
|
||||||
ToWidget
|
ToWidget
|
||||||
}
|
}
|
||||||
|
|
@ -41,6 +42,7 @@ data class WidgetMessage(
|
||||||
enum class Action {
|
enum class Action {
|
||||||
@SerialName("im.vector.hangup")
|
@SerialName("im.vector.hangup")
|
||||||
HangUp,
|
HangUp,
|
||||||
|
|
||||||
@SerialName("send_event")
|
@SerialName("send_event")
|
||||||
SendEvent,
|
SendEvent,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,4 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||||
navigator.close()
|
navigator.close()
|
||||||
widgetDriver?.close()
|
widgetDriver?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class WebViewWidgetMessageInterceptor(
|
||||||
|| !message.data.response && message.data.api == "fromWidget") {
|
|| !message.data.response && message.data.api == "fromWidget") {
|
||||||
let json = JSON.stringify(event.data)
|
let json = JSON.stringify(event.data)
|
||||||
${"console.log('message sent: ' + json);".takeIf { BuildConfig.DEBUG } }
|
${"console.log('message sent: ' + json);".takeIf { BuildConfig.DEBUG } }
|
||||||
${LISTENER_NAME}.postMessage(json);
|
$LISTENER_NAME.postMessage(json);
|
||||||
} else {
|
} else {
|
||||||
${"console.log('message received (ignored): ' + JSON.stringify(event.data));".takeIf { BuildConfig.DEBUG } }
|
${"console.log('message received (ignored): ' + JSON.stringify(event.data));".takeIf { BuildConfig.DEBUG } }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url extra param appPrompt gets url extracted`() {
|
fun `Element Call url with url extra param appPrompt gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}&appPrompt=true",
|
url = "$VALID_CALL_URL_WITH_PARAM&appPrompt=true",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +125,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url extra param in fragment appPrompt gets url extracted`() {
|
fun `Element Call url with url extra param in fragment appPrompt gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#?appPrompt=true",
|
url = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=true",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&confineToRoom=true"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&confineToRoom=true"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +133,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url extra param in fragment appPrompt and other gets url extracted`() {
|
fun `Element Call url with url extra param in fragment appPrompt and other gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#?appPrompt=true&otherParam=maybe",
|
url = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=true&otherParam=maybe",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&otherParam=maybe&confineToRoom=true"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&otherParam=maybe&confineToRoom=true"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +141,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url extra param confineToRoom gets url extracted`() {
|
fun `Element Call url with url extra param confineToRoom gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}&confineToRoom=false",
|
url = "$VALID_CALL_URL_WITH_PARAM&confineToRoom=false",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +149,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url extra param in fragment confineToRoom gets url extracted`() {
|
fun `Element Call url with url extra param in fragment confineToRoom gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#?confineToRoom=false",
|
url = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=false",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&appPrompt=false"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&appPrompt=false"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -157,7 +157,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url extra param in fragment confineToRoom and more gets url extracted`() {
|
fun `Element Call url with url extra param in fragment confineToRoom and more gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#?confineToRoom=false&otherParam=maybe",
|
url = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=false&otherParam=maybe",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&otherParam=maybe&appPrompt=false"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&otherParam=maybe&appPrompt=false"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +165,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url fragment gets url extracted`() {
|
fun `Element Call url with url fragment gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#fragment",
|
url = "$VALID_CALL_URL_WITH_PARAM#fragment",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url fragment with params gets url extracted`() {
|
fun `Element Call url with url fragment with params gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#fragment?otherParam=maybe",
|
url = "$VALID_CALL_URL_WITH_PARAM#fragment?otherParam=maybe",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?otherParam=maybe&$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?otherParam=maybe&$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +181,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with url fragment with other params gets url extracted`() {
|
fun `Element Call url with url fragment with other params gets url extracted`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#?otherParam=maybe",
|
url = "$VALID_CALL_URL_WITH_PARAM#?otherParam=maybe",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?otherParam=maybe&$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?otherParam=maybe&$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -189,7 +189,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with empty fragment`() {
|
fun `Element Call url with empty fragment`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#",
|
url = "$VALID_CALL_URL_WITH_PARAM#",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +197,7 @@ class CallIntentDataParserTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Element Call url with empty fragment query`() {
|
fun `Element Call url with empty fragment query`() {
|
||||||
doTest(
|
doTest(
|
||||||
url = "${VALID_CALL_URL_WITH_PARAM}#?",
|
url = "$VALID_CALL_URL_WITH_PARAM#?",
|
||||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import javax.inject.Inject
|
||||||
class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint {
|
class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint {
|
||||||
|
|
||||||
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder {
|
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder {
|
||||||
|
|
||||||
val plugins = ArrayList<Plugin>()
|
val plugins = ArrayList<Plugin>()
|
||||||
|
|
||||||
return object : CreateRoomEntryPoint.NodeBuilder {
|
return object : CreateRoomEntryPoint.NodeBuilder {
|
||||||
|
|
|
||||||
|
|
@ -45,4 +45,3 @@ class AddPeoplePresenter @Inject constructor(
|
||||||
return userListPresenter.present()
|
return userListPresenter.present()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,13 @@ open class AddPeopleUserListStateProvider : PreviewParameterProvider<UserListSta
|
||||||
selectionMode = SelectionMode.Multiple,
|
selectionMode = SelectionMode.Multiple,
|
||||||
),
|
),
|
||||||
aUserListState().copy(
|
aUserListState().copy(
|
||||||
searchResults = SearchBarResultState.Results(aMatrixUserList()
|
searchResults = SearchBarResultState.Results(
|
||||||
|
aMatrixUserList()
|
||||||
.mapIndexed { index, matrixUser ->
|
.mapIndexed { index, matrixUser ->
|
||||||
UserSearchResult(matrixUser, index % 2 == 0)
|
UserSearchResult(matrixUser, index % 2 == 0)
|
||||||
}
|
}
|
||||||
.toImmutableList()),
|
.toImmutableList()
|
||||||
|
),
|
||||||
selectedUsers = aListOfSelectedUsers(),
|
selectedUsers = aListOfSelectedUsers(),
|
||||||
isSearchActive = true,
|
isSearchActive = true,
|
||||||
selectionMode = SelectionMode.Multiple,
|
selectionMode = SelectionMode.Multiple,
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.createroom.impl.configureroom.RoomPrivacyItem
|
import io.element.android.features.createroom.impl.configureroom.RoomPrivacyItem
|
||||||
import io.element.android.features.createroom.impl.configureroom.roomPrivacyItems
|
import io.element.android.features.createroom.impl.configureroom.roomPrivacyItems
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.RadioButton
|
import io.element.android.libraries.designsystem.theme.components.RadioButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomPrivacyOption(
|
fun RoomPrivacyOption(
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ package io.element.android.features.createroom.impl.configureroom
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import io.element.android.libraries.designsystem.icons.CompoundDrawables
|
|
||||||
import io.element.android.features.createroom.impl.R
|
import io.element.android.features.createroom.impl.R
|
||||||
|
import io.element.android.libraries.designsystem.icons.CompoundDrawables
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package io.element.android.features.createroom.impl.root
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.createroom.impl.userlist.aUserListState
|
import io.element.android.features.createroom.impl.userlist.aUserListState
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
|
||||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
import io.element.android.libraries.usersearch.api.UserSearchResult
|
import io.element.android.libraries.usersearch.api.UserSearchResult
|
||||||
|
|
|
||||||
|
|
@ -57,4 +57,3 @@ class AddPeoplePresenterTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -316,4 +316,3 @@ class ConfigureRoomPresenterTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,6 @@ class CreateRoomRootPresenterTests {
|
||||||
awaitItem().also { state ->
|
awaitItem().also { state ->
|
||||||
assertThat(state.startDmAction).isEqualTo(startDMSuccessResult)
|
assertThat(state.startDmAction).isEqualTo(startDMSuccessResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,5 +50,6 @@ fun MigrationScreenView(
|
||||||
internal fun MigrationViewPreview() = ElementPreview {
|
internal fun MigrationViewPreview() = ElementPreview {
|
||||||
MigrationScreenView(
|
MigrationScreenView(
|
||||||
migrationState = MigrationScreenState(isMigrating = true),
|
migrationState = MigrationScreenState(isMigrating = true),
|
||||||
onMigrationFinished = {})
|
onMigrationFinished = {}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,3 @@ class SharedPrefsMigrationScreenStore @Inject constructor(
|
||||||
private const val IS_MIGRATION_SCREEN_SHOWN_PREFIX = "is_migration_screen_shown_"
|
private const val IS_MIGRATION_SCREEN_SHOWN_PREFIX = "is_migration_screen_shown_"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ class NotificationsOptInPresenter @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(notificationsPermissionsState) {
|
LaunchedEffect(notificationsPermissionsState) {
|
||||||
if (notificationsPermissionsState.permissionGranted
|
if (notificationsPermissionsState.permissionGranted ||
|
||||||
|| notificationsPermissionsState.permissionAlreadyDenied) {
|
notificationsPermissionsState.permissionAlreadyDenied) {
|
||||||
callback.onNotificationsOptInFinished()
|
callback.onNotificationsOptInFinished()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import javax.inject.Inject
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
class DefaultFtueState @Inject constructor(
|
class DefaultFtueState @Inject constructor(
|
||||||
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
||||||
private val coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val welcomeScreenState: WelcomeScreenState,
|
private val welcomeScreenState: WelcomeScreenState,
|
||||||
private val migrationScreenStore: MigrationScreenStore,
|
private val migrationScreenStore: MigrationScreenStore,
|
||||||
|
|
@ -68,21 +68,31 @@ class DefaultFtueState @Inject constructor(
|
||||||
|
|
||||||
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
|
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
|
||||||
when (currentStep) {
|
when (currentStep) {
|
||||||
null -> if (shouldDisplayMigrationScreen()) FtueStep.MigrationScreen else getNextStep(
|
null -> if (shouldDisplayMigrationScreen()) {
|
||||||
FtueStep.MigrationScreen
|
FtueStep.MigrationScreen
|
||||||
)
|
} else {
|
||||||
FtueStep.MigrationScreen -> if (shouldDisplayWelcomeScreen()) FtueStep.WelcomeScreen else getNextStep(
|
getNextStep(FtueStep.MigrationScreen)
|
||||||
|
}
|
||||||
|
FtueStep.MigrationScreen -> if (shouldDisplayWelcomeScreen()) {
|
||||||
FtueStep.WelcomeScreen
|
FtueStep.WelcomeScreen
|
||||||
)
|
} else {
|
||||||
FtueStep.WelcomeScreen -> if (shouldAskNotificationPermissions()) FtueStep.NotificationsOptIn else getNextStep(
|
getNextStep(FtueStep.WelcomeScreen)
|
||||||
|
}
|
||||||
|
FtueStep.WelcomeScreen -> if (shouldAskNotificationPermissions()) {
|
||||||
FtueStep.NotificationsOptIn
|
FtueStep.NotificationsOptIn
|
||||||
)
|
} else {
|
||||||
FtueStep.NotificationsOptIn -> if (shouldDisplayLockscreenSetup()) FtueStep.LockscreenSetup else getNextStep(
|
getNextStep(FtueStep.NotificationsOptIn)
|
||||||
|
}
|
||||||
|
FtueStep.NotificationsOptIn -> if (shouldDisplayLockscreenSetup()) {
|
||||||
FtueStep.LockscreenSetup
|
FtueStep.LockscreenSetup
|
||||||
)
|
} else {
|
||||||
FtueStep.LockscreenSetup -> if (needsAnalyticsOptIn()) FtueStep.AnalyticsOptIn else getNextStep(
|
getNextStep(FtueStep.LockscreenSetup)
|
||||||
|
}
|
||||||
|
FtueStep.LockscreenSetup -> if (needsAnalyticsOptIn()) {
|
||||||
FtueStep.AnalyticsOptIn
|
FtueStep.AnalyticsOptIn
|
||||||
)
|
} else {
|
||||||
|
getNextStep(FtueStep.AnalyticsOptIn)
|
||||||
|
}
|
||||||
FtueStep.AnalyticsOptIn -> null
|
FtueStep.AnalyticsOptIn -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +125,9 @@ class DefaultFtueState @Inject constructor(
|
||||||
val isPermissionDenied = runBlocking { permissionStateProvider.isPermissionDenied(permission).first() }
|
val isPermissionDenied = runBlocking { permissionStateProvider.isPermissionDenied(permission).first() }
|
||||||
val isPermissionGranted = permissionStateProvider.isPermissionGranted(permission)
|
val isPermissionGranted = permissionStateProvider.isPermissionGranted(permission)
|
||||||
!isPermissionGranted && !isPermissionDenied
|
!isPermissionGranted && !isPermissionDenied
|
||||||
} else false
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldDisplayLockscreenSetup(): Boolean {
|
private fun shouldDisplayLockscreenSetup(): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -50,5 +50,4 @@ class WelcomeNode @AssistedInject constructor(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,4 +37,3 @@ interface InviteListEntryPoint : FeatureEntryPoint {
|
||||||
fun onInviteAccepted(roomId: RoomId)
|
fun onInviteAccepted(roomId: RoomId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ import javax.inject.Inject
|
||||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_seeninvites")
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "elementx_seeninvites")
|
||||||
private val seenInvitesKey = stringSetPreferencesKey("seenInvites")
|
private val seenInvitesKey = stringSetPreferencesKey("seenInvites")
|
||||||
|
|
||||||
|
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
class DefaultSeenInvitesStore @Inject constructor(
|
class DefaultSeenInvitesStore @Inject constructor(
|
||||||
@ApplicationContext context: Context
|
@ApplicationContext context: Context
|
||||||
|
|
@ -55,5 +54,4 @@ class DefaultSeenInvitesStore @Inject constructor(
|
||||||
prefs[seenInvitesKey] = roomIds.map { it.value }.toSet()
|
prefs[seenInvitesKey] = roomIds.map { it.value }.toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,25 +159,27 @@ class InviteListPresenter @Inject constructor(
|
||||||
|
|
||||||
private fun RoomSummary.Filled.toInviteSummary(seen: Boolean) = details.run {
|
private fun RoomSummary.Filled.toInviteSummary(seen: Boolean) = details.run {
|
||||||
val i = inviter
|
val i = inviter
|
||||||
val avatarData = if (isDirect && i != null)
|
val avatarData = if (isDirect && i != null) {
|
||||||
AvatarData(
|
AvatarData(
|
||||||
id = i.userId.value,
|
id = i.userId.value,
|
||||||
name = i.displayName,
|
name = i.displayName,
|
||||||
url = i.avatarUrl,
|
url = i.avatarUrl,
|
||||||
size = AvatarSize.RoomInviteItem,
|
size = AvatarSize.RoomInviteItem,
|
||||||
)
|
)
|
||||||
else
|
} else {
|
||||||
AvatarData(
|
AvatarData(
|
||||||
id = roomId.value,
|
id = roomId.value,
|
||||||
name = name,
|
name = name,
|
||||||
url = avatarURLString,
|
url = avatarURLString,
|
||||||
size = AvatarSize.RoomInviteItem,
|
size = AvatarSize.RoomInviteItem,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val alias = if (isDirect)
|
val alias = if (isDirect) {
|
||||||
inviter?.userId?.value
|
inviter?.userId?.value
|
||||||
else
|
} else {
|
||||||
canonicalAlias
|
canonicalAlias
|
||||||
|
}
|
||||||
|
|
||||||
InviteListInviteSummary(
|
InviteListInviteSummary(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
|
@ -186,7 +188,9 @@ class InviteListPresenter @Inject constructor(
|
||||||
roomAvatarData = avatarData,
|
roomAvatarData = avatarData,
|
||||||
isDirect = isDirect,
|
isDirect = isDirect,
|
||||||
isNew = !seen,
|
isNew = !seen,
|
||||||
sender = if (isDirect) null else inviter?.run {
|
sender = inviter
|
||||||
|
?.takeIf { !isDirect }
|
||||||
|
?.run {
|
||||||
InviteSender(
|
InviteSender(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
displayName = displayName ?: "",
|
displayName = displayName ?: "",
|
||||||
|
|
|
||||||
|
|
@ -69,15 +69,17 @@ fun InviteListView(
|
||||||
)
|
)
|
||||||
|
|
||||||
if (state.declineConfirmationDialog is InviteDeclineConfirmationDialog.Visible) {
|
if (state.declineConfirmationDialog is InviteDeclineConfirmationDialog.Visible) {
|
||||||
val contentResource = if (state.declineConfirmationDialog.isDirect)
|
val contentResource = if (state.declineConfirmationDialog.isDirect) {
|
||||||
R.string.screen_invites_decline_direct_chat_message
|
R.string.screen_invites_decline_direct_chat_message
|
||||||
else
|
} else {
|
||||||
R.string.screen_invites_decline_chat_message
|
R.string.screen_invites_decline_chat_message
|
||||||
|
}
|
||||||
|
|
||||||
val titleResource = if (state.declineConfirmationDialog.isDirect)
|
val titleResource = if (state.declineConfirmationDialog.isDirect) {
|
||||||
R.string.screen_invites_decline_direct_chat_title
|
R.string.screen_invites_decline_direct_chat_title
|
||||||
else
|
} else {
|
||||||
R.string.screen_invites_decline_chat_title
|
R.string.screen_invites_decline_chat_title
|
||||||
|
}
|
||||||
|
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
content = stringResource(contentResource, state.declineConfirmationDialog.name),
|
content = stringResource(contentResource, state.declineConfirmationDialog.name),
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.invitelist.impl.R
|
import io.element.android.features.invitelist.impl.R
|
||||||
import io.element.android.features.invitelist.impl.model.InviteListInviteSummary
|
import io.element.android.features.invitelist.impl.model.InviteListInviteSummary
|
||||||
import io.element.android.features.invitelist.impl.model.InviteListInviteSummaryProvider
|
import io.element.android.features.invitelist.impl.model.InviteListInviteSummaryProvider
|
||||||
|
|
@ -51,7 +52,6 @@ import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
import io.element.android.libraries.designsystem.theme.components.ButtonSize
|
import io.element.android.libraries.designsystem.theme.components.ButtonSize
|
||||||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
private val minHeight = 72.dp
|
private val minHeight = 72.dp
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ internal class MapTilerStaticMapUrlBuilder(
|
||||||
// image smaller than the available space in pixels.
|
// image smaller than the available space in pixels.
|
||||||
// The resulting image will have to be scaled to fit the available space in order
|
// The resulting image will have to be scaled to fit the available space in order
|
||||||
// to keep the perceived content size constant at the expense of sharpness.
|
// to keep the perceived content size constant at the expense of sharpness.
|
||||||
return "$MAPTILER_BASE_URL/${mapId}/static/${lon},${lat},${finalZoom}/${finalWidth}x${finalHeight}${scale}.webp?key=${apiKey}&attribution=bottomleft"
|
return "$MAPTILER_BASE_URL/$mapId/static/$lon,$lat,$finalZoom/${finalWidth}x${finalHeight}$scale.webp?key=$apiKey&attribution=bottomleft"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,6 @@ internal class MapTilerTileServerStyleUriBuilder(
|
||||||
|
|
||||||
override fun build(darkMode: Boolean): String {
|
override fun build(darkMode: Boolean): String {
|
||||||
val mapId = if (darkMode) darkMapId else lightMapId
|
val mapId = if (darkMode) darkMapId else lightMapId
|
||||||
return "${MAPTILER_BASE_URL}/${mapId}/style.json?key=${apiKey}"
|
return "$MAPTILER_BASE_URL/$mapId/style.json?key=$apiKey"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import javax.inject.Inject
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class SendLocationEntryPointImpl @Inject constructor() : SendLocationEntryPoint {
|
class SendLocationEntryPointImpl @Inject constructor() : SendLocationEntryPoint {
|
||||||
override fun createNode(
|
override fun createNode(
|
||||||
parentNode: Node, buildContext: BuildContext
|
parentNode: Node,
|
||||||
|
buildContext: BuildContext
|
||||||
): SendLocationNode = parentNode.createNode(buildContext)
|
): SendLocationNode = parentNode.createNode(buildContext)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,11 @@ class SendLocationPresenter @Inject constructor(
|
||||||
val permissionsState: PermissionsState = permissionsPresenter.present()
|
val permissionsState: PermissionsState = permissionsPresenter.present()
|
||||||
var mode: SendLocationState.Mode by remember {
|
var mode: SendLocationState.Mode by remember {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
if (permissionsState.isAnyGranted) SendLocationState.Mode.SenderLocation
|
if (permissionsState.isAnyGranted) {
|
||||||
else SendLocationState.Mode.PinLocation
|
SendLocationState.Mode.SenderLocation
|
||||||
|
} else {
|
||||||
|
SendLocationState.Mode.PinLocation
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val appName by remember { derivedStateOf { buildMeta.applicationName } }
|
val appName by remember { derivedStateOf { buildMeta.applicationName } }
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ class SendLocationPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
sendLocationPresenter.present()
|
sendLocationPresenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||||
|
|
@ -102,7 +101,6 @@ class SendLocationPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
sendLocationPresenter.present()
|
sendLocationPresenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||||
|
|
@ -381,7 +379,9 @@ class SendLocationPresenterTest {
|
||||||
)
|
)
|
||||||
fakeMessageComposerContext.apply {
|
fakeMessageComposerContext.apply {
|
||||||
composerMode = MessageComposerMode.Edit(
|
composerMode = MessageComposerMode.Edit(
|
||||||
eventId = null, defaultContent = "", transactionId = null
|
eventId = null,
|
||||||
|
defaultContent = "",
|
||||||
|
transactionId = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,7 +427,9 @@ class SendLocationPresenterTest {
|
||||||
)
|
)
|
||||||
fakeMessageComposerContext.apply {
|
fakeMessageComposerContext.apply {
|
||||||
composerMode = MessageComposerMode.Edit(
|
composerMode = MessageComposerMode.Edit(
|
||||||
eventId = null, defaultContent = "", transactionId = null
|
eventId = null,
|
||||||
|
defaultContent = "",
|
||||||
|
transactionId = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import javax.inject.Inject
|
||||||
class DefaultLockScreenEntryPoint @Inject constructor() : LockScreenEntryPoint {
|
class DefaultLockScreenEntryPoint @Inject constructor() : LockScreenEntryPoint {
|
||||||
|
|
||||||
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): LockScreenEntryPoint.NodeBuilder {
|
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): LockScreenEntryPoint.NodeBuilder {
|
||||||
|
|
||||||
var innerTarget: LockScreenEntryPoint.Target = LockScreenEntryPoint.Target.Unlock
|
var innerTarget: LockScreenEntryPoint.Target = LockScreenEntryPoint.Target.Unlock
|
||||||
val callbacks = mutableListOf<LockScreenEntryPoint.Callback>()
|
val callbacks = mutableListOf<LockScreenEntryPoint.Callback>()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,15 +66,15 @@ class DefaultBiometricUnlockManager @Inject constructor(
|
||||||
* Returns true if a weak biometric method (i.e.: some face or iris unlock implementations) can be used.
|
* Returns true if a weak biometric method (i.e.: some face or iris unlock implementations) can be used.
|
||||||
*/
|
*/
|
||||||
private val canUseWeakBiometricAuth: Boolean
|
private val canUseWeakBiometricAuth: Boolean
|
||||||
get() = lockScreenConfig.isWeakBiometricsEnabled
|
get() = lockScreenConfig.isWeakBiometricsEnabled &&
|
||||||
&& biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS
|
biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a strong biometric method (i.e.: fingerprint, some face or iris unlock implementations) can be used.
|
* Returns true if a strong biometric method (i.e.: fingerprint, some face or iris unlock implementations) can be used.
|
||||||
*/
|
*/
|
||||||
private val canUseStrongBiometricAuth: Boolean
|
private val canUseStrongBiometricAuth: Boolean
|
||||||
get() = lockScreenConfig.isStrongBiometricsEnabled
|
get() = lockScreenConfig.isStrongBiometricsEnabled &&
|
||||||
&& biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if any biometric method (weak or strong) can be used.
|
* Returns true if any biometric method (weak or strong) can be used.
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
||||||
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
|
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.pinDigitBg
|
import io.element.android.libraries.designsystem.theme.pinDigitBg
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PinEntryTextField(
|
fun PinEntryTextField(
|
||||||
|
|
@ -112,7 +112,6 @@ private fun PinDigitView(
|
||||||
style = ElementTheme.typography.fontHeadingMdBold
|
style = ElementTheme.typography.fontHeadingMdBold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,6 @@ class LockScreenSettingsFlowNode @AssistedInject constructor(
|
||||||
createNode<LockScreenSettingsNode>(buildContext, plugins = listOf(callback))
|
createNode<LockScreenSettingsNode>(buildContext, plugins = listOf(callback))
|
||||||
}
|
}
|
||||||
NavTarget.Unknown -> node(buildContext) { }
|
NavTarget.Unknown -> node(buildContext) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.lockscreen.impl.R
|
import io.element.android.features.lockscreen.impl.R
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||||
|
|
@ -29,7 +30,6 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LockScreenSettingsView(
|
fun LockScreenSettingsView(
|
||||||
|
|
@ -79,7 +79,8 @@ fun LockScreenSettingsView(
|
||||||
},
|
},
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
state.eventSink(LockScreenSettingsEvents.CancelRemovePin)
|
state.eventSink(LockScreenSettingsEvents.CancelRemovePin)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ class SetupBiometricPresenter @Inject constructor(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): SetupBiometricState {
|
override fun present(): SetupBiometricState {
|
||||||
|
|
||||||
var isBiometricSetupDone by remember {
|
var isBiometricSetupDone by remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,4 +97,3 @@ internal fun SetupBiometricViewPreview(@PreviewParameter(SetupBiometricStateProv
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,3 @@ fun aSetupPinState(
|
||||||
appName = "Element",
|
appName = "Element",
|
||||||
eventSink = {}
|
eventSink = {}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,5 +42,4 @@ interface EncryptedPinCodeStorage {
|
||||||
* Returns whether the PIN code is stored or not.
|
* Returns whether the PIN code is stored or not.
|
||||||
*/
|
*/
|
||||||
fun hasPinCode(): Flow<Boolean>
|
fun hasPinCode(): Flow<Boolean>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ data class PinUnlockState(
|
||||||
}
|
}
|
||||||
|
|
||||||
val biometricUnlockErrorMessage = when {
|
val biometricUnlockErrorMessage = when {
|
||||||
biometricUnlockResult is BiometricUnlock.AuthenticationResult.Failure
|
biometricUnlockResult is BiometricUnlock.AuthenticationResult.Failure &&
|
||||||
&& biometricUnlockResult.error is BiometricUnlockError
|
biometricUnlockResult.error is BiometricUnlockError &&
|
||||||
&& biometricUnlockResult.error.isAuthDisabledError -> {
|
biometricUnlockResult.error.isAuthDisabledError -> {
|
||||||
biometricUnlockResult.error.message
|
biometricUnlockResult.error.message
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package io.element.android.features.lockscreen.impl.unlock
|
package io.element.android.features.lockscreen.impl.unlock
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
|
@ -51,6 +50,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.lockscreen.impl.R
|
import io.element.android.features.lockscreen.impl.R
|
||||||
import io.element.android.features.lockscreen.impl.components.PinEntryTextField
|
import io.element.android.features.lockscreen.impl.components.PinEntryTextField
|
||||||
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
||||||
|
|
@ -68,7 +68,6 @@ import io.element.android.libraries.designsystem.theme.components.Surface
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -378,4 +377,3 @@ internal fun PinUnlockDefaultViewPreview(@PreviewParameter(PinUnlockStateProvide
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,11 @@ import androidx.compose.ui.unit.coerceAtMost
|
||||||
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 androidx.compose.ui.unit.times
|
import androidx.compose.ui.unit.times
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.text.toSp
|
import io.element.android.libraries.designsystem.text.toSp
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
|
|
@ -210,5 +210,3 @@ internal fun PinKeypadPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SingleIn(AppScope::class)
|
@SingleIn(AppScope::class)
|
||||||
class AccountProviderDataSource @Inject constructor(
|
class AccountProviderDataSource @Inject constructor() {
|
||||||
) {
|
|
||||||
private val accountProvider: MutableStateFlow<AccountProvider> = MutableStateFlow(
|
private val accountProvider: MutableStateFlow<AccountProvider> = MutableStateFlow(
|
||||||
defaultAccountProvider
|
defaultAccountProvider
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,11 @@ fun AccountProviderView(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(modifier = modifier
|
Column(
|
||||||
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable { onClick() }) {
|
.clickable { onClick() }
|
||||||
|
) {
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,11 @@ fun ChangeServerView(
|
||||||
onLearnMoreClicked = {
|
onLearnMoreClicked = {
|
||||||
onLearnMoreClicked()
|
onLearnMoreClicked()
|
||||||
eventSink.invoke(ChangeServerEvents.ClearError)
|
eventSink.invoke(ChangeServerEvents.ClearError)
|
||||||
}, onDismiss = {
|
},
|
||||||
|
onDismiss = {
|
||||||
eventSink.invoke(ChangeServerEvents.ClearError)
|
eventSink.invoke(ChangeServerEvents.ClearError)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,9 @@ class HomeserverResolver @Inject constructor(
|
||||||
if (data.contains(".")) {
|
if (data.contains(".")) {
|
||||||
// TLD detected?
|
// TLD detected?
|
||||||
} else {
|
} else {
|
||||||
add("${data}.org")
|
add("$data.org")
|
||||||
add("${data}.com")
|
add("$data.com")
|
||||||
add("${data}.io")
|
add("$data.io")
|
||||||
}
|
}
|
||||||
// Always try what the user has entered
|
// Always try what the user has entered
|
||||||
add(data)
|
add(data)
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,9 @@ private fun LoginForm(
|
||||||
Icon(imageVector = CompoundIcons.Close, contentDescription = stringResource(CommonStrings.action_clear))
|
Icon(imageVector = CompoundIcons.Close, contentDescription = stringResource(CommonStrings.action_clear))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else null,
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
var passwordVisible by remember { mutableStateOf(false) }
|
var passwordVisible by remember { mutableStateOf(false) }
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,9 @@ fun SearchAccountProviderView(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else null,
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
supportingText = {
|
supportingText = {
|
||||||
Text(text = stringResource(id = R.string.screen_account_provider_form_notice), color = MaterialTheme.colorScheme.secondary)
|
Text(text = stringResource(id = R.string.screen_account_provider_form_notice), color = MaterialTheme.colorScheme.secondary)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,6 @@ private fun OverallContent(
|
||||||
.padding(bottom = 8.dp),
|
.padding(bottom = 8.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,4 +43,3 @@ class DefaultLogoutEntryPoint @Inject constructor() : LogoutEntryPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.bool.orTrue
|
import io.element.android.libraries.core.bool.orTrue
|
||||||
|
|
|
||||||
|
|
@ -213,4 +213,3 @@ class LogoutPresenterTest {
|
||||||
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
|
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,4 +194,3 @@ class DefaultDirectLogoutPresenterTest {
|
||||||
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
|
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,8 @@ internal fun ExpandableBottomSheetScaffold(
|
||||||
top.place(x = 0, y = 0)
|
top.place(x = 0, y = 0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
content = { sheetContent(false) })
|
content = { sheetContent(false) }
|
||||||
|
)
|
||||||
}, sheetDragHandle, peekHeight)
|
}, sheetDragHandle, peekHeight)
|
||||||
}.map { measurable: Measurable ->
|
}.map { measurable: Measurable ->
|
||||||
measurable.measure(constraints)
|
measurable.measure(constraints)
|
||||||
|
|
@ -161,7 +162,8 @@ internal fun ExpandableBottomSheetScaffold(
|
||||||
layout(constraints.maxWidth, constraints.maxHeight) {
|
layout(constraints.maxWidth, constraints.maxHeight) {
|
||||||
scaffoldPlaceable.place(0, 0)
|
scaffoldPlaceable.place(0, 0)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CustomSheetState.getIntOffset(): Int? = try {
|
private fun CustomSheetState.getIntOffset(): Int? = try {
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@ import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPr
|
||||||
import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories
|
import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.libraries.core.bool.orFalse
|
import io.element.android.libraries.core.bool.orFalse
|
||||||
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||||
|
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.analytics.api.extensions.toAnalyticsViewRoom
|
import io.element.android.services.analytics.api.extensions.toAnalyticsViewRoom
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,8 @@ private fun SheetContent(
|
||||||
item {
|
item {
|
||||||
Column {
|
Column {
|
||||||
MessageSummary(
|
MessageSummary(
|
||||||
event = target.event, modifier = Modifier
|
event = target.event,
|
||||||
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
)
|
)
|
||||||
|
|
@ -299,7 +300,11 @@ private fun EmojiReactionsRow(
|
||||||
) {
|
) {
|
||||||
// TODO use most recently used emojis here when available from the Rust SDK
|
// TODO use most recently used emojis here when available from the Rust SDK
|
||||||
val defaultEmojis = sequenceOf(
|
val defaultEmojis = sequenceOf(
|
||||||
"👍️", "👎️", "🔥", "❤️", "👏"
|
"👍️",
|
||||||
|
"👎️",
|
||||||
|
"🔥",
|
||||||
|
"❤️",
|
||||||
|
"👏"
|
||||||
)
|
)
|
||||||
for (emoji in defaultEmojis) {
|
for (emoji in defaultEmojis) {
|
||||||
val isHighlighted = highlightedEmojis.contains(emoji)
|
val isHighlighted = highlightedEmojis.contains(emoji)
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): AttachmentsPreviewState {
|
override fun present(): AttachmentsPreviewState {
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val sendActionState = remember {
|
val sendActionState = remember {
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,3 @@ sealed interface SendActionState {
|
||||||
data class Failure(val error: Throwable) : SendActionState
|
data class Failure(val error: Throwable) : SendActionState
|
||||||
data object Done : SendActionState
|
data object Done : SendActionState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider<Attachment
|
||||||
|
|
||||||
fun anAttachmentsPreviewState(
|
fun anAttachmentsPreviewState(
|
||||||
mediaInfo: MediaInfo = anImageInfo(),
|
mediaInfo: MediaInfo = anImageInfo(),
|
||||||
sendActionState: SendActionState = SendActionState.Idle) = AttachmentsPreviewState(
|
sendActionState: SendActionState = SendActionState.Idle
|
||||||
|
) = AttachmentsPreviewState(
|
||||||
attachment = Attachment.Media(
|
attachment = Attachment.Media(
|
||||||
localMedia = LocalMedia("file://path".toUri(), mediaInfo),
|
localMedia = LocalMedia("file://path".toUri(), mediaInfo),
|
||||||
compressIfPossible = true
|
compressIfPossible = true
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ fun AttachmentsPreviewView(
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun postSendAttachment() {
|
fun postSendAttachment() {
|
||||||
state.eventSink(AttachmentsPreviewEvents.SendAttachment)
|
state.eventSink(AttachmentsPreviewEvents.SendAttachment)
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +87,6 @@ private fun AttachmentSendStateView(
|
||||||
onDismissClicked: () -> Unit,
|
onDismissClicked: () -> Unit,
|
||||||
onRetryClicked: () -> Unit
|
onRetryClicked: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
when (sendActionState) {
|
when (sendActionState) {
|
||||||
is SendActionState.Sending -> {
|
is SendActionState.Sending -> {
|
||||||
ProgressDialog(
|
ProgressDialog(
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ object MentionSuggestionsProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun memberMatchesQuery(member: RoomMember, query: String): Boolean {
|
fun memberMatchesQuery(member: RoomMember, query: String): Boolean {
|
||||||
return member.userId.value.contains(query, ignoreCase = true)
|
return member.userId.value.contains(query, ignoreCase = true) ||
|
||||||
|| member.displayName?.contains(query, ignoreCase = true) == true
|
member.displayName?.contains(query, ignoreCase = true) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
val matchingMembers = roomMembers
|
val matchingMembers = roomMembers
|
||||||
|
|
|
||||||
|
|
@ -62,12 +62,12 @@ internal fun AttachmentsBottomSheet(
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(state.showAttachmentSourcePicker) {
|
LaunchedEffect(state.showAttachmentSourcePicker) {
|
||||||
if (state.showAttachmentSourcePicker) {
|
isVisible = if (state.showAttachmentSourcePicker) {
|
||||||
// We need to use this instead of `LocalFocusManager.clearFocus()` to hide the keyboard when focus is on an Android View
|
// We need to use this instead of `LocalFocusManager.clearFocus()` to hide the keyboard when focus is on an Android View
|
||||||
localView.hideKeyboard()
|
localView.hideKeyboard()
|
||||||
isVisible = true
|
true
|
||||||
} else {
|
} else {
|
||||||
isVisible = false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Send 'DismissAttachmentMenu' event when the bottomsheet was just hidden
|
// Send 'DismissAttachmentMenu' event when the bottomsheet was just hidden
|
||||||
|
|
@ -122,7 +122,7 @@ private fun AttachmentSourcePickerMenu(
|
||||||
)
|
)
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.PhotoFromCamera) },
|
modifier = Modifier.clickable { state.eventSink(MessageComposerEvents.PickAttachmentSource.PhotoFromCamera) },
|
||||||
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_take_photo_camera, )),
|
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_take_photo_camera)),
|
||||||
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_photo)) },
|
headlineContent = { Text(stringResource(R.string.screen_room_attachment_source_camera_photo)) },
|
||||||
style = ListItemStyle.Primary,
|
style = ListItemStyle.Primary,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -456,4 +456,3 @@ class MessageComposerPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,3 @@ class DefaultRichTextEditorStateFactory @Inject constructor() : RichTextEditorSt
|
||||||
return rememberRichTextEditorState()
|
return rememberRichTextEditorState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,9 @@ internal fun aTimelineItemDebugInfo(
|
||||||
originalJson: String? = null,
|
originalJson: String? = null,
|
||||||
latestEditedJson: String? = null,
|
latestEditedJson: String? = null,
|
||||||
) = TimelineItemDebugInfo(
|
) = TimelineItemDebugInfo(
|
||||||
model, originalJson, latestEditedJson
|
model,
|
||||||
|
originalJson,
|
||||||
|
latestEditedJson
|
||||||
)
|
)
|
||||||
|
|
||||||
internal fun aTimelineItemReadReceipts(): TimelineItemReadReceipts {
|
internal fun aTimelineItemReadReceipts(): TimelineItemReadReceipts {
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,8 @@ fun TimelineView(
|
||||||
timelineItem = timelineItem,
|
timelineItem = timelineItem,
|
||||||
timelineRoomInfo = state.timelineRoomInfo,
|
timelineRoomInfo = state.timelineRoomInfo,
|
||||||
showReadReceipts = state.showReadReceipts,
|
showReadReceipts = state.showReadReceipts,
|
||||||
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true
|
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true &&
|
||||||
&& state.timelineItems.first().identifier() == timelineItem.identifier(),
|
state.timelineItems.first().identifier() == timelineItem.identifier(),
|
||||||
highlightedItem = state.highlightedEventId?.value,
|
highlightedItem = state.highlightedEventId?.value,
|
||||||
onClick = onMessageClicked,
|
onClick = onMessageClicked,
|
||||||
onLongClick = onMessageLongClicked,
|
onLongClick = onMessageLongClicked,
|
||||||
|
|
|
||||||
|
|
@ -165,8 +165,7 @@ private fun ReactionContent(
|
||||||
model = MediaRequestData(MediaSource(reaction.key), MediaRequestData.Kind.Content),
|
model = MediaRequestData(MediaSource(reaction.key), MediaRequestData.Kind.Content),
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Text(
|
Text(
|
||||||
text = reaction.displayKey,
|
text = reaction.displayKey,
|
||||||
style = ElementTheme.typography.fontBodyMdRegular.copy(
|
style = ElementTheme.typography.fontBodyMdRegular.copy(
|
||||||
|
|
@ -225,4 +224,3 @@ internal fun MessagesReactionExtraButtonsPreview() = ElementPreview {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,6 @@ private fun MessageEventBubbleContent(
|
||||||
@Suppress("ModifierNaming")
|
@Suppress("ModifierNaming")
|
||||||
bubbleModifier: Modifier = Modifier, // need to rename this modifier to prevent linter false positives
|
bubbleModifier: Modifier = Modifier, // need to rename this modifier to prevent linter false positives
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Long clicks are not not automatically propagated from a `clickable`
|
// Long clicks are not not automatically propagated from a `clickable`
|
||||||
// to its `combinedClickable` parent so we do it manually
|
// to its `combinedClickable` parent so we do it manually
|
||||||
fun onTimestampLongClick() = onMessageLongClick()
|
fun onTimestampLongClick() = onMessageLongClick()
|
||||||
|
|
@ -578,7 +577,6 @@ private fun MessageEventBubbleContent(
|
||||||
.clip(RoundedCornerShape(6.dp))
|
.clip(RoundedCornerShape(6.dp))
|
||||||
.clickable(enabled = true, onClick = inReplyToClick),
|
.clickable(enabled = true, onClick = inReplyToClick),
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
if (inReplyToDetails != null) {
|
if (inReplyToDetails != null) {
|
||||||
// Use SubComposeLayout only if necessary as it can have consequences on the performance.
|
// Use SubComposeLayout only if necessary as it can have consequences on the performance.
|
||||||
|
|
|
||||||
|
|
@ -59,4 +59,3 @@ internal fun TimelineItemEventRowForDirectRoomPreview() = ElementPreview {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,4 +42,3 @@ internal fun TimelineItemEventRowWithManyReactionsPreview() = ElementPreview {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import io.element.android.features.messages.impl.R
|
import io.element.android.features.messages.impl.R
|
||||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
|
||||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||||
|
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||||
import io.element.android.features.messages.impl.timeline.aGroupedEvents
|
import io.element.android.features.messages.impl.timeline.aGroupedEvents
|
||||||
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
|
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
|
||||||
import io.element.android.features.messages.impl.timeline.components.group.GroupHeaderView
|
import io.element.android.features.messages.impl.timeline.components.group.GroupHeaderView
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ fun TimelineItemReactionsLayout(
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a list of rows place them in the layout.
|
// Given a list of rows place them in the layout.
|
||||||
fun layoutRows(rows: List<List<Placeable>>): MeasureResult {
|
fun layoutRows(rows: List<List<Placeable>>): MeasureResult {
|
||||||
var width = 0
|
var width = 0
|
||||||
var height = 0
|
var height = 0
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,11 @@ private fun TimelineItemReactionsView(
|
||||||
// In LTR languages we want an incoming message's reactions to be LTR and outgoing to be RTL.
|
// In LTR languages we want an incoming message's reactions to be LTR and outgoing to be RTL.
|
||||||
// For RTL languages it should be the opposite.
|
// For RTL languages it should be the opposite.
|
||||||
val currentLayout = LocalLayoutDirection.current
|
val currentLayout = LocalLayoutDirection.current
|
||||||
val reactionsLayoutDirection = if (!isOutgoing) currentLayout
|
val reactionsLayoutDirection = when {
|
||||||
else if (currentLayout == LayoutDirection.Ltr)
|
!isOutgoing -> currentLayout
|
||||||
LayoutDirection.Rtl
|
currentLayout == LayoutDirection.Ltr -> LayoutDirection.Rtl
|
||||||
else
|
else -> LayoutDirection.Ltr
|
||||||
LayoutDirection.Ltr
|
}
|
||||||
|
|
||||||
return CompositionLocalProvider(LocalLayoutDirection provides reactionsLayoutDirection) {
|
return CompositionLocalProvider(LocalLayoutDirection provides reactionsLayoutDirection) {
|
||||||
TimelineItemReactionsLayout(
|
TimelineItemReactionsLayout(
|
||||||
|
|
@ -104,7 +104,9 @@ private fun TimelineItemReactionsView(
|
||||||
onLongClick = {}
|
onLongClick = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else null,
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
reactions = {
|
reactions = {
|
||||||
reactions.forEach { reaction ->
|
reactions.forEach { reaction ->
|
||||||
CompositionLocalProvider(LocalLayoutDirection provides currentLayout) {
|
CompositionLocalProvider(LocalLayoutDirection provides currentLayout) {
|
||||||
|
|
@ -174,4 +176,3 @@ private fun ContentToPreview(
|
||||||
onMoreReactionsClicked = {},
|
onMoreReactionsClicked = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package io.element.android.features.messages.impl.timeline.components
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import io.element.android.features.messages.impl.timeline.session.SessionState
|
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineEncryptedHistoryBannerView
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineEncryptedHistoryBannerView
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemDaySeparatorView
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemDaySeparatorView
|
||||||
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemReadMarkerView
|
import io.element.android.features.messages.impl.timeline.components.virtual.TimelineItemReadMarkerView
|
||||||
|
|
@ -26,6 +25,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemEncryptedHistoryBannerVirtualModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemEncryptedHistoryBannerVirtualModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel
|
||||||
|
import io.element.android.features.messages.impl.timeline.session.SessionState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemVirtualRow(
|
fun TimelineItemVirtualRow(
|
||||||
|
|
@ -39,4 +39,3 @@ fun TimelineItemVirtualRow(
|
||||||
is TimelineItemEncryptedHistoryBannerVirtualModel -> TimelineEncryptedHistoryBannerView(sessionState, modifier)
|
is TimelineItemEncryptedHistoryBannerVirtualModel -> TimelineEncryptedHistoryBannerView(sessionState, modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ 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
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import io.element.android.libraries.architecture.Presenter
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import kotlinx.collections.immutable.toImmutableSet
|
import kotlinx.collections.immutable.toImmutableSet
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class CustomReactionPresenter @Inject constructor(
|
class CustomReactionPresenter @Inject constructor(
|
||||||
|
|
@ -59,7 +59,12 @@ class CustomReactionPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val event = (target.value as? CustomReactionState.Target.Success)?.event
|
val event = (target.value as? CustomReactionState.Target.Success)?.event
|
||||||
val selectedEmoji = event?.reactionsState?.reactions?.mapNotNull { if(it.isHighlighted) it.key else null }.orEmpty().toImmutableSet()
|
val selectedEmoji = event
|
||||||
|
?.reactionsState
|
||||||
|
?.reactions
|
||||||
|
?.mapNotNull { if (it.isHighlighted) it.key else null }
|
||||||
|
.orEmpty()
|
||||||
|
.toImmutableSet()
|
||||||
return CustomReactionState(
|
return CustomReactionState(
|
||||||
target = target.value,
|
target = target.value,
|
||||||
selectedEmoji = selectedEmoji,
|
selectedEmoji = selectedEmoji,
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,3 @@ data class CustomReactionState(
|
||||||
) : Target
|
) : Target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,5 +25,4 @@ class DefaultEmojibaseProvider(val context: Context): EmojibaseProvider {
|
||||||
override val emojibaseStore: EmojibaseStore by lazy {
|
override val emojibaseStore: EmojibaseStore by lazy {
|
||||||
EmojibaseDatasource().load(context)
|
EmojibaseDatasource().load(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.features.location.api.StaticMapView
|
import io.element.android.features.location.api.StaticMapView
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContentProvider
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContentProvider
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -62,4 +62,3 @@ internal fun TimelineItemLocationViewPreview(@PreviewParameter(TimelineItemLocat
|
||||||
ElementPreview {
|
ElementPreview {
|
||||||
TimelineItemLocationView(content)
|
TimelineItemLocationView(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemStateView(
|
fun TimelineItemStateView(
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ fun TimelineItemTextView(
|
||||||
LocalContentColor provides ElementTheme.colors.textPrimary,
|
LocalContentColor provides ElementTheme.colors.textPrimary,
|
||||||
LocalTextStyle provides ElementTheme.typography.fontBodyLgRegular
|
LocalTextStyle provides ElementTheme.typography.fontBodyLgRegular
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val formattedBody = content.formattedBody
|
val formattedBody = content.formattedBody
|
||||||
val body = SpannableString(formattedBody ?: content.body)
|
val body = SpannableString(formattedBody ?: content.body)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContentProvider
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContentProvider
|
||||||
import io.element.android.libraries.designsystem.components.BlurHashAsyncImage
|
import io.element.android.libraries.designsystem.components.BlurHashAsyncImage
|
||||||
import io.element.android.libraries.designsystem.modifiers.roundedBackground
|
import io.element.android.libraries.designsystem.modifiers.roundedBackground
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,5 +78,4 @@ class ReactionSummaryPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,4 +29,3 @@ data class ReactionSummaryState(
|
||||||
val selectedEventId: EventId
|
val selectedEventId: EventId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,6 @@ private fun AggregatedReactionButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val buttonColor = if (isHighlighted) {
|
val buttonColor = if (isHighlighted) {
|
||||||
ElementTheme.colors.bgActionPrimaryRest
|
ElementTheme.colors.bgActionPrimaryRest
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -209,8 +208,7 @@ private fun AggregatedReactionButton(
|
||||||
model = MediaRequestData(MediaSource(reaction.key), MediaRequestData.Kind.Content),
|
model = MediaRequestData(MediaSource(reaction.key), MediaRequestData.Kind.Content),
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Text(
|
Text(
|
||||||
text = reaction.displayKey,
|
text = reaction.displayKey,
|
||||||
style = ElementTheme.typography.fontBodyMdRegular.copy(
|
style = ElementTheme.typography.fontBodyMdRegular.copy(
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import io.element.android.appconfig.TimelineConfig
|
import io.element.android.appconfig.TimelineConfig
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
|
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
|
|
@ -50,7 +51,6 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
import io.element.android.libraries.ui.strings.CommonPlurals
|
import io.element.android.libraries.ui.strings.CommonPlurals
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
@ -76,7 +76,8 @@ fun TimelineItemReadReceiptView(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else when (state.sendState) {
|
} else {
|
||||||
|
when (state.sendState) {
|
||||||
LocalEventSendState.NotSentYet -> {
|
LocalEventSendState.NotSentYet -> {
|
||||||
ReadReceiptsRow(modifier) {
|
ReadReceiptsRow(modifier) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
@ -106,6 +107,7 @@ fun TimelineItemReadReceiptView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ReadReceiptsRow(
|
private fun ReadReceiptsRow(
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ReadReceiptBottomSheetPresenter @Inject constructor(
|
class ReadReceiptBottomSheetPresenter @Inject constructor() : Presenter<ReadReceiptBottomSheetState> {
|
||||||
) : Presenter<ReadReceiptBottomSheetState> {
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): ReadReceiptBottomSheetState {
|
override fun present(): ReadReceiptBottomSheetState {
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,12 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.messages.impl.R
|
import io.element.android.features.messages.impl.R
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet
|
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModelProvider
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModelProvider
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.compound.theme.ElementTheme
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TimelineItemDaySeparatorView(
|
internal fun TimelineItemDaySeparatorView(
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue