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:
@@ -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_standard_wrapping = disabled
|
||||
ktlint_standard_trailing-comma-on-call-site = disabled
|
||||
|
||||
ktlint_standard_spacing-between-declarations-with-annotations = disabled
|
||||
|
||||
[*.java]
|
||||
ij_java_align_consecutive_assignments = false
|
||||
|
||||
@@ -68,5 +68,4 @@ class MainNode(
|
||||
|
||||
@Parcelize
|
||||
object RootNavTarget : Parcelable
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ interface AppComponent : NodeFactoriesBindings {
|
||||
|
||||
@Component.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
|
||||
accept(Remove(lastExpectedNavElement.key))
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||
},
|
||||
onStop = {
|
||||
coroutineScope.launch {
|
||||
//Counterpart startSync is done in observeSyncStateAndNetworkStatus method.
|
||||
// Counterpart startSync is done in observeSyncStateAndNetworkStatus method.
|
||||
syncService.stopSync()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -268,10 +268,9 @@ class RootFlowNode @AssistedInject constructor(
|
||||
}
|
||||
|
||||
private suspend fun attachSession(sessionId: SessionId): LoggedInAppScopeFlowNode {
|
||||
//TODO handle multi-session
|
||||
// TODO handle multi-session
|
||||
return waitForChildAttached { navTarget ->
|
||||
navTarget is NavTarget.LoggedInFlow && navTarget.sessionId == sessionId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,8 +65,9 @@ class MatrixClientsHolder @Inject constructor(private val authenticationService:
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun restoreWithSavedState(state: SavedStateMap?) {
|
||||
Timber.d("Restore state")
|
||||
if (state == null || sessionIdsToMatrixClient.isNotEmpty()) return Unit.also {
|
||||
if (state == null || sessionIdsToMatrixClient.isNotEmpty()) {
|
||||
Timber.w("Restore with non-empty map")
|
||||
return
|
||||
}
|
||||
val sessionIds = state[SAVE_INSTANCE_KEY] as? Array<SessionId>
|
||||
Timber.d("Restore matrix session keys = ${sessionIds?.map { it.value }}")
|
||||
|
||||
@@ -59,15 +59,15 @@ fun SyncStateView(
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(color = ElementTheme.colors.bgSubtleSecondary)
|
||||
.padding(horizontal = 24.dp, vertical = 10.dp),
|
||||
.background(color = ElementTheme.colors.bgSubtleSecondary)
|
||||
.padding(horizontal = 24.dp, vertical = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.progressSemantics()
|
||||
.size(12.dp),
|
||||
.progressSemantics()
|
||||
.size(12.dp),
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
strokeWidth = 1.5.dp,
|
||||
)
|
||||
|
||||
@@ -136,4 +136,3 @@ class RoomFlowNode @AssistedInject constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,22 +31,22 @@ class LoadingRoomStateFlowFactoryTest {
|
||||
|
||||
@Test
|
||||
fun `flow should emit Loading and then Loaded when there is a room in cache`() = runTest {
|
||||
val room = FakeMatrixRoom(sessionId= A_SESSION_ID, roomId = A_ROOM_ID)
|
||||
val room = FakeMatrixRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID)
|
||||
val matrixClient = FakeMatrixClient(A_SESSION_ID).apply {
|
||||
givenGetRoomResult(A_ROOM_ID, room)
|
||||
}
|
||||
val flowFactory = LoadingRoomStateFlowFactory(matrixClient)
|
||||
flowFactory
|
||||
.create(this, A_ROOM_ID)
|
||||
.test {
|
||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
|
||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
|
||||
}
|
||||
.test {
|
||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
|
||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `flow should emit Loading and then Loaded when there is a room in cache after SS is loaded`() = runTest {
|
||||
val room = FakeMatrixRoom(sessionId= A_SESSION_ID, roomId = A_ROOM_ID)
|
||||
val room = FakeMatrixRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID)
|
||||
val roomListService = FakeRoomListService()
|
||||
val matrixClient = FakeMatrixClient(A_SESSION_ID, roomListService = roomListService)
|
||||
val flowFactory = LoadingRoomStateFlowFactory(matrixClient)
|
||||
|
||||
@@ -216,13 +216,15 @@ subprojects {
|
||||
if (project.findProperty("composeCompilerReports") == "true") {
|
||||
freeCompilerArgs += listOf(
|
||||
"-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") {
|
||||
freeCompilerArgs += listOf(
|
||||
"-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.libraries.designsystem.components.LINK_TAG
|
||||
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.PreviewsDayNight
|
||||
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.ListSupportingText
|
||||
|
||||
@@ -19,8 +19,7 @@ package io.element.android.features.analytics.impl
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
open class AnalyticsOptInStateProvider @Inject constructor(
|
||||
) : PreviewParameterProvider<AnalyticsOptInState> {
|
||||
open class AnalyticsOptInStateProvider @Inject constructor() : PreviewParameterProvider<AnalyticsOptInState> {
|
||||
override val values: Sequence<AnalyticsOptInState>
|
||||
get() = sequenceOf(
|
||||
aAnalyticsOptInState(),
|
||||
|
||||
@@ -70,4 +70,3 @@ class AnalyticsOptInPresenterTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,4 +82,3 @@ class AnalyticsPreferencesPresenterTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ data class WidgetMessage(
|
||||
enum class Direction {
|
||||
@SerialName("fromWidget")
|
||||
FromWidget,
|
||||
|
||||
@SerialName("toWidget")
|
||||
ToWidget
|
||||
}
|
||||
@@ -41,6 +42,7 @@ data class WidgetMessage(
|
||||
enum class Action {
|
||||
@SerialName("im.vector.hangup")
|
||||
HangUp,
|
||||
|
||||
@SerialName("send_event")
|
||||
SendEvent,
|
||||
}
|
||||
|
||||
@@ -224,6 +224,4 @@ class CallScreenPresenter @AssistedInject constructor(
|
||||
navigator.close()
|
||||
widgetDriver?.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class WebViewWidgetMessageInterceptor(
|
||||
|| !message.data.response && message.data.api == "fromWidget") {
|
||||
let json = JSON.stringify(event.data)
|
||||
${"console.log('message sent: ' + json);".takeIf { BuildConfig.DEBUG } }
|
||||
${LISTENER_NAME}.postMessage(json);
|
||||
$LISTENER_NAME.postMessage(json);
|
||||
} else {
|
||||
${"console.log('message received (ignored): ' + JSON.stringify(event.data));".takeIf { BuildConfig.DEBUG } }
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class CallScreenPresenterTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
consumeItemsUntilTimeout()
|
||||
consumeItemsUntilTimeout()
|
||||
|
||||
assertThat(matrixClient.syncService().syncState.value).isEqualTo(SyncState.Running)
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package io.element.android.features.call.ui
|
||||
|
||||
class FakeCallScreenNavigator : CallScreenNavigator {
|
||||
var closeCalled = false
|
||||
private set
|
||||
var closeCalled = false
|
||||
private set
|
||||
|
||||
override fun close() {
|
||||
closeCalled = true
|
||||
}
|
||||
override fun close() {
|
||||
closeCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url extra param appPrompt gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url extra param in fragment appPrompt gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url extra param in fragment appPrompt and other gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -141,7 +141,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url extra param confineToRoom gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -149,7 +149,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url extra param in fragment confineToRoom gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -157,7 +157,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url extra param in fragment confineToRoom and more gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -165,7 +165,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url fragment gets url extracted`() {
|
||||
doTest(
|
||||
url = "${VALID_CALL_URL_WITH_PARAM}#fragment",
|
||||
url = "$VALID_CALL_URL_WITH_PARAM#fragment",
|
||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?$EXTRA_PARAMS"
|
||||
)
|
||||
}
|
||||
@@ -173,7 +173,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url fragment with params gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -181,7 +181,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with url fragment with other params gets url extracted`() {
|
||||
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"
|
||||
)
|
||||
}
|
||||
@@ -189,7 +189,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with empty fragment`() {
|
||||
doTest(
|
||||
url = "${VALID_CALL_URL_WITH_PARAM}#",
|
||||
url = "$VALID_CALL_URL_WITH_PARAM#",
|
||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
||||
)
|
||||
}
|
||||
@@ -197,7 +197,7 @@ class CallIntentDataParserTest {
|
||||
@Test
|
||||
fun `Element Call url with empty fragment query`() {
|
||||
doTest(
|
||||
url = "${VALID_CALL_URL_WITH_PARAM}#?",
|
||||
url = "$VALID_CALL_URL_WITH_PARAM#?",
|
||||
expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,19 +24,19 @@ import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver
|
||||
class FakeCallWidgetProvider(
|
||||
private val widgetDriver: FakeWidgetDriver = FakeWidgetDriver(),
|
||||
private val url: String = "https://call.element.io",
|
||||
) : CallWidgetProvider {
|
||||
) : CallWidgetProvider {
|
||||
|
||||
var getWidgetCalled = false
|
||||
private set
|
||||
var getWidgetCalled = false
|
||||
private set
|
||||
|
||||
override suspend fun getWidget(
|
||||
sessionId: SessionId,
|
||||
roomId: RoomId,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?
|
||||
): Result<Pair<MatrixWidgetDriver, String>> {
|
||||
getWidgetCalled = true
|
||||
return Result.success(widgetDriver to url)
|
||||
}
|
||||
override suspend fun getWidget(
|
||||
sessionId: SessionId,
|
||||
roomId: RoomId,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?
|
||||
): Result<Pair<MatrixWidgetDriver, String>> {
|
||||
getWidgetCalled = true
|
||||
return Result.success(widgetDriver to url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,15 +19,15 @@ package io.element.android.features.call.utils
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
class FakeWidgetMessageInterceptor : WidgetMessageInterceptor {
|
||||
val sentMessages = mutableListOf<String>()
|
||||
val sentMessages = mutableListOf<String>()
|
||||
|
||||
override val interceptedMessages = MutableSharedFlow<String>(extraBufferCapacity = 1)
|
||||
override val interceptedMessages = MutableSharedFlow<String>(extraBufferCapacity = 1)
|
||||
|
||||
override fun sendMessage(message: String) {
|
||||
sentMessages += message
|
||||
}
|
||||
|
||||
fun givenInterceptedMessage(message: String) {
|
||||
interceptedMessages.tryEmit(message)
|
||||
}
|
||||
override fun sendMessage(message: String) {
|
||||
sentMessages += message
|
||||
}
|
||||
|
||||
fun givenInterceptedMessage(message: String) {
|
||||
interceptedMessages.tryEmit(message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import javax.inject.Inject
|
||||
class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint {
|
||||
|
||||
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder {
|
||||
|
||||
val plugins = ArrayList<Plugin>()
|
||||
|
||||
return object : CreateRoomEntryPoint.NodeBuilder {
|
||||
|
||||
@@ -45,4 +45,3 @@ class AddPeoplePresenter @Inject constructor(
|
||||
return userListPresenter.present()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,13 @@ open class AddPeopleUserListStateProvider : PreviewParameterProvider<UserListSta
|
||||
selectionMode = SelectionMode.Multiple,
|
||||
),
|
||||
aUserListState().copy(
|
||||
searchResults = SearchBarResultState.Results(aMatrixUserList()
|
||||
.mapIndexed { index, matrixUser ->
|
||||
UserSearchResult(matrixUser, index % 2 == 0)
|
||||
}
|
||||
.toImmutableList()),
|
||||
searchResults = SearchBarResultState.Results(
|
||||
aMatrixUserList()
|
||||
.mapIndexed { index, matrixUser ->
|
||||
UserSearchResult(matrixUser, index % 2 == 0)
|
||||
}
|
||||
.toImmutableList()
|
||||
),
|
||||
selectedUsers = aListOfSelectedUsers(),
|
||||
isSearchActive = true,
|
||||
selectionMode = SelectionMode.Multiple,
|
||||
|
||||
@@ -29,14 +29,14 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.semantics.Role
|
||||
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.roomPrivacyItems
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
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.RadioButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
||||
@Composable
|
||||
fun RoomPrivacyOption(
|
||||
|
||||
@@ -19,8 +19,8 @@ package io.element.android.features.createroom.impl.configureroom
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Composable
|
||||
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.libraries.designsystem.icons.CompoundDrawables
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
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 io.element.android.features.createroom.impl.userlist.aUserListState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||
import io.element.android.libraries.usersearch.api.UserSearchResult
|
||||
|
||||
@@ -106,7 +106,7 @@ fun CreateRoomRootView(
|
||||
onRetry = {
|
||||
state.userListState.selectedUsers.firstOrNull()
|
||||
?.let { state.eventSink(CreateRoomRootEvents.StartDM(it)) }
|
||||
// Cancel start DM if there is no more selected user (should not happen)
|
||||
// Cancel start DM if there is no more selected user (should not happen)
|
||||
?: state.eventSink(CreateRoomRootEvents.CancelStartDM)
|
||||
},
|
||||
onErrorDismiss = { state.eventSink(CreateRoomRootEvents.CancelStartDM) },
|
||||
|
||||
@@ -57,4 +57,3 @@ class AddPeoplePresenterTests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,4 +316,3 @@ class ConfigureRoomPresenterTests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ class CreateRoomRootPresenterTests {
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.startDmAction).isEqualTo(startDMSuccessResult)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,5 +50,6 @@ fun MigrationScreenView(
|
||||
internal fun MigrationViewPreview() = ElementPreview {
|
||||
MigrationScreenView(
|
||||
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_"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ class NotificationsOptInPresenter @AssistedInject constructor(
|
||||
}
|
||||
|
||||
LaunchedEffect(notificationsPermissionsState) {
|
||||
if (notificationsPermissionsState.permissionGranted
|
||||
|| notificationsPermissionsState.permissionAlreadyDenied) {
|
||||
if (notificationsPermissionsState.permissionGranted ||
|
||||
notificationsPermissionsState.permissionAlreadyDenied) {
|
||||
callback.onNotificationsOptInFinished()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import javax.inject.Inject
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultFtueState @Inject constructor(
|
||||
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
coroutineScope: CoroutineScope,
|
||||
private val analyticsService: AnalyticsService,
|
||||
private val welcomeScreenState: WelcomeScreenState,
|
||||
private val migrationScreenStore: MigrationScreenStore,
|
||||
@@ -68,21 +68,31 @@ class DefaultFtueState @Inject constructor(
|
||||
|
||||
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
|
||||
when (currentStep) {
|
||||
null -> if (shouldDisplayMigrationScreen()) FtueStep.MigrationScreen else getNextStep(
|
||||
null -> if (shouldDisplayMigrationScreen()) {
|
||||
FtueStep.MigrationScreen
|
||||
)
|
||||
FtueStep.MigrationScreen -> if (shouldDisplayWelcomeScreen()) FtueStep.WelcomeScreen else getNextStep(
|
||||
} else {
|
||||
getNextStep(FtueStep.MigrationScreen)
|
||||
}
|
||||
FtueStep.MigrationScreen -> if (shouldDisplayWelcomeScreen()) {
|
||||
FtueStep.WelcomeScreen
|
||||
)
|
||||
FtueStep.WelcomeScreen -> if (shouldAskNotificationPermissions()) FtueStep.NotificationsOptIn else getNextStep(
|
||||
} else {
|
||||
getNextStep(FtueStep.WelcomeScreen)
|
||||
}
|
||||
FtueStep.WelcomeScreen -> if (shouldAskNotificationPermissions()) {
|
||||
FtueStep.NotificationsOptIn
|
||||
)
|
||||
FtueStep.NotificationsOptIn -> if (shouldDisplayLockscreenSetup()) FtueStep.LockscreenSetup else getNextStep(
|
||||
} else {
|
||||
getNextStep(FtueStep.NotificationsOptIn)
|
||||
}
|
||||
FtueStep.NotificationsOptIn -> if (shouldDisplayLockscreenSetup()) {
|
||||
FtueStep.LockscreenSetup
|
||||
)
|
||||
FtueStep.LockscreenSetup -> if (needsAnalyticsOptIn()) FtueStep.AnalyticsOptIn else getNextStep(
|
||||
} else {
|
||||
getNextStep(FtueStep.LockscreenSetup)
|
||||
}
|
||||
FtueStep.LockscreenSetup -> if (needsAnalyticsOptIn()) {
|
||||
FtueStep.AnalyticsOptIn
|
||||
)
|
||||
} else {
|
||||
getNextStep(FtueStep.AnalyticsOptIn)
|
||||
}
|
||||
FtueStep.AnalyticsOptIn -> null
|
||||
}
|
||||
|
||||
@@ -115,7 +125,9 @@ class DefaultFtueState @Inject constructor(
|
||||
val isPermissionDenied = runBlocking { permissionStateProvider.isPermissionDenied(permission).first() }
|
||||
val isPermissionGranted = permissionStateProvider.isPermissionGranted(permission)
|
||||
!isPermissionGranted && !isPermissionDenied
|
||||
} else false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldDisplayLockscreenSetup(): Boolean {
|
||||
|
||||
@@ -50,5 +50,4 @@ class WelcomeNode @AssistedInject constructor(
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,4 +37,3 @@ interface InviteListEntryPoint : FeatureEntryPoint {
|
||||
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 seenInvitesKey = stringSetPreferencesKey("seenInvites")
|
||||
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultSeenInvitesStore @Inject constructor(
|
||||
@ApplicationContext context: Context
|
||||
@@ -55,5 +54,4 @@ class DefaultSeenInvitesStore @Inject constructor(
|
||||
prefs[seenInvitesKey] = roomIds.map { it.value }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ sealed interface InviteListEvents {
|
||||
data class AcceptInvite(val invite: InviteListInviteSummary) : InviteListEvents
|
||||
data class DeclineInvite(val invite: InviteListInviteSummary) : InviteListEvents
|
||||
|
||||
data object ConfirmDeclineInvite: InviteListEvents
|
||||
data object CancelDeclineInvite: InviteListEvents
|
||||
data object ConfirmDeclineInvite : InviteListEvents
|
||||
data object CancelDeclineInvite : InviteListEvents
|
||||
|
||||
data object DismissAcceptError: InviteListEvents
|
||||
data object DismissDeclineError: InviteListEvents
|
||||
data object DismissAcceptError : InviteListEvents
|
||||
data object DismissDeclineError : InviteListEvents
|
||||
}
|
||||
|
||||
@@ -159,25 +159,27 @@ class InviteListPresenter @Inject constructor(
|
||||
|
||||
private fun RoomSummary.Filled.toInviteSummary(seen: Boolean) = details.run {
|
||||
val i = inviter
|
||||
val avatarData = if (isDirect && i != null)
|
||||
val avatarData = if (isDirect && i != null) {
|
||||
AvatarData(
|
||||
id = i.userId.value,
|
||||
name = i.displayName,
|
||||
url = i.avatarUrl,
|
||||
size = AvatarSize.RoomInviteItem,
|
||||
)
|
||||
else
|
||||
} else {
|
||||
AvatarData(
|
||||
id = roomId.value,
|
||||
name = name,
|
||||
url = avatarURLString,
|
||||
size = AvatarSize.RoomInviteItem,
|
||||
)
|
||||
}
|
||||
|
||||
val alias = if (isDirect)
|
||||
val alias = if (isDirect) {
|
||||
inviter?.userId?.value
|
||||
else
|
||||
} else {
|
||||
canonicalAlias
|
||||
}
|
||||
|
||||
InviteListInviteSummary(
|
||||
roomId = roomId,
|
||||
@@ -186,18 +188,20 @@ class InviteListPresenter @Inject constructor(
|
||||
roomAvatarData = avatarData,
|
||||
isDirect = isDirect,
|
||||
isNew = !seen,
|
||||
sender = if (isDirect) null else inviter?.run {
|
||||
InviteSender(
|
||||
userId = userId,
|
||||
displayName = displayName ?: "",
|
||||
avatarData = AvatarData(
|
||||
id = userId.value,
|
||||
name = displayName,
|
||||
url = avatarUrl,
|
||||
size = AvatarSize.InviteSender,
|
||||
),
|
||||
)
|
||||
},
|
||||
sender = inviter
|
||||
?.takeIf { !isDirect }
|
||||
?.run {
|
||||
InviteSender(
|
||||
userId = userId,
|
||||
displayName = displayName ?: "",
|
||||
avatarData = AvatarData(
|
||||
id = userId.value,
|
||||
name = displayName,
|
||||
url = avatarUrl,
|
||||
size = AvatarSize.InviteSender,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,15 +69,17 @@ fun InviteListView(
|
||||
)
|
||||
|
||||
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
|
||||
else
|
||||
} else {
|
||||
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
|
||||
else
|
||||
} else {
|
||||
R.string.screen_invites_decline_chat_title
|
||||
}
|
||||
|
||||
ConfirmationDialog(
|
||||
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.tooling.preview.PreviewParameter
|
||||
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.model.InviteListInviteSummary
|
||||
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.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
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.dialogs.ConfirmationDialog
|
||||
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.PreviewsDayNight
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ internal class MapTilerStaticMapUrlBuilder(
|
||||
// image smaller than the available space in pixels.
|
||||
// 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.
|
||||
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 {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ internal class LocationKtTest {
|
||||
|
||||
@Test
|
||||
fun `encode geoUri - returns geoUri from a Location`() {
|
||||
assertThat(Location(1.0,2.0,3.0f).toGeoUri())
|
||||
assertThat(Location(1.0, 2.0, 3.0f).toGeoUri())
|
||||
.isEqualTo("geo:1.0,2.0;u=3.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import javax.inject.Inject
|
||||
@ContributesBinding(AppScope::class)
|
||||
class SendLocationEntryPointImpl @Inject constructor() : SendLocationEntryPoint {
|
||||
override fun createNode(
|
||||
parentNode: Node, buildContext: BuildContext
|
||||
parentNode: Node,
|
||||
buildContext: BuildContext
|
||||
): SendLocationNode = parentNode.createNode(buildContext)
|
||||
}
|
||||
|
||||
@@ -55,8 +55,11 @@ class SendLocationPresenter @Inject constructor(
|
||||
val permissionsState: PermissionsState = permissionsPresenter.present()
|
||||
var mode: SendLocationState.Mode by remember {
|
||||
mutableStateOf(
|
||||
if (permissionsState.isAnyGranted) SendLocationState.Mode.SenderLocation
|
||||
else SendLocationState.Mode.PinLocation
|
||||
if (permissionsState.isAnyGranted) {
|
||||
SendLocationState.Mode.SenderLocation
|
||||
} else {
|
||||
SendLocationState.Mode.PinLocation
|
||||
}
|
||||
)
|
||||
}
|
||||
val appName by remember { derivedStateOf { buildMeta.applicationName } }
|
||||
|
||||
@@ -75,7 +75,6 @@ class SendLocationPresenterTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
sendLocationPresenter.present()
|
||||
}.test {
|
||||
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||
@@ -102,7 +101,6 @@ class SendLocationPresenterTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
sendLocationPresenter.present()
|
||||
}.test {
|
||||
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||
@@ -381,7 +379,9 @@ class SendLocationPresenterTest {
|
||||
)
|
||||
fakeMessageComposerContext.apply {
|
||||
composerMode = MessageComposerMode.Edit(
|
||||
eventId = null, defaultContent = "", transactionId = null
|
||||
eventId = null,
|
||||
defaultContent = "",
|
||||
transactionId = null
|
||||
)
|
||||
}
|
||||
|
||||
@@ -427,7 +427,9 @@ class SendLocationPresenterTest {
|
||||
)
|
||||
fakeMessageComposerContext.apply {
|
||||
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 {
|
||||
|
||||
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): LockScreenEntryPoint.NodeBuilder {
|
||||
|
||||
var innerTarget: LockScreenEntryPoint.Target = LockScreenEntryPoint.Target.Unlock
|
||||
val callbacks = mutableListOf<LockScreenEntryPoint.Callback>()
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class DefaultLockScreenService @Inject constructor(
|
||||
override suspend fun onSessionCreated(userId: String) = Unit
|
||||
|
||||
override suspend fun onSessionDeleted(userId: String) {
|
||||
//TODO handle multi session at some point
|
||||
// TODO handle multi session at some point
|
||||
pinCodeManager.deletePinCode()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
private val canUseWeakBiometricAuth: Boolean
|
||||
get() = lockScreenConfig.isWeakBiometricsEnabled
|
||||
&& biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS
|
||||
get() = lockScreenConfig.isWeakBiometricsEnabled &&
|
||||
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.
|
||||
*/
|
||||
private val canUseStrongBiometricAuth: Boolean
|
||||
get() = lockScreenConfig.isStrongBiometricsEnabled
|
||||
&& biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
||||
get() = lockScreenConfig.isStrongBiometricsEnabled &&
|
||||
biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
||||
|
||||
/**
|
||||
* 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.text.input.KeyboardType
|
||||
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.PinEntry
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.pinDigitBg
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
||||
@Composable
|
||||
fun PinEntryTextField(
|
||||
@@ -100,7 +100,7 @@ private fun PinDigitView(
|
||||
.then(appearanceModifier),
|
||||
contentAlignment = Alignment.Center,
|
||||
|
||||
) {
|
||||
) {
|
||||
if (digit is PinDigit.Filled) {
|
||||
val text = if (isSecured) {
|
||||
"•"
|
||||
@@ -112,7 +112,6 @@ private fun PinDigitView(
|
||||
style = ElementTheme.typography.fontHeadingMdBold
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,6 @@ class LockScreenSettingsFlowNode @AssistedInject constructor(
|
||||
createNode<LockScreenSettingsNode>(buildContext, plugins = listOf(callback))
|
||||
}
|
||||
NavTarget.Unknown -> node(buildContext) { }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
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.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
||||
@Composable
|
||||
fun LockScreenSettingsView(
|
||||
@@ -79,7 +79,8 @@ fun LockScreenSettingsView(
|
||||
},
|
||||
onDismiss = {
|
||||
state.eventSink(LockScreenSettingsEvents.CancelRemovePin)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ class SetupBiometricPresenter @Inject constructor(
|
||||
|
||||
@Composable
|
||||
override fun present(): SetupBiometricState {
|
||||
|
||||
var isBiometricSetupDone by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
@@ -97,4 +97,3 @@ internal fun SetupBiometricViewPreview(@PreviewParameter(SetupBiometricStateProv
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,4 +58,3 @@ fun aSetupPinState(
|
||||
appName = "Element",
|
||||
eventSink = {}
|
||||
)
|
||||
|
||||
|
||||
@@ -42,5 +42,4 @@ interface EncryptedPinCodeStorage {
|
||||
* Returns whether the PIN code is stored or not.
|
||||
*/
|
||||
fun hasPinCode(): Flow<Boolean>
|
||||
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ data class PinUnlockState(
|
||||
}
|
||||
|
||||
val biometricUnlockErrorMessage = when {
|
||||
biometricUnlockResult is BiometricUnlock.AuthenticationResult.Failure
|
||||
&& biometricUnlockResult.error is BiometricUnlockError
|
||||
&& biometricUnlockResult.error.isAuthDisabledError -> {
|
||||
biometricUnlockResult is BiometricUnlock.AuthenticationResult.Failure &&
|
||||
biometricUnlockResult.error is BiometricUnlockError &&
|
||||
biometricUnlockResult.error.isAuthDisabledError -> {
|
||||
biometricUnlockResult.error.message
|
||||
}
|
||||
else -> null
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package io.element.android.features.lockscreen.impl.unlock
|
||||
|
||||
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.unit.dp
|
||||
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.components.PinEntryTextField
|
||||
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.TextButton
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@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.sp
|
||||
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.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.text.toSp
|
||||
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.persistentListOf
|
||||
|
||||
@@ -210,5 +210,3 @@ internal fun PinKeypadPreview() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class SetupPinPresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun SetupPinState.onPinEntryChanged(pinEntry: String){
|
||||
private fun SetupPinState.onPinEntryChanged(pinEntry: String) {
|
||||
eventSink(SetupPinEvents.OnPinEntryChanged(pinEntry, isConfirmationStep))
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
class AccountProviderDataSource @Inject constructor(
|
||||
) {
|
||||
class AccountProviderDataSource @Inject constructor() {
|
||||
private val accountProvider: MutableStateFlow<AccountProvider> = MutableStateFlow(
|
||||
defaultAccountProvider
|
||||
)
|
||||
|
||||
@@ -50,9 +50,11 @@ fun AccountProviderView(
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick() }
|
||||
) {
|
||||
HorizontalDivider()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -54,9 +54,11 @@ fun ChangeServerView(
|
||||
onLearnMoreClicked = {
|
||||
onLearnMoreClicked()
|
||||
eventSink.invoke(ChangeServerEvents.ClearError)
|
||||
}, onDismiss = {
|
||||
eventSink.invoke(ChangeServerEvents.ClearError)
|
||||
})
|
||||
},
|
||||
onDismiss = {
|
||||
eventSink.invoke(ChangeServerEvents.ClearError)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@ import io.element.android.features.login.api.oidc.OidcAction
|
||||
|
||||
sealed interface OidcEvents {
|
||||
data object Cancel : OidcEvents
|
||||
data class OidcActionEvent(val oidcAction: OidcAction): OidcEvents
|
||||
data class OidcActionEvent(val oidcAction: OidcAction) : OidcEvents
|
||||
data object ClearError : OidcEvents
|
||||
}
|
||||
|
||||
@@ -90,9 +90,9 @@ class HomeserverResolver @Inject constructor(
|
||||
if (data.contains(".")) {
|
||||
// TLD detected?
|
||||
} else {
|
||||
add("${data}.org")
|
||||
add("${data}.com")
|
||||
add("${data}.io")
|
||||
add("$data.org")
|
||||
add("$data.com")
|
||||
add("$data.io")
|
||||
}
|
||||
// Always try what the user has entered
|
||||
add(data)
|
||||
|
||||
@@ -30,6 +30,6 @@ import kotlinx.serialization.Serializable
|
||||
*/
|
||||
@Serializable
|
||||
data class WellKnownBaseConfig(
|
||||
@SerialName("base_url")
|
||||
val baseURL: String? = null
|
||||
@SerialName("base_url")
|
||||
val baseURL: String? = null
|
||||
)
|
||||
|
||||
@@ -21,6 +21,6 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class WellKnownSlidingSyncConfig(
|
||||
@SerialName("url")
|
||||
val url: String? = null,
|
||||
@SerialName("url")
|
||||
val url: String? = null,
|
||||
)
|
||||
|
||||
@@ -220,7 +220,9 @@ private fun LoginForm(
|
||||
Icon(imageVector = CompoundIcons.Close, contentDescription = stringResource(CommonStrings.action_clear))
|
||||
}
|
||||
}
|
||||
} else null,
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
|
||||
var passwordVisible by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -144,7 +144,9 @@ fun SearchAccountProviderView(
|
||||
)
|
||||
}
|
||||
}
|
||||
} else null,
|
||||
} else {
|
||||
null
|
||||
},
|
||||
supportingText = {
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.rememberCoroutineScope
|
||||
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.AsyncData
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.core.bool.orTrue
|
||||
|
||||
@@ -213,4 +213,3 @@ class LogoutPresenterTest {
|
||||
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -194,4 +194,3 @@ class DefaultDirectLogoutPresenterTest {
|
||||
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,8 @@ internal fun ExpandableBottomSheetScaffold(
|
||||
top.place(x = 0, y = 0)
|
||||
}
|
||||
},
|
||||
content = { sheetContent(false) })
|
||||
content = { sheetContent(false) }
|
||||
)
|
||||
}, sheetDragHandle, peekHeight)
|
||||
}.map { measurable: Measurable ->
|
||||
measurable.measure(constraints)
|
||||
@@ -161,7 +162,8 @@ internal fun ExpandableBottomSheetScaffold(
|
||||
layout(constraints.maxWidth, constraints.maxHeight) {
|
||||
scaffoldPlaceable.place(0, 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
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.model.TimelineItem
|
||||
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.matrix.api.core.EventId
|
||||
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.room.MatrixRoom
|
||||
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.extensions.toAnalyticsViewRoom
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@@ -172,9 +172,10 @@ private fun SheetContent(
|
||||
item {
|
||||
Column {
|
||||
MessageSummary(
|
||||
event = target.event, modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
event = target.event,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
HorizontalDivider()
|
||||
@@ -299,7 +300,11 @@ private fun EmojiReactionsRow(
|
||||
) {
|
||||
// TODO use most recently used emojis here when available from the Rust SDK
|
||||
val defaultEmojis = sequenceOf(
|
||||
"👍️", "👎️", "🔥", "❤️", "👏"
|
||||
"👍️",
|
||||
"👎️",
|
||||
"🔥",
|
||||
"❤️",
|
||||
"👏"
|
||||
)
|
||||
for (emoji in defaultEmojis) {
|
||||
val isHighlighted = highlightedEmojis.contains(emoji)
|
||||
|
||||
@@ -48,7 +48,6 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
|
||||
|
||||
@Composable
|
||||
override fun present(): AttachmentsPreviewState {
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val sendActionState = remember {
|
||||
|
||||
@@ -34,4 +34,3 @@ sealed interface SendActionState {
|
||||
data class Failure(val error: Throwable) : SendActionState
|
||||
data object Done : SendActionState
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ open class AttachmentsPreviewStateProvider : PreviewParameterProvider<Attachment
|
||||
|
||||
fun anAttachmentsPreviewState(
|
||||
mediaInfo: MediaInfo = anImageInfo(),
|
||||
sendActionState: SendActionState = SendActionState.Idle) = AttachmentsPreviewState(
|
||||
sendActionState: SendActionState = SendActionState.Idle
|
||||
) = AttachmentsPreviewState(
|
||||
attachment = Attachment.Media(
|
||||
localMedia = LocalMedia("file://path".toUri(), mediaInfo),
|
||||
compressIfPossible = true
|
||||
|
||||
@@ -48,7 +48,6 @@ fun AttachmentsPreviewView(
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
||||
fun postSendAttachment() {
|
||||
state.eventSink(AttachmentsPreviewEvents.SendAttachment)
|
||||
}
|
||||
@@ -88,7 +87,6 @@ private fun AttachmentSendStateView(
|
||||
onDismissClicked: () -> Unit,
|
||||
onRetryClicked: () -> Unit
|
||||
) {
|
||||
|
||||
when (sendActionState) {
|
||||
is SendActionState.Sending -> {
|
||||
ProgressDialog(
|
||||
|
||||
@@ -88,8 +88,8 @@ object MentionSuggestionsProcessor {
|
||||
}
|
||||
|
||||
fun memberMatchesQuery(member: RoomMember, query: String): Boolean {
|
||||
return member.userId.value.contains(query, ignoreCase = true)
|
||||
|| member.displayName?.contains(query, ignoreCase = true) == true
|
||||
return member.userId.value.contains(query, ignoreCase = true) ||
|
||||
member.displayName?.contains(query, ignoreCase = true) == true
|
||||
}
|
||||
|
||||
val matchingMembers = roomMembers
|
||||
|
||||
@@ -62,12 +62,12 @@ internal fun AttachmentsBottomSheet(
|
||||
}
|
||||
|
||||
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
|
||||
localView.hideKeyboard()
|
||||
isVisible = true
|
||||
true
|
||||
} else {
|
||||
isVisible = false
|
||||
false
|
||||
}
|
||||
}
|
||||
// Send 'DismissAttachmentMenu' event when the bottomsheet was just hidden
|
||||
@@ -122,7 +122,7 @@ private fun AttachmentSourcePickerMenu(
|
||||
)
|
||||
ListItem(
|
||||
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)) },
|
||||
style = ListItemStyle.Primary,
|
||||
)
|
||||
|
||||
@@ -456,4 +456,3 @@ class MessageComposerPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,4 +35,3 @@ class DefaultRichTextEditorStateFactory @Inject constructor() : RichTextEditorSt
|
||||
return rememberRichTextEditorState()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
@SingleIn(SessionScope::class)
|
||||
class DefaultHtmlConverterProvider @Inject constructor(): HtmlConverterProvider {
|
||||
class DefaultHtmlConverterProvider @Inject constructor() : HtmlConverterProvider {
|
||||
|
||||
private val htmlConverter: MutableState<HtmlConverter?> = mutableStateOf(null)
|
||||
|
||||
@@ -67,7 +67,7 @@ class DefaultHtmlConverterProvider @Inject constructor(): HtmlConverterProvider
|
||||
return TextDisplay.Custom(mentionSpanProvider.getMentionSpanFor(text, url))
|
||||
}
|
||||
},
|
||||
isMention = { _, url -> mentionDetector?.isMention(url).orFalse() }
|
||||
isMention = { _, url -> mentionDetector?.isMention(url).orFalse() }
|
||||
).apply {
|
||||
configureWith(editorStyle)
|
||||
}
|
||||
|
||||
@@ -179,7 +179,9 @@ internal fun aTimelineItemDebugInfo(
|
||||
originalJson: String? = null,
|
||||
latestEditedJson: String? = null,
|
||||
) = TimelineItemDebugInfo(
|
||||
model, originalJson, latestEditedJson
|
||||
model,
|
||||
originalJson,
|
||||
latestEditedJson
|
||||
)
|
||||
|
||||
internal fun aTimelineItemReadReceipts(): TimelineItemReadReceipts {
|
||||
|
||||
@@ -120,8 +120,8 @@ fun TimelineView(
|
||||
timelineItem = timelineItem,
|
||||
timelineRoomInfo = state.timelineRoomInfo,
|
||||
showReadReceipts = state.showReadReceipts,
|
||||
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true
|
||||
&& state.timelineItems.first().identifier() == timelineItem.identifier(),
|
||||
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true &&
|
||||
state.timelineItems.first().identifier() == timelineItem.identifier(),
|
||||
highlightedItem = state.highlightedEventId?.value,
|
||||
onClick = onMessageClicked,
|
||||
onLongClick = onMessageLongClicked,
|
||||
|
||||
@@ -165,8 +165,7 @@ private fun ReactionContent(
|
||||
model = MediaRequestData(MediaSource(reaction.key), MediaRequestData.Kind.Content),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text(
|
||||
text = reaction.displayKey,
|
||||
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.graphics.graphicsLayer
|
||||
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.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
|
||||
|
||||
@@ -419,7 +419,6 @@ private fun MessageEventBubbleContent(
|
||||
@Suppress("ModifierNaming")
|
||||
bubbleModifier: Modifier = Modifier, // need to rename this modifier to prevent linter false positives
|
||||
) {
|
||||
|
||||
// Long clicks are not not automatically propagated from a `clickable`
|
||||
// to its `combinedClickable` parent so we do it manually
|
||||
fun onTimestampLongClick() = onMessageLongClick()
|
||||
@@ -578,7 +577,6 @@ private fun MessageEventBubbleContent(
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.clickable(enabled = true, onClick = inReplyToClick),
|
||||
)
|
||||
|
||||
}
|
||||
if (inReplyToDetails != null) {
|
||||
// Use SubComposeLayout only if necessary as it can have consequences on the performance.
|
||||
@@ -669,7 +667,7 @@ internal fun TimelineItemEventRowPreview() = ElementPreview {
|
||||
isMine = it,
|
||||
content = aTimelineItemTextContent().copy(
|
||||
body = "A long text which will be displayed on several lines and" +
|
||||
" hopefully can be manually adjusted to test different behaviors."
|
||||
" hopefully can be manually adjusted to test different behaviors."
|
||||
),
|
||||
groupPosition = TimelineItemGroupPosition.First,
|
||||
),
|
||||
|
||||
@@ -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.res.pluralStringResource
|
||||
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.TimelineRoomInfo
|
||||
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.components.group.GroupHeaderView
|
||||
|
||||
@@ -117,7 +117,7 @@ fun TimelineItemReactionsLayout(
|
||||
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 {
|
||||
var width = 0
|
||||
var height = 0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user