Merge branch 'develop' into feature/fga/space_settings_iteration
This commit is contained in:
commit
ce079e84f5
600 changed files with 3591 additions and 2388 deletions
2
.github/workflows/sync-localazy.yml
vendored
2
.github/workflows/sync-localazy.yml
vendored
|
|
@ -36,7 +36,7 @@ jobs:
|
|||
./tools/localazy/importSupportedLocalesFromLocalazy.py
|
||||
./tools/test/generateAllScreenshots.py
|
||||
- name: Create Pull Request for Strings
|
||||
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9
|
||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
|
||||
with:
|
||||
token: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||
commit-message: Sync Strings from Localazy
|
||||
|
|
|
|||
2
.github/workflows/sync-sas-strings.yml
vendored
2
.github/workflows/sync-sas-strings.yml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
- name: Run SAS String script
|
||||
run: ./tools/sas/import_sas_strings.py
|
||||
- name: Create Pull Request for SAS Strings
|
||||
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9
|
||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
|
||||
with:
|
||||
commit-message: Sync SAS Strings
|
||||
title: Sync SAS Strings
|
||||
|
|
|
|||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
|
@ -83,7 +83,7 @@ jobs:
|
|||
|
||||
# https://github.com/codecov/codecov-action
|
||||
- name: ☂️ Upload coverage reports to codecov
|
||||
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -199,6 +199,10 @@ android {
|
|||
resources.pickFirsts += setOf(
|
||||
"META-INF/versions/9/OSGI-INF/MANIFEST.MF",
|
||||
)
|
||||
|
||||
jniLibs {
|
||||
useLegacyPackaging = project.findProperty("useLegacyPackaging")?.toString()?.toBoolean()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
|
|
@ -69,4 +69,4 @@
|
|||
-keep class org.matrix.rustcomponents.sdk.** { *;}
|
||||
-keep class uniffi.** { *;}
|
||||
-keep class io.element.android.x.di.** { *; }
|
||||
-keepnames class io.element.android.x.**
|
||||
-keepclasseswithmembernames,allowoptimization,allowshrinking class io.element.android.** { *; }
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ object LearnMoreConfig {
|
|||
const val DEVICE_VERIFICATION_URL: String = "https://element.io/help#encryption-device-verification"
|
||||
const val SECURE_BACKUP_URL: String = "https://element.io/help#encryption5"
|
||||
const val IDENTITY_CHANGE_URL: String = "https://element.io/help#encryption18"
|
||||
const val HISTORY_VISIBLE_URL: String = "https://element.io/en/help#e2ee-history-sharing"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
package io.element.android.appnav.room.joined
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Parcelable
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -96,6 +98,9 @@ class JoinedRoomLoadedFlowNode(
|
|||
private val callback: Callback = callback()
|
||||
override val graph = roomGraphFactory.create(inputs.room)
|
||||
|
||||
// This is an ugly hack to check activity recreation
|
||||
private var currentActivity: Activity? = null
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onCreate = {
|
||||
|
|
@ -115,8 +120,12 @@ class JoinedRoomLoadedFlowNode(
|
|||
},
|
||||
onDestroy = {
|
||||
Timber.v("OnDestroy")
|
||||
// If we're just going through an activity recreation there's no need to destroy the Room object
|
||||
// Destroying it would actually cause an issue where its methods can no longer be called
|
||||
if (currentActivity?.isChangingConfigurations != true) {
|
||||
activeRoomsHolder.removeRoom(inputs.room.sessionId, inputs.room.roomId)
|
||||
inputs.room.destroy()
|
||||
}
|
||||
appNavigationStateService.onLeavingRoom(id)
|
||||
}
|
||||
)
|
||||
|
|
@ -289,6 +298,8 @@ class JoinedRoomLoadedFlowNode(
|
|||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
currentActivity = LocalActivity.current
|
||||
|
||||
BackstackView()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ allprojects {
|
|||
config.from(files("$rootDir/tools/detekt/detekt.yml"))
|
||||
}
|
||||
dependencies {
|
||||
detektPlugins("io.nlopez.compose.rules:detekt:0.4.28")
|
||||
detektPlugins("io.nlopez.compose.rules:detekt:0.5.1")
|
||||
detektPlugins(project(":tests:detekt-rules"))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ private fun SpaceAnnouncementHeader(
|
|||
showBetaLabel = true,
|
||||
subTitle = stringResource(id = R.string.screen_space_announcement_subtitle),
|
||||
iconStyle = BigIcon.Style.Default(
|
||||
vectorIcon = CompoundIcons.WorkspaceSolid(),
|
||||
vectorIcon = CompoundIcons.SpaceSolid(),
|
||||
usePrimaryTint = true,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidityEf
|
|||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -132,7 +132,7 @@ class ConfigureRoomPresenter(
|
|||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> dataStore.setAvatarUri(uri = null)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import dev.zacsweers.metro.AssistedInject
|
|||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.noop.NoopPermissionsPresenter
|
||||
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
||||
|
|
@ -58,7 +58,7 @@ class NotificationsOptInPresenter(
|
|||
if (notificationsPermissionsState.permissionGranted) {
|
||||
callback.onNotificationsOptInFinished()
|
||||
} else {
|
||||
notificationsPermissionsState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
notificationsPermissionsState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
NotificationsOptInEvents.NotNowClicked -> {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ enum class HomeNavigationBarItem(
|
|||
isSelected: Boolean,
|
||||
) = when (this) {
|
||||
Chats -> if (isSelected) CompoundIcons.ChatSolid() else CompoundIcons.Chat()
|
||||
Spaces -> if (isSelected) CompoundIcons.WorkspaceSolid() else CompoundIcons.Workspace()
|
||||
Spaces -> if (isSelected) CompoundIcons.SpaceSolid() else CompoundIcons.Space()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ internal fun RoomSummaryRow(
|
|||
) {
|
||||
NameAndTimestampRow(
|
||||
name = room.name,
|
||||
latestEvent = room.latestEvent,
|
||||
timestamp = room.timestamp,
|
||||
isHighlighted = room.isHighlighted
|
||||
)
|
||||
|
|
@ -138,7 +137,6 @@ internal fun RoomSummaryRow(
|
|||
) {
|
||||
NameAndTimestampRow(
|
||||
name = room.name,
|
||||
latestEvent = room.latestEvent,
|
||||
timestamp = null,
|
||||
isHighlighted = room.isHighlighted
|
||||
)
|
||||
|
|
@ -214,7 +212,6 @@ private fun RoomSummaryScaffoldRow(
|
|||
@Composable
|
||||
private fun NameAndTimestampRow(
|
||||
name: String?,
|
||||
latestEvent: LatestEvent,
|
||||
timestamp: String?,
|
||||
isHighlighted: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
|
|
@ -236,28 +233,6 @@ private fun NameAndTimestampRow(
|
|||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
// Picto
|
||||
when (latestEvent) {
|
||||
is LatestEvent.Sending -> {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Icon(
|
||||
modifier = Modifier.size(16.dp),
|
||||
imageVector = CompoundIcons.Time(),
|
||||
contentDescription = null,
|
||||
tint = ElementTheme.colors.iconTertiary,
|
||||
)
|
||||
}
|
||||
is LatestEvent.Error -> {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Icon(
|
||||
modifier = Modifier.size(16.dp),
|
||||
imageVector = CompoundIcons.ErrorSolid(),
|
||||
contentDescription = null,
|
||||
tint = ElementTheme.colors.iconCriticalPrimary,
|
||||
)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
// Timestamp
|
||||
Text(
|
||||
|
|
@ -302,7 +277,6 @@ private fun MessagePreviewAndIndicatorRow(
|
|||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = spacedBy(28.dp)
|
||||
) {
|
||||
if (room.isTombstoned) {
|
||||
Text(
|
||||
|
|
@ -316,6 +290,16 @@ private fun MessagePreviewAndIndicatorRow(
|
|||
)
|
||||
} else {
|
||||
if (room.latestEvent is LatestEvent.Error) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(top = 2.dp)
|
||||
.size(16.dp),
|
||||
imageVector = CompoundIcons.ErrorSolid(),
|
||||
// The last message contains the error.
|
||||
contentDescription = null,
|
||||
tint = ElementTheme.colors.iconCriticalPrimary,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringResource(CommonStrings.common_message_failed_to_send),
|
||||
|
|
@ -326,6 +310,17 @@ private fun MessagePreviewAndIndicatorRow(
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
} else {
|
||||
if (room.latestEvent is LatestEvent.Sending) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(top = 2.dp)
|
||||
.size(16.dp),
|
||||
imageVector = CompoundIcons.Time(),
|
||||
contentDescription = stringResource(CommonStrings.common_sending),
|
||||
tint = ElementTheme.colors.iconTertiary,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
}
|
||||
val messagePreview = room.latestEvent.content()
|
||||
val annotatedMessagePreview = messagePreview as? AnnotatedString ?: AnnotatedString(text = messagePreview.orEmpty().toString())
|
||||
Text(
|
||||
|
|
@ -339,7 +334,7 @@ private fun MessagePreviewAndIndicatorRow(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
// Call and unread
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class DefaultPinCodeManager(
|
|||
lockScreenStore.onWrongPin()
|
||||
}
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import androidx.compose.runtime.setValue
|
|||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
|
||||
@Inject
|
||||
|
|
@ -46,7 +46,7 @@ class QrCodeIntroPresenter(
|
|||
canContinue = true
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ private fun Content(
|
|||
QrCodeCameraView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onScanQrCode = { state.eventSink.invoke(QrCodeScanEvents.QrCodeScanned(it)) },
|
||||
renderPreview = state.isScanning,
|
||||
isScanning = state.isScanning,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ dependencies {
|
|||
implementation(libs.jsoup)
|
||||
implementation(libs.androidx.constraintlayout)
|
||||
implementation(libs.androidx.constraintlayout.compose)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.androidx.media3.exoplayer)
|
||||
implementation(libs.androidx.media3.ui)
|
||||
implementation(libs.sigpwned.emoji4j)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import io.element.android.features.messages.api.timeline.HtmlConverterProvider
|
|||
import io.element.android.features.messages.impl.actionlist.ActionListEvents
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.link.LinkState
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvent
|
||||
|
|
@ -101,6 +102,7 @@ class MessagesPresenter(
|
|||
@Assisted private val timelinePresenter: Presenter<TimelineState>,
|
||||
private val timelineProtectionPresenter: Presenter<TimelineProtectionState>,
|
||||
private val identityChangeStatePresenter: Presenter<IdentityChangeState>,
|
||||
private val historyVisibleStatePresenter: Presenter<HistoryVisibleState>,
|
||||
private val linkPresenter: Presenter<LinkState>,
|
||||
@Assisted private val actionListPresenter: Presenter<ActionListState>,
|
||||
private val customReactionPresenter: Presenter<CustomReactionState>,
|
||||
|
|
@ -152,6 +154,7 @@ class MessagesPresenter(
|
|||
val timelineState = timelinePresenter.present()
|
||||
val timelineProtectionState = timelineProtectionPresenter.present()
|
||||
val identityChangeState = identityChangeStatePresenter.present()
|
||||
val historyVisibleState = historyVisibleStatePresenter.present()
|
||||
val actionListState = actionListPresenter.present()
|
||||
val linkState = linkPresenter.present()
|
||||
val customReactionState = customReactionPresenter.present()
|
||||
|
|
@ -274,6 +277,7 @@ class MessagesPresenter(
|
|||
timelineState = timelineState,
|
||||
timelineProtectionState = timelineProtectionState,
|
||||
identityChangeState = identityChangeState,
|
||||
historyVisibleState = historyVisibleState,
|
||||
linkState = linkState,
|
||||
actionListState = actionListState,
|
||||
customReactionState = customReactionState,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.messages.impl
|
|||
|
||||
import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerState
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.link.LinkState
|
||||
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
|
||||
|
|
@ -40,6 +41,7 @@ data class MessagesState(
|
|||
val timelineState: TimelineState,
|
||||
val timelineProtectionState: TimelineProtectionState,
|
||||
val identityChangeState: IdentityChangeState,
|
||||
val historyVisibleState: HistoryVisibleState,
|
||||
val linkState: LinkState,
|
||||
val actionListState: ActionListState,
|
||||
val customReactionState: CustomReactionState,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ import io.element.android.features.messages.api.timeline.voicemessages.composer.
|
|||
import io.element.android.features.messages.api.timeline.voicemessages.composer.aVoiceMessagePreviewState
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.aHistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.crypto.identity.aRoomMemberIdentityStateChange
|
||||
import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState
|
||||
import io.element.android.features.messages.impl.link.LinkState
|
||||
import io.element.android.features.messages.impl.link.aLinkState
|
||||
|
|
@ -38,6 +41,7 @@ import io.element.android.features.messages.impl.timeline.protection.aTimelinePr
|
|||
import io.element.android.features.roomcall.api.RoomCallState
|
||||
import io.element.android.features.roomcall.api.aStandByCallState
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
|
|
@ -48,6 +52,7 @@ import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
|||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.textcomposer.model.MessageComposerMode
|
||||
import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown
|
||||
import io.element.android.libraries.textcomposer.model.aTextEditorStateRich
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -83,6 +88,19 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
|||
timelineItems = aTimelineItemList(aTimelineItemTextContent()),
|
||||
)
|
||||
),
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(textEditorState = aTextEditorStateMarkdown()),
|
||||
identityChangeState = anIdentityChangeState(listOf(aRoomMemberIdentityStateChange()))
|
||||
),
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(textEditorState = aTextEditorStateMarkdown()),
|
||||
historyVisibleState = aHistoryVisibleState(showAlert = true)
|
||||
),
|
||||
aMessagesState(
|
||||
composerState = aMessageComposerState(textEditorState = aTextEditorStateMarkdown()),
|
||||
identityChangeState = anIdentityChangeState(listOf(aRoomMemberIdentityStateChange())),
|
||||
historyVisibleState = aHistoryVisibleState(showAlert = true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +121,7 @@ fun aMessagesState(
|
|||
),
|
||||
timelineProtectionState: TimelineProtectionState = aTimelineProtectionState(),
|
||||
identityChangeState: IdentityChangeState = anIdentityChangeState(),
|
||||
historyVisibleState: HistoryVisibleState = aHistoryVisibleState(),
|
||||
linkState: LinkState = aLinkState(),
|
||||
readReceiptBottomSheetState: ReadReceiptBottomSheetState = aReadReceiptBottomSheetState(),
|
||||
actionListState: ActionListState = anActionListState(),
|
||||
|
|
@ -125,6 +144,7 @@ fun aMessagesState(
|
|||
voiceMessageComposerState = voiceMessageComposerState,
|
||||
timelineProtectionState = timelineProtectionState,
|
||||
identityChangeState = identityChangeState,
|
||||
historyVisibleState = historyVisibleState,
|
||||
linkState = linkState,
|
||||
timelineState = timelineState,
|
||||
readReceiptBottomSheetState = readReceiptBottomSheetState,
|
||||
|
|
@ -145,11 +165,9 @@ fun aMessagesState(
|
|||
)
|
||||
|
||||
fun aRoomMemberModerationState(
|
||||
canKick: Boolean = false,
|
||||
canBan: Boolean = false,
|
||||
permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions.DEFAULT,
|
||||
) = object : RoomMemberModerationState {
|
||||
override val canKick: Boolean = canKick
|
||||
override val canBan: Boolean = canBan
|
||||
override val permissions: RoomMemberModerationPermissions = permissions
|
||||
override val eventSink: (RoomMemberModerationEvents) -> Unit = {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import io.element.android.features.messages.api.timeline.voicemessages.composer.
|
|||
import io.element.android.features.messages.impl.actionlist.ActionListEvents
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListView
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleStateView
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStateView
|
||||
import io.element.android.features.messages.impl.link.LinkEvents
|
||||
import io.element.android.features.messages.impl.link.LinkView
|
||||
|
|
@ -486,10 +487,17 @@ private fun MessagesViewComposerBottomSheetContents(
|
|||
// Do not show the identity change if user is composing a Rich message or is seeing suggestion(s).
|
||||
if (state.composerState.suggestions.isEmpty() &&
|
||||
state.composerState.textEditorState is TextEditorState.Markdown) {
|
||||
if (state.identityChangeState.roomMemberIdentityStateChanges.isNotEmpty()) {
|
||||
IdentityChangeStateView(
|
||||
state = state.identityChangeState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
} else {
|
||||
HistoryVisibleStateView(
|
||||
state = state.historyVisibleState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
val verificationViolation = state.identityChangeState.roomMemberIdentityStateChanges.firstOrNull {
|
||||
it.identityState == IdentityState.VerificationViolation
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.hash.hash
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.preferences.api.store.PreferenceDataStoreFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
interface HistoryVisibleAcknowledgementRepository {
|
||||
fun hasAcknowledged(roomId: RoomId): Flow<Boolean>
|
||||
suspend fun setAcknowledged(roomId: RoomId, value: Boolean)
|
||||
}
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultHistoryVisibleAcknowledgementRepository(
|
||||
sessionId: SessionId,
|
||||
preferenceDataStoreFactory: PreferenceDataStoreFactory,
|
||||
) : HistoryVisibleAcknowledgementRepository {
|
||||
val store =
|
||||
sessionId.value.hash().take(16).let { hash ->
|
||||
preferenceDataStoreFactory.create("elementx_historyvisible_$hash")
|
||||
}
|
||||
|
||||
override fun hasAcknowledged(roomId: RoomId): Flow<Boolean> {
|
||||
return store.data.map { prefs ->
|
||||
val acknowledged = prefs[booleanPreferencesKey(roomId.value)] ?: false
|
||||
acknowledged
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setAcknowledged(roomId: RoomId, value: Boolean) {
|
||||
store.edit { prefs ->
|
||||
prefs[booleanPreferencesKey(roomId.value)] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
sealed interface HistoryVisibleEvent {
|
||||
data object Acknowledge : HistoryVisibleEvent
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
data class HistoryVisibleState(
|
||||
val showAlert: Boolean,
|
||||
val eventSink: (HistoryVisibleEvent) -> Unit,
|
||||
)
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Inject
|
||||
class HistoryVisibleStatePresenter(
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val repository: HistoryVisibleAcknowledgementRepository,
|
||||
private val room: JoinedRoom,
|
||||
) : Presenter<HistoryVisibleState> {
|
||||
@Composable
|
||||
override fun present(): HistoryVisibleState {
|
||||
val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.EnableKeyShareOnInvite).collectAsState(initial = false)
|
||||
val roomInfo by room.roomInfoFlow.collectAsState()
|
||||
// Implicitly assume the alert is initially acknowledged to avoid flashes in UI.
|
||||
val acknowledged by repository.hasAcknowledged(room.roomId).collectAsState(initial = true)
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(roomInfo.historyVisibility, acknowledged) {
|
||||
if (roomInfo.historyVisibility == RoomHistoryVisibility.Joined && acknowledged) {
|
||||
repository.setAcknowledged(room.roomId, false)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvent(event: HistoryVisibleEvent) {
|
||||
when (event) {
|
||||
is HistoryVisibleEvent.Acknowledge -> coroutineScope.setAcknowledged(room.roomId, true)
|
||||
}
|
||||
}
|
||||
|
||||
return HistoryVisibleState(
|
||||
showAlert = isFeatureEnabled && roomInfo.historyVisibility != RoomHistoryVisibility.Joined && roomInfo.isEncrypted == true && !acknowledged,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setAcknowledged(roomId: RoomId, value: Boolean) = launch {
|
||||
repository.setAcknowledged(roomId, value)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
||||
class HistoryVisibleStateProvider : PreviewParameterProvider<HistoryVisibleState> {
|
||||
override val values: Sequence<HistoryVisibleState>
|
||||
get() = sequenceOf(
|
||||
aHistoryVisibleState(showAlert = true),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aHistoryVisibleState(
|
||||
showAlert: Boolean = false,
|
||||
eventSink: (HistoryVisibleEvent) -> Unit = {},
|
||||
) = HistoryVisibleState(
|
||||
showAlert,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.LinkAnnotation
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.appconfig.LearnMoreConfig
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertLevel
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun HistoryVisibleStateView(
|
||||
state: HistoryVisibleState,
|
||||
onLinkClick: (String, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (!state.showAlert) {
|
||||
return
|
||||
}
|
||||
|
||||
ComposerAlertMolecule(
|
||||
modifier = modifier,
|
||||
avatar = null,
|
||||
showIcon = true,
|
||||
level = ComposerAlertLevel.Info,
|
||||
content = buildAnnotatedString {
|
||||
val learnMoreStr = stringResource(CommonStrings.action_learn_more)
|
||||
val fullText = stringResource(CommonStrings.crypto_history_visible, learnMoreStr)
|
||||
append(fullText)
|
||||
val learnMoreStartIndex = fullText.lastIndexOf(learnMoreStr)
|
||||
addStyle(
|
||||
style = SpanStyle(
|
||||
textDecoration = TextDecoration.Underline,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = ElementTheme.colors.textPrimary
|
||||
),
|
||||
start = learnMoreStartIndex,
|
||||
end = learnMoreStartIndex + learnMoreStr.length,
|
||||
)
|
||||
addLink(
|
||||
url = LinkAnnotation.Url(
|
||||
url = LearnMoreConfig.HISTORY_VISIBLE_URL,
|
||||
linkInteractionListener = {
|
||||
onLinkClick(LearnMoreConfig.HISTORY_VISIBLE_URL, true)
|
||||
}
|
||||
),
|
||||
start = learnMoreStartIndex,
|
||||
end = learnMoreStartIndex + learnMoreStr.length,
|
||||
)
|
||||
},
|
||||
submitText = stringResource(CommonStrings.action_dismiss),
|
||||
onSubmitClick = { state.eventSink(HistoryVisibleEvent.Acknowledge) },
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun HistoryVisibleStateViewPreview(
|
||||
@PreviewParameter(HistoryVisibleStateProvider::class) state: HistoryVisibleState,
|
||||
) = ElementPreview {
|
||||
HistoryVisibleStateView(
|
||||
state = state,
|
||||
onLinkClick = { _, _ -> },
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.element.android.features.messages.impl.MessagesView
|
||||
import io.element.android.features.messages.impl.aMessagesState
|
||||
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MessagesViewWithHistoryVisiblePreview() = ElementPreview {
|
||||
MessagesView(
|
||||
state = aMessagesState(
|
||||
composerState = aMessageComposerState(
|
||||
textEditorState = aTextEditorStateMarkdown(
|
||||
initialText = "",
|
||||
initialFocus = false,
|
||||
)
|
||||
),
|
||||
historyVisibleState = aHistoryVisibleState(showAlert = true),
|
||||
),
|
||||
onBackClick = {},
|
||||
onRoomDetailsClick = {},
|
||||
onEventContentClick = { _, _ -> false },
|
||||
onUserDataClick = {},
|
||||
onLinkClick = { _, _ -> },
|
||||
onSendLocationClick = {},
|
||||
onCreatePollClick = {},
|
||||
onJoinCallClick = {},
|
||||
onViewAllPinnedMessagesClick = {},
|
||||
knockRequestsBannerView = {}
|
||||
)
|
||||
}
|
||||
|
|
@ -11,6 +11,8 @@ package io.element.android.features.messages.impl.di
|
|||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.Binds
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.HistoryVisibleStatePresenter
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
|
||||
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStatePresenter
|
||||
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailurePresenter
|
||||
|
|
@ -61,4 +63,7 @@ interface MessagesBindsModule {
|
|||
|
||||
@Binds
|
||||
fun bindIdentityChangeStatePresenter(presenter: IdentityChangeStatePresenter): Presenter<IdentityChangeState>
|
||||
|
||||
@Binds
|
||||
fun bindHistoryVisibleStatePresenter(presenter: HistoryVisibleStatePresenter): Presenter<HistoryVisibleState>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ import io.element.android.libraries.mediapickers.api.PickerProvider
|
|||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaSenderFactory
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
import io.element.android.libraries.push.api.notifications.conversations.NotificationConversationService
|
||||
|
|
@ -286,7 +286,7 @@ class MessageComposerPresenter(
|
|||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingEvent = event
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
MessageComposerEvent.PickAttachmentSource.VideoFromCamera -> localCoroutineScope.launch {
|
||||
|
|
@ -295,7 +295,7 @@ class MessageComposerPresenter(
|
|||
cameraVideoPicker.launch()
|
||||
} else {
|
||||
pendingEvent = event
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
MessageComposerEvent.PickAttachmentSource.Location -> {
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ fun EventDebugInfoView(
|
|||
private fun prettyJSON(maybeJSON: String): String {
|
||||
return try {
|
||||
JSONObject(maybeJSON).toString(2)
|
||||
} catch (e: JSONException) {
|
||||
} catch (_: JSONException) {
|
||||
// Prefer not pretty-printing over crashing if the data is not actually JSON
|
||||
maybeJSON
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import io.element.android.libraries.di.RoomScope
|
|||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.mediaupload.api.MediaSenderFactory
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.textcomposer.model.VoiceMessagePlayerEvent
|
||||
import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent
|
||||
|
|
@ -111,7 +111,7 @@ class DefaultVoiceMessageComposerPresenter(
|
|||
}
|
||||
else -> {
|
||||
Timber.i("Voice message permission needed")
|
||||
permissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
permissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -176,10 +176,10 @@ class DefaultVoiceMessageComposerPresenter(
|
|||
localCoroutineScope.deleteRecording()
|
||||
}
|
||||
VoiceMessageComposerEvent.DismissPermissionsRationale -> {
|
||||
permissionState.eventSink(PermissionsEvents.CloseDialog)
|
||||
permissionState.eventSink(PermissionsEvent.CloseDialog)
|
||||
}
|
||||
VoiceMessageComposerEvent.AcceptPermissionRationale -> {
|
||||
permissionState.eventSink(PermissionsEvents.OpenSystemSettingAndCloseDialog)
|
||||
permissionState.eventSink(PermissionsEvent.OpenSystemSettingAndCloseDialog)
|
||||
}
|
||||
is VoiceMessageComposerEvent.LifecycleEvent -> handleLifecycleEvent(event.event)
|
||||
VoiceMessageComposerEvent.DismissSendFailureDialog -> {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvents
|
|||
import io.element.android.features.messages.impl.actionlist.ActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
|
||||
import io.element.android.features.messages.impl.crypto.historyvisible.aHistoryVisibleState
|
||||
import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState
|
||||
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
||||
import io.element.android.features.messages.impl.link.aLinkState
|
||||
|
|
@ -1297,6 +1298,7 @@ class MessagesPresenterTest {
|
|||
timelinePresenter = { aTimelineState(eventSink = timelineEventSink) },
|
||||
timelineProtectionPresenter = { aTimelineProtectionState() },
|
||||
identityChangeStatePresenter = { anIdentityChangeState() },
|
||||
historyVisibleStatePresenter = { aHistoryVisibleState() },
|
||||
linkPresenter = { aLinkState() },
|
||||
actionListPresenter = { anActionListState(eventSink = actionListEventSink) },
|
||||
customReactionPresenter = { aCustomReactionState() },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakeHistoryVisibleAcknowledgementRepository(
|
||||
private val acknowledgements: MutableMap<RoomId, MutableStateFlow<Boolean>> = mutableMapOf()
|
||||
) : HistoryVisibleAcknowledgementRepository {
|
||||
override fun hasAcknowledged(roomId: RoomId): Flow<Boolean> {
|
||||
return acknowledgements.getOrPut(roomId) {
|
||||
MutableStateFlow(false)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setAcknowledged(roomId: RoomId, value: Boolean) {
|
||||
val flow = acknowledgements.getOrPut(roomId) {
|
||||
MutableStateFlow(value)
|
||||
}
|
||||
flow.emit(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Create the repository with a pre-existing entry.
|
||||
*/
|
||||
fun withRoom(roomId: RoomId, acknowledged: Boolean = false): FakeHistoryVisibleAcknowledgementRepository {
|
||||
return FakeHistoryVisibleAcknowledgementRepository(
|
||||
mutableMapOf(
|
||||
roomId to MutableStateFlow(acknowledged)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.historyvisible
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class HistoryVisibleStatePresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
@Test
|
||||
fun `present - not visible if feature disabled`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room, enabled = false, acknowledged = false)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room shared, unencrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = false))
|
||||
val presenter = createHistoryVisibleStatePresenter(room)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room joined, encrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = false))
|
||||
val presenter = createHistoryVisibleStatePresenter(room)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room shared, encrypted, unacknowledged`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room, acknowledged = false)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showAlert).isFalse()
|
||||
val nextState = awaitItem()
|
||||
assertThat(nextState.showAlert).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial with room shared, encrypted, acknowledged`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
val presenter = createHistoryVisibleStatePresenter(room, acknowledged = true)
|
||||
presenter.test {
|
||||
assertThat(awaitLastSequentialItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - transition from joined + unencrypted, to shared + encrypted`() = runTest {
|
||||
val room = FakeJoinedRoom()
|
||||
val featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.EnableKeyShareOnInvite.key to true))
|
||||
val repository = FakeHistoryVisibleAcknowledgementRepository()
|
||||
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = false))
|
||||
|
||||
val presenter = HistoryVisibleStatePresenter(
|
||||
featureFlagService,
|
||||
repository,
|
||||
room,
|
||||
)
|
||||
|
||||
presenter.test {
|
||||
// emitted by the feature flag service(?)
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
|
||||
// emitted state from room info assignment
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
|
||||
// room is marked as encrypted
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Joined, isEncrypted = true))
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
|
||||
// room history visibility is changed to shared
|
||||
room.givenRoomInfo(aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, isEncrypted = true))
|
||||
assertThat(awaitItem().showAlert).isTrue()
|
||||
|
||||
// alert is acknowledged
|
||||
repository.setAcknowledged(room.roomId, true)
|
||||
assertThat(awaitItem().showAlert).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHistoryVisibleStatePresenter(
|
||||
room: JoinedRoom = FakeJoinedRoom(),
|
||||
enabled: Boolean = true,
|
||||
acknowledged: Boolean = false
|
||||
): HistoryVisibleStatePresenter {
|
||||
return HistoryVisibleStatePresenter(
|
||||
room = room,
|
||||
featureFlagService = FakeFeatureFlagService(mapOf("feature.enableKeyShareOnInvite" to enabled)),
|
||||
repository = FakeHistoryVisibleAcknowledgementRepository.withRoom(room.roomId, acknowledged)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -21,4 +21,5 @@ sealed interface DeveloperSettingsEvents {
|
|||
data class SetShowColorPicker(val show: Boolean) : DeveloperSettingsEvents
|
||||
data class ChangeBrandColor(val color: Color?) : DeveloperSettingsEvents
|
||||
data object ClearCache : DeveloperSettingsEvents
|
||||
data object VacuumStores : DeveloperSettingsEvents
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import io.element.android.features.preferences.impl.developer.tracing.toLogLevel
|
|||
import io.element.android.features.preferences.impl.model.EnabledFeature
|
||||
import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase
|
||||
import io.element.android.features.preferences.impl.tasks.ComputeCacheSizeUseCase
|
||||
import io.element.android.features.preferences.impl.tasks.VacuumStoresUseCase
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
|
|
@ -61,6 +62,7 @@ class DeveloperSettingsPresenter(
|
|||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val buildMeta: BuildMeta,
|
||||
private val enterpriseService: EnterpriseService,
|
||||
private val vacuumStoresUseCase: VacuumStoresUseCase,
|
||||
) : Presenter<DeveloperSettingsState> {
|
||||
@Composable
|
||||
override fun present(): DeveloperSettingsState {
|
||||
|
|
@ -151,6 +153,9 @@ class DeveloperSettingsPresenter(
|
|||
is DeveloperSettingsEvents.SetShowColorPicker -> {
|
||||
showColorPicker = event.show
|
||||
}
|
||||
DeveloperSettingsEvents.VacuumStores -> coroutineScope.launch {
|
||||
vacuumStoresUseCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,14 @@ fun DeveloperSettingsView(
|
|||
}
|
||||
val cache = state.cacheSize
|
||||
PreferenceCategory(title = "Cache") {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text("Vacuum stores")
|
||||
},
|
||||
onClick = {
|
||||
state.eventSink(DeveloperSettingsEvents.VacuumStores)
|
||||
}
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text("Clear cache")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.preferences.impl.tasks
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import timber.log.Timber
|
||||
|
||||
fun interface VacuumStoresUseCase {
|
||||
suspend operator fun invoke()
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultVacuumStoresUseCase(
|
||||
private val matrixClient: MatrixClient,
|
||||
) : VacuumStoresUseCase {
|
||||
override suspend fun invoke() {
|
||||
matrixClient.performDatabaseVacuum()
|
||||
.onFailure { Timber.e(it, "Failed to vacuum stores") }
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ import io.element.android.libraries.matrix.ui.media.AvatarAction
|
|||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -127,7 +127,7 @@ class EditUserProfilePresenter(
|
|||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> {
|
||||
temporaryUriDeleter.delete(userAvatarUri?.toUri())
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import io.element.android.features.enterprise.test.FakeEnterpriseService
|
|||
import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem
|
||||
import io.element.android.features.preferences.impl.tasks.FakeClearCacheUseCase
|
||||
import io.element.android.features.preferences.impl.tasks.FakeComputeCacheSizeUseCase
|
||||
import io.element.android.features.preferences.impl.tasks.VacuumStoresUseCase
|
||||
import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
|
|
@ -212,6 +213,23 @@ class DeveloperSettingsPresenterTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - VacuumStores action invokes the VacuumStoresUseCase`() = runTest {
|
||||
var vacuumCalled = false
|
||||
val presenter = createDeveloperSettingsPresenter(
|
||||
vacuumStoresUseCase = VacuumStoresUseCase {
|
||||
vacuumCalled = true
|
||||
}
|
||||
)
|
||||
presenter.test {
|
||||
val state = awaitItem()
|
||||
assertThat(vacuumCalled).isFalse()
|
||||
state.eventSink(DeveloperSettingsEvents.VacuumStores)
|
||||
skipItems(1)
|
||||
assertThat(vacuumCalled).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDeveloperSettingsPresenter(
|
||||
sessionId: SessionId = A_SESSION_ID,
|
||||
featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(
|
||||
|
|
@ -230,6 +248,7 @@ class DeveloperSettingsPresenterTest {
|
|||
preferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
||||
buildMeta: BuildMeta = aBuildMeta(),
|
||||
enterpriseService: EnterpriseService = FakeEnterpriseService(),
|
||||
vacuumStoresUseCase: VacuumStoresUseCase = VacuumStoresUseCase {},
|
||||
): DeveloperSettingsPresenter {
|
||||
return DeveloperSettingsPresenter(
|
||||
sessionId = sessionId,
|
||||
|
|
@ -240,6 +259,7 @@ class DeveloperSettingsPresenterTest {
|
|||
appPreferencesStore = preferencesStore,
|
||||
buildMeta = buildMeta,
|
||||
enterpriseService = enterpriseService,
|
||||
vacuumStoresUseCase = vacuumStoresUseCase,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_room_change_permissions_administrators">"Správca"</string>
|
||||
<string name="screen_room_change_permissions_ban_people">"Zakázať ľudí"</string>
|
||||
<string name="screen_room_change_permissions_change_settings">"Zmeniť nastavenia"</string>
|
||||
<string name="screen_room_change_permissions_delete_messages">"Odstrániť správy"</string>
|
||||
<string name="screen_room_change_permissions_everyone">"Člen"</string>
|
||||
<string name="screen_room_change_permissions_invite_people">"Pozvať ľudí"</string>
|
||||
<string name="screen_room_change_permissions_manage_space">"Spravovať priestor"</string>
|
||||
<string name="screen_room_change_permissions_manage_space_rooms">"Spravovať miestnosti"</string>
|
||||
<string name="screen_room_change_permissions_member_moderation">"Spravovať členov"</string>
|
||||
<string name="screen_room_change_permissions_messages_and_content">"Správy a obsah"</string>
|
||||
<string name="screen_room_change_permissions_moderators">"Moderátor"</string>
|
||||
|
|
@ -17,7 +14,6 @@
|
|||
<string name="screen_room_change_permissions_room_name">"Zmeniť názov miestnosti"</string>
|
||||
<string name="screen_room_change_permissions_room_topic">"Zmeniť tému miestnosti"</string>
|
||||
<string name="screen_room_change_permissions_send_messages">"Odoslať správy"</string>
|
||||
<string name="screen_room_change_permissions_title">"Povolenia"</string>
|
||||
<string name="screen_room_change_role_administrators_title">"Upraviť správcov"</string>
|
||||
<string name="screen_room_change_role_confirm_add_admin_description">"Túto akciu nebudete môcť vrátiť späť. Zvyšujete úroveň používateľa na rovnakú úroveň výkonu ako máte vy."</string>
|
||||
<string name="screen_room_change_role_confirm_add_admin_title">"Pridať správcu?"</string>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ data class RoomMemberListState(
|
|||
val moderationState: RoomMemberModerationState,
|
||||
val eventSink: (RoomMemberListEvents) -> Unit,
|
||||
) {
|
||||
val showBannedSection: Boolean = moderationState.canBan && roomMembers.dataOrNull()?.banned?.isNotEmpty() == true
|
||||
val showBannedSection: Boolean = moderationState.permissions.canBan && roomMembers.dataOrNull()?.banned?.isNotEmpty() == true
|
||||
}
|
||||
|
||||
enum class SelectedSection {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.roomdetails.impl.members
|
|||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.architecture.map
|
||||
|
|
@ -99,8 +100,10 @@ fun aRoomMemberModerationState(
|
|||
canKick: Boolean = false,
|
||||
): RoomMemberModerationState {
|
||||
return object : RoomMemberModerationState {
|
||||
override val canKick: Boolean = canKick
|
||||
override val canBan: Boolean = canBan
|
||||
override val permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions(
|
||||
canBan = canBan,
|
||||
canKick = canKick,
|
||||
)
|
||||
override val eventSink: (RoomMemberModerationEvents) -> Unit = {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@
|
|||
<string name="screen_room_member_list_manage_member_unban_title">"Eemalda suhtluskeeld jututoas"</string>
|
||||
<string name="screen_room_member_list_mode_banned">"Suhtluskeeluga kasutajad"</string>
|
||||
<string name="screen_room_member_list_mode_members">"Liikmed"</string>
|
||||
<plurals name="screen_room_member_list_pending_header_title">
|
||||
<item quantity="one">"%1$d saatis kutse"</item>
|
||||
<item quantity="other">"%1$d saatis kutse"</item>
|
||||
</plurals>
|
||||
<string name="screen_room_member_list_pending_status">"Ootel"</string>
|
||||
<string name="screen_room_member_list_role_administrator">"Peakasutajad"</string>
|
||||
<string name="screen_room_member_list_role_moderator">"Moderaatorid"</string>
|
||||
|
|
@ -133,6 +137,7 @@ Me ei soovita krüptimise kasutamist selliste avalike jututubade puhul, millega
|
|||
<string name="screen_security_and_privacy_encryption_toggle_title">"Võta läbiv krüptimine kasutusele"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Kõik võivad jututoaga liituda"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Kõik"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Halda kogukondi"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Liituda saab vaid kutse olemasolul"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Vaid kutsega"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Ligipääs"</string>
|
||||
|
|
|
|||
|
|
@ -141,9 +141,13 @@ Nous ne recommandons pas d’activer le chiffrement pour les salons que tout le
|
|||
<string name="screen_security_and_privacy_encryption_toggle_title">"Activer le chiffrement de bout en bout"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Tout le monde peut rejoindre."</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Tout le monde"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer">"Choisissez les espaces dont les membres peuvent rejoindre ce salon sans invitation. %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Gérer les espaces"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Seules les personnes invitées peuvent rejoindre."</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Sur invitation uniquement"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Accès"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_multiple_parents_description">"Toute personne se trouvant dans un espace autorisé peut joindre le salon."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_single_parent_description">"Toute personne de l’espace %1$s peut joindre le salon."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Membres de l’espace"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_unavailable_description">"Les Espaces ne sont pas encore supportés"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"Vous aurez besoin d’une adresse pour le rendre visible dans l’annuaire public."</string>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_edit_room_address_room_address_section_footer">"Budete potrebovať adresu miestnosti, aby bola viditeľná v adresári."</string>
|
||||
<string name="screen_edit_room_address_title">"Adresa miestnosti"</string>
|
||||
<string name="screen_edit_room_address_room_address_section_footer">"Budete potrebovať adresu, aby sa zobrazovala vo verejnom adresári."</string>
|
||||
<string name="screen_edit_room_address_title">"Upraviť adresu"</string>
|
||||
<string name="screen_notification_settings_edit_failed_updating_default_mode">"Pri aktualizácii nastavenia oznámenia došlo k chybe."</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Váš domovský server nepodporuje túto možnosť v šifrovaných miestnostiach, v niektorých miestnostiach nemusíte dostať upozornenie."</string>
|
||||
<string name="screen_polls_history_title">"Ankety"</string>
|
||||
<string name="screen_room_change_permissions_administrators">"Iba správcovia"</string>
|
||||
<string name="screen_room_change_permissions_administrators">"Správca"</string>
|
||||
<string name="screen_room_change_permissions_ban_people">"Zakázať ľudí"</string>
|
||||
<string name="screen_room_change_permissions_delete_messages">"Odstrániť správy"</string>
|
||||
<string name="screen_room_change_permissions_invite_people">"Pozvite ľudí a prijmite žiadosti o pripojenie"</string>
|
||||
<string name="screen_room_change_permissions_everyone">"Člen"</string>
|
||||
<string name="screen_room_change_permissions_invite_people">"Pozvať ľudí"</string>
|
||||
<string name="screen_room_change_permissions_member_moderation">"Spravovať členov"</string>
|
||||
<string name="screen_room_change_permissions_messages_and_content">"Správy a obsah"</string>
|
||||
<string name="screen_room_change_permissions_moderators">"Správcovia a moderátori"</string>
|
||||
<string name="screen_room_change_permissions_remove_people">"Odstrániť ľudí a odmietnuť žiadosti o pripojenie"</string>
|
||||
<string name="screen_room_change_permissions_moderators">"Moderátor"</string>
|
||||
<string name="screen_room_change_permissions_remove_people">"Odstrániť ľudí"</string>
|
||||
<string name="screen_room_change_permissions_room_avatar">"Zmeniť obrázok miestnosti"</string>
|
||||
<string name="screen_room_change_permissions_room_details">"Upraviť miestnosť"</string>
|
||||
<string name="screen_room_change_permissions_room_details">"Upraviť podrobnosti"</string>
|
||||
<string name="screen_room_change_permissions_room_name">"Zmeniť názov miestnosti"</string>
|
||||
<string name="screen_room_change_permissions_room_topic">"Zmeniť tému miestnosti"</string>
|
||||
<string name="screen_room_change_permissions_send_messages">"Odoslať správy"</string>
|
||||
|
|
@ -40,7 +42,7 @@
|
|||
<string name="screen_room_details_badge_encrypted">"Zašifrované"</string>
|
||||
<string name="screen_room_details_badge_not_encrypted">"Nešifrované"</string>
|
||||
<string name="screen_room_details_badge_public">"Verejná miestnosť"</string>
|
||||
<string name="screen_room_details_edit_room_title">"Upraviť miestnosť"</string>
|
||||
<string name="screen_room_details_edit_room_title">"Upraviť podrobnosti"</string>
|
||||
<string name="screen_room_details_edition_error">"Vyskytla sa neznáma chyba a informácie nebolo možné zmeniť."</string>
|
||||
<string name="screen_room_details_edition_error_title">"Nepodarilo sa aktualizovať miestnosť"</string>
|
||||
<string name="screen_room_details_encryption_enabled_subtitle">"Správy sú zabezpečené zámkami. Jedine vy a príjemcovia máte jedinečné kľúče na ich odomknutie."</string>
|
||||
|
|
@ -69,6 +71,13 @@
|
|||
<string name="screen_room_details_topic_title">"Téma"</string>
|
||||
<string name="screen_room_details_updating_room">"Aktualizácia miestnosti…"</string>
|
||||
<string name="screen_room_member_list_banned_empty">"Neexistujú žiadni zablokovaní používatelia."</string>
|
||||
<plurals name="screen_room_member_list_banned_header_title">
|
||||
<item quantity="one">"%1$d zakázaný"</item>
|
||||
<item quantity="few">"%1$d zakázaní"</item>
|
||||
<item quantity="other">"%1$d zakázaných"</item>
|
||||
</plurals>
|
||||
<string name="screen_room_member_list_empty_search_subtitle">"Skontrolujte preklepy alebo skúste nové vyhľadávanie"</string>
|
||||
<string name="screen_room_member_list_empty_search_title">"Žiadne výsledky pre „%1$s“"</string>
|
||||
<plurals name="screen_room_member_list_header_title">
|
||||
<item quantity="one">"%1$d osoba"</item>
|
||||
<item quantity="few">"%1$d osoby"</item>
|
||||
|
|
@ -81,8 +90,14 @@
|
|||
<string name="screen_room_member_list_manage_member_unban_title">"Zrušiť zákaz prístupu do miestnosti"</string>
|
||||
<string name="screen_room_member_list_mode_banned">"Zakázaní"</string>
|
||||
<string name="screen_room_member_list_mode_members">"Členovia"</string>
|
||||
<string name="screen_room_member_list_role_administrator">"Iba správcovia"</string>
|
||||
<string name="screen_room_member_list_role_moderator">"Správcovia a moderátori"</string>
|
||||
<plurals name="screen_room_member_list_pending_header_title">
|
||||
<item quantity="one">"%1$d pozvaný"</item>
|
||||
<item quantity="few">"%1$d pozvaní"</item>
|
||||
<item quantity="other">"%1$d pozvaných"</item>
|
||||
</plurals>
|
||||
<string name="screen_room_member_list_pending_status">"Čaká na schválenie"</string>
|
||||
<string name="screen_room_member_list_role_administrator">"Správca"</string>
|
||||
<string name="screen_room_member_list_role_moderator">"Moderátor"</string>
|
||||
<string name="screen_room_member_list_role_owner">"Vlastník"</string>
|
||||
<string name="screen_room_member_list_room_members_header_title">"Členovia miestnosti"</string>
|
||||
<string name="screen_room_member_list_unbanning_user">"Zrušenie zákazu %1$s"</string>
|
||||
|
|
@ -109,14 +124,15 @@
|
|||
<string name="screen_room_roles_and_permissions_messages_and_content">"Správy a obsah"</string>
|
||||
<string name="screen_room_roles_and_permissions_moderators">"Moderátori"</string>
|
||||
<string name="screen_room_roles_and_permissions_owners">"Vlastníci"</string>
|
||||
<string name="screen_room_roles_and_permissions_permissions_header">"Povolenia"</string>
|
||||
<string name="screen_room_roles_and_permissions_reset">"Obnoviť povolenia"</string>
|
||||
<string name="screen_room_roles_and_permissions_reset_confirm_description">"Po obnovení oprávnení prídete o aktuálne nastavenia."</string>
|
||||
<string name="screen_room_roles_and_permissions_reset_confirm_title">"Obnoviť oprávnenia?"</string>
|
||||
<string name="screen_room_roles_and_permissions_roles_header">"Roly"</string>
|
||||
<string name="screen_room_roles_and_permissions_room_details">"Podrobnosti o miestnosti"</string>
|
||||
<string name="screen_room_roles_and_permissions_title">"Roly a povolenia"</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Pridať adresu miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Ktokoľvek môže požiadať o pripojenie do miestnosti, ale správca alebo moderátor bude musieť žiadosť prijať."</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Pridať adresu"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Všetci musia požiadať o prístup."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_title">"Požiadať o pripojenie"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Áno, povoliť šifrovanie"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Po aktivácii nie je možné zakázať šifrovanie pre miestnosť. História správ bude viditeľná len pre členov miestnosti, odkedy boli pozvaní alebo keď vstúpili do miestnosti.
|
||||
|
|
@ -126,17 +142,22 @@ To môže brániť správnemu fungovaniu robotov a premostení. Neodporúčame p
|
|||
<string name="screen_security_and_privacy_encryption_section_footer">"Po zapnutí už šifrovanie nie je možné vypnúť."</string>
|
||||
<string name="screen_security_and_privacy_encryption_section_header">"Šifrovanie"</string>
|
||||
<string name="screen_security_and_privacy_encryption_toggle_title">"Povoliť end-to-end šifrovanie"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Ktokoľvek môže nájsť a pripojiť sa"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Pripojiť sa môže ktokoľvek."</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Ktokoľvek"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Ľudia sa môžu pripojiť len vtedy, ak sú pozvaní"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer">"Vyberte, ktorých členovia priestorov sa môžu pripojiť k tejto miestnosti bez pozvánky. %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Spravovať priestory"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Pripojiť sa môžu iba pozvaní ľudia."</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Iba na pozvánku"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Prístup do miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Prístup"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_multiple_parents_description">"Ktokoľvek v povolených priestoroch sa môže pripojiť."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_single_parent_description">"Ktokoľvek v %1$s sa môže pripojiť."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Členovia priestoru"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_unavailable_description">"Priestory momentálne nie sú podporované"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"Budete potrebovať adresu miestnosti, aby bola viditeľná v adresári."</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_header">"Adresa miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"Budete potrebovať adresu, aby sa zobrazovala vo verejnom adresári."</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_header">"Adresa"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Umožniť vyhľadanie tejto miestnosti v adresári verejných miestností %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Viditeľné v adresári verejných miestností"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_description">"Umožniť nájdenie vyhľadávaním vo verejnom adresári."</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Viditeľné vo verejnom adresári"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Ktokoľvek"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_header">"Kto môže čítať históriu"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Len pre členov, odkedy boli pozvaní"</string>
|
||||
|
|
@ -144,6 +165,7 @@ To môže brániť správnemu fungovaniu robotov a premostení. Neodporúčame p
|
|||
<string name="screen_security_and_privacy_room_publishing_section_footer">"Adresy miestností predstavujú spôsoby, ako nájsť a získať prístup k miestnostiam. To tiež zaisťuje, že môžete jednoducho zdieľať svoju miestnosť s ostatnými.
|
||||
Môžete sa rozhodnúť zverejniť svoju miestnosť v adresári verejných miestností vášho domovského servera."</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_header">"Zverejnenie miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_header">"Viditeľnosť miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_footer">"Adresy sú spôsob, ako nájsť a získať prístup do miestností a priestorov. To tiež zabezpečuje, že ich môžete jednoducho zdieľať s ostatnými."</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_header">"Viditeľnosť"</string>
|
||||
<string name="screen_security_and_privacy_title">"Bezpečnosť a súkromie"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
<string name="screen_room_details_share_room_title">"Share room"</string>
|
||||
<string name="screen_room_details_title">"Room info"</string>
|
||||
<string name="screen_room_details_topic_title">"Topic"</string>
|
||||
<string name="screen_room_details_updating_room">"Updating room…"</string>
|
||||
<string name="screen_room_details_updating_room">"Updating details…"</string>
|
||||
<string name="screen_room_member_list_banned_empty">"There are no banned users."</string>
|
||||
<plurals name="screen_room_member_list_banned_header_title">
|
||||
<item quantity="one">"%1$d Banned"</item>
|
||||
|
|
@ -129,8 +129,10 @@
|
|||
<string name="screen_room_roles_and_permissions_room_details">"Room details"</string>
|
||||
<string name="screen_room_roles_and_permissions_title">"Roles & permissions"</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Add address"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_multiple_spaces_members_option_description">"Anyone in authorized spaces can join, but everyone else must request access."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Everyone must request access."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_title">"Ask to join"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_single_space_members_option_description">"Anyone in %1$s can join, but everyone else must request access."</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Yes, enable encryption"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Once enabled, encryption for a room cannot be disabled, Message history will only be visible for room members since they were invited or since they joined the room.
|
||||
No one besides the room members will be able to read messages. This may prevent bots and bridges to work correctly.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import io.element.android.libraries.matrix.ui.media.AvatarAction
|
|||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -151,7 +151,7 @@ class RoomDetailsEditPresenter(
|
|||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> {
|
||||
temporaryUriDeleter.delete(roomAvatarUriEdited?.toUri())
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
<string name="screen_room_details_edit_room_title">"Edit details"</string>
|
||||
<string name="screen_room_details_edition_error">"There was an unknown error and the information couldn\'t be changed."</string>
|
||||
<string name="screen_room_details_edition_error_title">"Unable to update room"</string>
|
||||
<string name="screen_room_details_updating_room">"Updating room…"</string>
|
||||
<string name="screen_room_details_updating_room">"Updating details…"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.roommembermoderation.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
|
||||
data class RoomMemberModerationPermissions(
|
||||
val canKick: Boolean,
|
||||
val canBan: Boolean,
|
||||
) {
|
||||
companion object {
|
||||
val DEFAULT = RoomMemberModerationPermissions(
|
||||
canKick = false,
|
||||
canBan = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomPermissions.roomMemberModerationPermissions(): RoomMemberModerationPermissions {
|
||||
return RoomMemberModerationPermissions(
|
||||
canKick = canOwnUserKick(),
|
||||
canBan = canOwnUserBan(),
|
||||
)
|
||||
}
|
||||
|
|
@ -12,8 +12,7 @@ import androidx.compose.runtime.Immutable
|
|||
|
||||
@Immutable
|
||||
interface RoomMemberModerationState {
|
||||
val canKick: Boolean
|
||||
val canBan: Boolean
|
||||
val permissions: RoomMemberModerationPermissions
|
||||
val eventSink: (RoomMemberModerationEvents) -> Unit
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ package io.element.android.features.roommembermoderation.impl
|
|||
|
||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class InternalRoomMemberModerationState(
|
||||
override val canKick: Boolean,
|
||||
override val canBan: Boolean,
|
||||
override val permissions: RoomMemberModerationPermissions,
|
||||
val selectedUser: MatrixUser?,
|
||||
val actions: ImmutableList<ModerationActionState>,
|
||||
val kickUserAsyncAction: AsyncAction<Unit>,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import io.element.android.features.roommembermoderation.api.ModerationAction
|
||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
|
@ -83,8 +84,7 @@ fun anAlice() = MatrixUser(
|
|||
)
|
||||
|
||||
fun aRoomMembersModerationState(
|
||||
canKick: Boolean = false,
|
||||
canBan: Boolean = false,
|
||||
permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions.DEFAULT,
|
||||
selectedUser: MatrixUser? = null,
|
||||
actions: List<ModerationActionState> = emptyList(),
|
||||
kickUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
|
|
@ -92,8 +92,7 @@ fun aRoomMembersModerationState(
|
|||
unbanUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
eventSink: (RoomMemberModerationEvents) -> Unit = {},
|
||||
) = InternalRoomMemberModerationState(
|
||||
canKick = canKick,
|
||||
canBan = canBan,
|
||||
permissions = permissions,
|
||||
selectedUser = selectedUser,
|
||||
actions = actions.toImmutableList(),
|
||||
kickUserAsyncAction = kickUserAsyncAction,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ import im.vector.app.features.analytics.plan.RoomModeration
|
|||
import io.element.android.features.roommembermoderation.api.ModerationAction
|
||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
||||
import io.element.android.features.roommembermoderation.api.roomMemberModerationPermissions
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
|
|
@ -55,11 +57,8 @@ class RoomMemberModerationPresenter(
|
|||
override fun present(): RoomMemberModerationState {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
||||
val permissions by room.permissionsAsState(Permissions()) { perms ->
|
||||
Permissions(
|
||||
canKick = perms.canOwnUserKick(),
|
||||
canBan = perms.canOwnUserBan(),
|
||||
)
|
||||
val permissions by room.permissionsAsState(RoomMemberModerationPermissions.DEFAULT) { perms ->
|
||||
perms.roomMemberModerationPermissions()
|
||||
}
|
||||
val currentUserMemberPowerLevel = room.userPowerLevelAsState(syncUpdateFlow.value)
|
||||
|
||||
|
|
@ -136,8 +135,7 @@ class RoomMemberModerationPresenter(
|
|||
}
|
||||
|
||||
return InternalRoomMemberModerationState(
|
||||
canKick = permissions.canKick,
|
||||
canBan = permissions.canBan,
|
||||
permissions = permissions,
|
||||
selectedUser = selectedUser,
|
||||
actions = moderationActions.value,
|
||||
kickUserAsyncAction = kickUserAsyncAction.value,
|
||||
|
|
@ -149,7 +147,7 @@ class RoomMemberModerationPresenter(
|
|||
|
||||
private fun computeModerationActions(
|
||||
member: RoomMember?,
|
||||
permissions: Permissions,
|
||||
permissions: RoomMemberModerationPermissions,
|
||||
currentUserMemberPowerLevel: Long,
|
||||
): ImmutableList<ModerationActionState> {
|
||||
return buildList {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.google.common.truth.Truth.assertThat
|
|||
import io.element.android.features.roommembermoderation.api.ModerationAction
|
||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions
|
||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
|
|
@ -49,8 +50,7 @@ class RoomMemberModerationPresenterTest {
|
|||
val room = aJoinedRoom()
|
||||
createRoomMemberModerationPresenter(room = room).test {
|
||||
val initialState = awaitState()
|
||||
assertThat(initialState.canKick).isFalse()
|
||||
assertThat(initialState.canBan).isFalse()
|
||||
assertThat(initialState.permissions).isEqualTo(RoomMemberModerationPermissions.DEFAULT)
|
||||
assertThat(initialState.selectedUser).isNull()
|
||||
assertThat(initialState.banUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)
|
||||
assertThat(initialState.kickUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ private fun RoomAccessSection(
|
|||
Text(text = stringResource(R.string.screen_security_and_privacy_room_access_space_members_option_unavailable_description))
|
||||
},
|
||||
trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.SpaceMember, enabled = false),
|
||||
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Workspace())),
|
||||
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Space())),
|
||||
enabled = false,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Me ei soovita krüptimise kasutamist selliste avalike jututubade puhul, millega
|
|||
<string name="screen_security_and_privacy_encryption_toggle_title">"Võta läbiv krüptimine kasutusele"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Kõik võivad jututoaga liituda"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Kõik"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Halda kogukondi"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Liituda saab vaid kutse olemasolul"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Vaid kutsega"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Ligipääs"</string>
|
||||
|
|
|
|||
|
|
@ -15,9 +15,13 @@ Nous ne recommandons pas d’activer le chiffrement pour les salons que tout le
|
|||
<string name="screen_security_and_privacy_encryption_toggle_title">"Activer le chiffrement de bout en bout"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Tout le monde peut rejoindre."</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Tout le monde"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer">"Choisissez les espaces dont les membres peuvent rejoindre ce salon sans invitation. %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Gérer les espaces"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Seules les personnes invitées peuvent rejoindre."</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Sur invitation uniquement"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Accès"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_multiple_parents_description">"Toute personne se trouvant dans un espace autorisé peut joindre le salon."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_single_parent_description">"Toute personne de l’espace %1$s peut joindre le salon."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Membres de l’espace"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_unavailable_description">"Les Espaces ne sont pas encore supportés"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"Vous aurez besoin d’une adresse pour le rendre visible dans l’annuaire public."</string>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_edit_room_address_room_address_section_footer">"Budete potrebovať adresu miestnosti, aby bola viditeľná v adresári."</string>
|
||||
<string name="screen_edit_room_address_title">"Adresa miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Pridať adresu miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Ktokoľvek môže požiadať o pripojenie do miestnosti, ale správca alebo moderátor bude musieť žiadosť prijať."</string>
|
||||
<string name="screen_edit_room_address_room_address_section_footer">"Budete potrebovať adresu, aby sa zobrazovala vo verejnom adresári."</string>
|
||||
<string name="screen_edit_room_address_title">"Upraviť adresu"</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Pridať adresu"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Všetci musia požiadať o prístup."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_title">"Požiadať o pripojenie"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Áno, povoliť šifrovanie"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Po aktivácii nie je možné zakázať šifrovanie pre miestnosť. História správ bude viditeľná len pre členov miestnosti, odkedy boli pozvaní alebo keď vstúpili do miestnosti.
|
||||
|
|
@ -13,17 +13,22 @@ To môže brániť správnemu fungovaniu robotov a premostení. Neodporúčame p
|
|||
<string name="screen_security_and_privacy_encryption_section_footer">"Po zapnutí už šifrovanie nie je možné vypnúť."</string>
|
||||
<string name="screen_security_and_privacy_encryption_section_header">"Šifrovanie"</string>
|
||||
<string name="screen_security_and_privacy_encryption_toggle_title">"Povoliť end-to-end šifrovanie"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Ktokoľvek môže nájsť a pripojiť sa"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Pripojiť sa môže ktokoľvek."</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Ktokoľvek"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Ľudia sa môžu pripojiť len vtedy, ak sú pozvaní"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer">"Vyberte, ktorých členovia priestorov sa môžu pripojiť k tejto miestnosti bez pozvánky. %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Spravovať priestory"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Pripojiť sa môžu iba pozvaní ľudia."</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Iba na pozvánku"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Prístup do miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Prístup"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_multiple_parents_description">"Ktokoľvek v povolených priestoroch sa môže pripojiť."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_single_parent_description">"Ktokoľvek v %1$s sa môže pripojiť."</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Členovia priestoru"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_unavailable_description">"Priestory momentálne nie sú podporované"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"Budete potrebovať adresu miestnosti, aby bola viditeľná v adresári."</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_header">"Adresa miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"Budete potrebovať adresu, aby sa zobrazovala vo verejnom adresári."</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_header">"Adresa"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Umožniť vyhľadanie tejto miestnosti v adresári verejných miestností %1$s"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Viditeľné v adresári verejných miestností"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_description">"Umožniť nájdenie vyhľadávaním vo verejnom adresári."</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Viditeľné vo verejnom adresári"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Ktokoľvek"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_header">"Kto môže čítať históriu"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Len pre členov, odkedy boli pozvaní"</string>
|
||||
|
|
@ -31,6 +36,7 @@ To môže brániť správnemu fungovaniu robotov a premostení. Neodporúčame p
|
|||
<string name="screen_security_and_privacy_room_publishing_section_footer">"Adresy miestností predstavujú spôsoby, ako nájsť a získať prístup k miestnostiam. To tiež zaisťuje, že môžete jednoducho zdieľať svoju miestnosť s ostatnými.
|
||||
Môžete sa rozhodnúť zverejniť svoju miestnosť v adresári verejných miestností vášho domovského servera."</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_header">"Zverejnenie miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_header">"Viditeľnosť miestnosti"</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_footer">"Adresy sú spôsob, ako nájsť a získať prístup do miestností a priestorov. To tiež zabezpečuje, že ich môžete jednoducho zdieľať s ostatnými."</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_header">"Viditeľnosť"</string>
|
||||
<string name="screen_security_and_privacy_title">"Bezpečnosť a súkromie"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
<string name="screen_edit_room_address_room_address_section_footer">"You’ll need an address in order to make it visible in the public directory."</string>
|
||||
<string name="screen_edit_room_address_title">"Edit address"</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Add address"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_multiple_spaces_members_option_description">"Anyone in authorized spaces can join, but everyone else must request access."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Everyone must request access."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_title">"Ask to join"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_single_space_members_option_description">"Anyone in %1$s can join, but everyone else must request access."</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Yes, enable encryption"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Once enabled, encryption for a room cannot be disabled, Message history will only be visible for room members since they were invited or since they joined the room.
|
||||
No one besides the room members will be able to read messages. This may prevent bots and bridges to work correctly.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[versions]
|
||||
# Project
|
||||
android_gradle_plugin = "8.13.1"
|
||||
android_gradle_plugin = "8.13.2"
|
||||
# When updateing this, please also update the version in the file ./idea/kotlinc.xml
|
||||
kotlin = "2.2.20"
|
||||
kotlinpoet = "2.2.0"
|
||||
|
|
@ -18,7 +18,7 @@ constraintlayout_compose = "1.1.1"
|
|||
lifecycle = "2.9.2"
|
||||
activity = "1.11.0"
|
||||
media3 = "1.8.0"
|
||||
camera = "1.5.1"
|
||||
camera = "1.5.2"
|
||||
work = "2.11.0"
|
||||
|
||||
# Compose
|
||||
|
|
@ -41,7 +41,7 @@ serialization_json = "1.9.0"
|
|||
#other
|
||||
coil = "3.3.0"
|
||||
# Rollback to 1.0.4, 1.0.5 has this issue: https://github.com/airbnb/Showkase/issues/420
|
||||
showkase = "1.0.4"
|
||||
showkase = "1.0.5"
|
||||
appyx = "1.7.1"
|
||||
sqldelight = "2.2.1"
|
||||
wysiwyg = "2.40.0"
|
||||
|
|
@ -52,7 +52,7 @@ haze = "1.6.10"
|
|||
dependencyAnalysis = "3.5.1"
|
||||
|
||||
# DI
|
||||
metro = "0.8.1"
|
||||
metro = "0.8.2"
|
||||
|
||||
# Auto service
|
||||
autoservice = "1.1.1"
|
||||
|
|
@ -160,7 +160,7 @@ test_corektx = { module = "androidx.test:core-ktx", version.ref = "test_core" }
|
|||
test_arch_core = "androidx.arch.core:core-testing:2.2.0"
|
||||
test_junit = "junit:junit:4.13.2"
|
||||
test_runner = "androidx.test:runner:1.7.0"
|
||||
test_mockk = "io.mockk:mockk:1.14.6"
|
||||
test_mockk = "io.mockk:mockk:1.14.7"
|
||||
test_konsist = "com.lemonappdev:konsist:0.17.3"
|
||||
test_turbine = "app.cash.turbine:turbine:1.2.1"
|
||||
test_truth = "com.google.truth:truth:1.4.5"
|
||||
|
|
@ -177,7 +177,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version
|
|||
# https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt
|
||||
# All new features should not be implemented in the pull request that upgrades the version, developers should
|
||||
# only fix API breaks and may add some TODOs.
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.12.2"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.12.10"
|
||||
|
||||
# Others
|
||||
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
|
||||
|
|
@ -199,14 +199,14 @@ matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose",
|
|||
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
|
||||
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
|
||||
sqlcipher = "net.zetetic:sqlcipher-android:4.11.0"
|
||||
sqlcipher = "net.zetetic:sqlcipher-android:4.12.0"
|
||||
sqlite = "androidx.sqlite:sqlite-ktx:2.6.2"
|
||||
unifiedpush = "org.unifiedpush.android:connector:3.1.2"
|
||||
vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0"
|
||||
telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" }
|
||||
telephoto_flick = { module = "me.saket.telephoto:flick-android", version.ref = "telephoto" }
|
||||
statemachine = "com.freeletics.flowredux:compose:1.2.2"
|
||||
maplibre = "org.maplibre.gl:android-sdk:12.2.1"
|
||||
maplibre = "org.maplibre.gl:android-sdk:12.2.2"
|
||||
maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.2"
|
||||
maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.2"
|
||||
opusencoder = "io.element.android:opusencoder:1.2.0"
|
||||
|
|
@ -217,7 +217,7 @@ color_picker = "io.mhssn:colorpicker:1.0.0"
|
|||
|
||||
# Analytics
|
||||
posthog = "com.posthog:posthog-android:3.26.0"
|
||||
sentry = "io.sentry:sentry-android:8.27.1"
|
||||
sentry = "io.sentry:sentry-android:8.28.0"
|
||||
# main branch can be tested replacing the version with main-SNAPSHOT
|
||||
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.29.2"
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ fun Activity.openUrlInChromeCustomTab(
|
|||
})
|
||||
}
|
||||
.launchUrl(this, url.toUri())
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
openUrlInExternalApp(url)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ fun String.hash() = try {
|
|||
digest.digest()
|
||||
.joinToString("") { String.format(Locale.ROOT, "%02X", it) }
|
||||
.lowercase(Locale.ROOT)
|
||||
} catch (exc: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// Should not happen, but just in case
|
||||
hashCode().toString()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ fun Context.getApplicationLabel(packageName: String): String {
|
|||
return try {
|
||||
val ai = packageManager.getApplicationInfoCompat(packageName, 0)
|
||||
packageManager.getApplicationLabel(ai).toString()
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
} catch (_: PackageManager.NameNotFoundException) {
|
||||
packageName
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ fun Context.startNotificationSettingsIntent(
|
|||
} else {
|
||||
startActivity(intent)
|
||||
}
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
toast(noActivityFoundMessage)
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ fun Context.openAppSettingsPage(
|
|||
data = Uri.fromParts("package", packageName, null)
|
||||
}
|
||||
)
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
toast(noActivityFoundMessage)
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ fun Context.startInstallFromSourceIntent(
|
|||
.setData("package:$packageName".toUri())
|
||||
try {
|
||||
activityResultLauncher.launch(intent)
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
toast(noActivityFoundMessage)
|
||||
}
|
||||
}
|
||||
|
|
@ -157,7 +157,7 @@ fun Context.startSharePlainTextIntent(
|
|||
} else {
|
||||
startActivity(intent)
|
||||
}
|
||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
toast(noActivityFoundMessage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.androidutils.text
|
||||
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
fun String.urlEncoded(charset: Charset = Charsets.UTF_8): String = URLEncoder.encode(this, charset.name())
|
||||
fun String.urlDecoded(charset: Charset = Charsets.UTF_8): String = URLDecoder.decode(this, charset.name())
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4c0f668bcd8d511bc80daa1320bdcc1fe6a8f82cd53d91dbab9ffd0d09d72934
|
||||
size 210897
|
||||
oid sha256:fc758c149db501d0ac5eb235cca1d63b67230aae40356e7ccca4c9d481a9ce17
|
||||
size 216981
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:85eb26db4406a921c45f143c8ccb59214b2b70cb19359fe9e7eeeecfb733ca74
|
||||
size 222592
|
||||
oid sha256:db230bfe3d51527959d2a4f7c64a8cc79209dcfb752f077f84c0f5058d94f0bd
|
||||
size 228829
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9acd4fdec8deddbf723184ce5f373ed54e64a68d5b572419059e3feab3a508be
|
||||
size 223915
|
||||
oid sha256:4c6cd3ad1978c6f4e07d62b1edd08c5f32b3c498934d25af43932c50ef309fe0
|
||||
size 230519
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:578e9b5a38791e2686a7b9ba5c461eb1d1fb29dfbe950bf46c113ad75ceac175
|
||||
size 327758
|
||||
oid sha256:c846cd10b83361c368bdbb31ed6220cc22693c3cbf52791fb369841af1e9ea48
|
||||
size 327701
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4cab40fc0506c8f2a2efafb1199e85f1da3ebacb49b176e9105e3f95175f85ee
|
||||
size 325565
|
||||
oid sha256:05b35fedbd53dec2cc5c4c211a8db1a56055963de69425ddae2cab5aff7e3e75
|
||||
size 325750
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:174f9d4ee70a29c0c8c2a01a15daeb14281530678ff7d7fb19a208bfd789533a
|
||||
size 309210
|
||||
oid sha256:8d98e64eda5d6333067ccc599e99636f618331397207bb7534595e2756edb75e
|
||||
size 309312
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7598b98462c015f2bf74b3ea3ad95fc0220b2efb9bb81ac56025cf6a158e3f8a
|
||||
size 308976
|
||||
oid sha256:5ccbf1234065b182939f001eb65eca0a62adae41a2d91ef0307d27b059407178
|
||||
size 309084
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9f2584ffd8e3a4746937cdc3e0baf04a89839061f15d00342e6150c21bf13228
|
||||
size 83228
|
||||
oid sha256:1d4f46c82f1504a983885a7d177900cd6d6f7729dce6851520cd7e471870ad2d
|
||||
size 84955
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fb1854bf504fcab7752c4d51f5fc6cae65511581fb64a1adcdcf6f912d4aa15a
|
||||
size 89148
|
||||
oid sha256:e2c1a78a88fad99c1fd9bc29d802ee8c2bdefec89626cd700c73f4909738aeb5
|
||||
size 91022
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,12 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* !!! WARNING !!!
|
||||
*
|
||||
|
|
@ -14,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
|
@ -185,6 +181,9 @@ object CompoundIcons {
|
|||
@Composable fun ErrorSolid(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_error_solid)
|
||||
}
|
||||
@Composable fun ExitFullScreen(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_exit_full_screen)
|
||||
}
|
||||
@Composable fun Expand(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_expand)
|
||||
}
|
||||
|
|
@ -218,6 +217,9 @@ object CompoundIcons {
|
|||
@Composable fun Forward(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_forward)
|
||||
}
|
||||
@Composable fun FullScreen(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_full_screen)
|
||||
}
|
||||
@Composable fun Grid(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_grid)
|
||||
}
|
||||
|
|
@ -296,6 +298,9 @@ object CompoundIcons {
|
|||
@Composable fun Leave(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_leave)
|
||||
}
|
||||
@Composable fun LeftPanelClose(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_left_panel_close)
|
||||
}
|
||||
@Composable fun Link(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_link)
|
||||
}
|
||||
|
|
@ -503,6 +508,12 @@ object CompoundIcons {
|
|||
@Composable fun SignOut(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_sign_out)
|
||||
}
|
||||
@Composable fun Space(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_space)
|
||||
}
|
||||
@Composable fun SpaceSolid(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_space_solid)
|
||||
}
|
||||
@Composable fun Spinner(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_spinner)
|
||||
}
|
||||
|
|
@ -620,12 +631,6 @@ object CompoundIcons {
|
|||
@Composable fun Windows(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_windows)
|
||||
}
|
||||
@Composable fun Workspace(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_workspace)
|
||||
}
|
||||
@Composable fun WorkspaceSolid(): ImageVector {
|
||||
return ImageVector.vectorResource(R.drawable.ic_compound_workspace_solid)
|
||||
}
|
||||
|
||||
val all @Composable get() = persistentListOf<ImageVector>(
|
||||
Admin(),
|
||||
|
|
@ -681,6 +686,7 @@ object CompoundIcons {
|
|||
EndCall(),
|
||||
Error(),
|
||||
ErrorSolid(),
|
||||
ExitFullScreen(),
|
||||
Expand(),
|
||||
Explore(),
|
||||
ExportArchive(),
|
||||
|
|
@ -692,6 +698,7 @@ object CompoundIcons {
|
|||
Files(),
|
||||
Filter(),
|
||||
Forward(),
|
||||
FullScreen(),
|
||||
Grid(),
|
||||
Group(),
|
||||
Guest(),
|
||||
|
|
@ -718,6 +725,7 @@ object CompoundIcons {
|
|||
Keyboard(),
|
||||
Labs(),
|
||||
Leave(),
|
||||
LeftPanelClose(),
|
||||
Link(),
|
||||
Linux(),
|
||||
ListBulleted(),
|
||||
|
|
@ -787,6 +795,8 @@ object CompoundIcons {
|
|||
Shield(),
|
||||
Sidebar(),
|
||||
SignOut(),
|
||||
Space(),
|
||||
SpaceSolid(),
|
||||
Spinner(),
|
||||
Spotlight(),
|
||||
SpotlightView(),
|
||||
|
|
@ -826,8 +836,6 @@ object CompoundIcons {
|
|||
Warning(),
|
||||
WebBrowser(),
|
||||
Windows(),
|
||||
Workspace(),
|
||||
WorkspaceSolid(),
|
||||
)
|
||||
|
||||
val allResIds get() = persistentListOf(
|
||||
|
|
@ -884,6 +892,7 @@ object CompoundIcons {
|
|||
R.drawable.ic_compound_end_call,
|
||||
R.drawable.ic_compound_error,
|
||||
R.drawable.ic_compound_error_solid,
|
||||
R.drawable.ic_compound_exit_full_screen,
|
||||
R.drawable.ic_compound_expand,
|
||||
R.drawable.ic_compound_explore,
|
||||
R.drawable.ic_compound_export_archive,
|
||||
|
|
@ -895,6 +904,7 @@ object CompoundIcons {
|
|||
R.drawable.ic_compound_files,
|
||||
R.drawable.ic_compound_filter,
|
||||
R.drawable.ic_compound_forward,
|
||||
R.drawable.ic_compound_full_screen,
|
||||
R.drawable.ic_compound_grid,
|
||||
R.drawable.ic_compound_group,
|
||||
R.drawable.ic_compound_guest,
|
||||
|
|
@ -921,6 +931,7 @@ object CompoundIcons {
|
|||
R.drawable.ic_compound_keyboard,
|
||||
R.drawable.ic_compound_labs,
|
||||
R.drawable.ic_compound_leave,
|
||||
R.drawable.ic_compound_left_panel_close,
|
||||
R.drawable.ic_compound_link,
|
||||
R.drawable.ic_compound_linux,
|
||||
R.drawable.ic_compound_list_bulleted,
|
||||
|
|
@ -990,6 +1001,8 @@ object CompoundIcons {
|
|||
R.drawable.ic_compound_shield,
|
||||
R.drawable.ic_compound_sidebar,
|
||||
R.drawable.ic_compound_sign_out,
|
||||
R.drawable.ic_compound_space,
|
||||
R.drawable.ic_compound_space_solid,
|
||||
R.drawable.ic_compound_spinner,
|
||||
R.drawable.ic_compound_spotlight,
|
||||
R.drawable.ic_compound_spotlight_view,
|
||||
|
|
@ -1029,7 +1042,5 @@ object CompoundIcons {
|
|||
R.drawable.ic_compound_warning,
|
||||
R.drawable.ic_compound_web_browser,
|
||||
R.drawable.ic_compound_windows,
|
||||
R.drawable.ic_compound_workspace,
|
||||
R.drawable.ic_compound_workspace_solid,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
|
||||
/**
|
||||
* !!! WARNING !!!
|
||||
*
|
||||
|
|
@ -21,8 +12,10 @@ import androidx.compose.ui.graphics.Color
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* This class holds all the semantic tokens of the Compound theme.
|
||||
|
|
@ -50,17 +43,21 @@ data class SemanticColors(
|
|||
val bgActionSecondaryPressed: Color,
|
||||
/** Background colour for secondary actions. State: Rest. */
|
||||
val bgActionSecondaryRest: Color,
|
||||
/** Background colour for tertiary actions. State: Hover */
|
||||
val bgActionTertiaryHovered: Color,
|
||||
/** Background colour for tertiary actions. State: Rest */
|
||||
val bgActionTertiaryRest: Color,
|
||||
/** Background colour for tertiary actions. State: Selected */
|
||||
val bgActionTertiarySelected: Color,
|
||||
/** Badge accent background colour */
|
||||
val bgBadgeAccent: Color,
|
||||
/** Badge default background colour */
|
||||
val bgBadgeDefault: Color,
|
||||
/** Badge info background colour */
|
||||
val bgBadgeInfo: Color,
|
||||
/** Default global background for the user interface.
|
||||
Elevation: Default (Level 0) */
|
||||
/** Default global background for the user interface. Elevation: Default (Level 0) */
|
||||
val bgCanvasDefault: Color,
|
||||
/** Default global background for the user interface.
|
||||
Elevation: Level 1. */
|
||||
/** Default global background for the user interface. Elevation: Level 1. */
|
||||
val bgCanvasDefaultLevel1: Color,
|
||||
/** Default background for disabled elements. There's no minimum contrast requirement. */
|
||||
val bgCanvasDisabled: Color,
|
||||
|
|
@ -86,14 +83,11 @@ Elevation: Level 1. */
|
|||
val bgDecorative6: Color,
|
||||
/** Subtle background colour for informational elements. State: Rest. */
|
||||
val bgInfoSubtle: Color,
|
||||
/** Medium contrast surfaces.
|
||||
Elevation: Default (Level 2). */
|
||||
/** Medium contrast surfaces. Elevation: Default (Level 2). */
|
||||
val bgSubtlePrimary: Color,
|
||||
/** Low contrast surfaces.
|
||||
Elevation: Default (Level 1). */
|
||||
/** Low contrast surfaces. Elevation: Default (Level 1). */
|
||||
val bgSubtleSecondary: Color,
|
||||
/** Lower contrast surfaces.
|
||||
Elevation: Level 0. */
|
||||
/** Lower contrast surfaces. Elevation: Level 0. */
|
||||
val bgSubtleSecondaryLevel0: Color,
|
||||
/** Subtle background colour for success state elements. State: Rest. */
|
||||
val bgSuccessSubtle: Color,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
|
@ -37,9 +34,12 @@ val compoundColorsDark = SemanticColors(
|
|||
bgActionSecondaryHovered = DarkColorTokens.colorAlphaGray200,
|
||||
bgActionSecondaryPressed = DarkColorTokens.colorAlphaGray300,
|
||||
bgActionSecondaryRest = DarkColorTokens.colorThemeBg,
|
||||
bgBadgeAccent = DarkColorTokens.colorAlphaGreen300,
|
||||
bgBadgeDefault = DarkColorTokens.colorAlphaGray300,
|
||||
bgBadgeInfo = DarkColorTokens.colorAlphaBlue300,
|
||||
bgActionTertiaryHovered = DarkColorTokens.colorGray300,
|
||||
bgActionTertiaryRest = DarkColorTokens.colorThemeBg,
|
||||
bgActionTertiarySelected = DarkColorTokens.colorGray400,
|
||||
bgBadgeAccent = DarkColorTokens.colorAlphaGreen500,
|
||||
bgBadgeDefault = DarkColorTokens.colorAlphaGray500,
|
||||
bgBadgeInfo = DarkColorTokens.colorAlphaBlue500,
|
||||
bgCanvasDefault = DarkColorTokens.colorThemeBg,
|
||||
bgCanvasDefaultLevel1 = DarkColorTokens.colorGray300,
|
||||
bgCanvasDisabled = DarkColorTokens.colorGray200,
|
||||
|
|
@ -89,7 +89,7 @@ val compoundColorsDark = SemanticColors(
|
|||
iconAccentTertiary = DarkColorTokens.colorGreen800,
|
||||
iconCriticalPrimary = DarkColorTokens.colorRed900,
|
||||
iconDisabled = DarkColorTokens.colorGray700,
|
||||
iconInfoPrimary = DarkColorTokens.colorBlue900,
|
||||
iconInfoPrimary = DarkColorTokens.colorBlue1100,
|
||||
iconOnSolidPrimary = DarkColorTokens.colorThemeBg,
|
||||
iconPrimary = DarkColorTokens.colorGray1400,
|
||||
iconPrimaryAlpha = DarkColorTokens.colorAlphaGray1400,
|
||||
|
|
@ -112,8 +112,8 @@ val compoundColorsDark = SemanticColors(
|
|||
textDecorative5 = DarkColorTokens.colorPink1100,
|
||||
textDecorative6 = DarkColorTokens.colorOrange1100,
|
||||
textDisabled = DarkColorTokens.colorGray800,
|
||||
textInfoPrimary = DarkColorTokens.colorBlue900,
|
||||
textLinkExternal = DarkColorTokens.colorBlue900,
|
||||
textInfoPrimary = DarkColorTokens.colorBlue1100,
|
||||
textLinkExternal = DarkColorTokens.colorBlue1100,
|
||||
textOnSolidPrimary = DarkColorTokens.colorThemeBg,
|
||||
textPrimary = DarkColorTokens.colorGray1400,
|
||||
textSecondary = DarkColorTokens.colorGray900,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
|
@ -37,9 +34,12 @@ val compoundColorsHcDark = SemanticColors(
|
|||
bgActionSecondaryHovered = DarkHcColorTokens.colorAlphaGray200,
|
||||
bgActionSecondaryPressed = DarkHcColorTokens.colorAlphaGray300,
|
||||
bgActionSecondaryRest = DarkHcColorTokens.colorThemeBg,
|
||||
bgBadgeAccent = DarkHcColorTokens.colorAlphaGreen300,
|
||||
bgBadgeDefault = DarkHcColorTokens.colorAlphaGray300,
|
||||
bgBadgeInfo = DarkHcColorTokens.colorAlphaBlue300,
|
||||
bgActionTertiaryHovered = DarkHcColorTokens.colorGray300,
|
||||
bgActionTertiaryRest = DarkHcColorTokens.colorThemeBg,
|
||||
bgActionTertiarySelected = DarkHcColorTokens.colorGray400,
|
||||
bgBadgeAccent = DarkHcColorTokens.colorAlphaGreen500,
|
||||
bgBadgeDefault = DarkHcColorTokens.colorAlphaGray500,
|
||||
bgBadgeInfo = DarkHcColorTokens.colorAlphaBlue500,
|
||||
bgCanvasDefault = DarkHcColorTokens.colorThemeBg,
|
||||
bgCanvasDefaultLevel1 = DarkHcColorTokens.colorGray300,
|
||||
bgCanvasDisabled = DarkHcColorTokens.colorGray200,
|
||||
|
|
@ -89,7 +89,7 @@ val compoundColorsHcDark = SemanticColors(
|
|||
iconAccentTertiary = DarkHcColorTokens.colorGreen800,
|
||||
iconCriticalPrimary = DarkHcColorTokens.colorRed900,
|
||||
iconDisabled = DarkHcColorTokens.colorGray700,
|
||||
iconInfoPrimary = DarkHcColorTokens.colorBlue900,
|
||||
iconInfoPrimary = DarkHcColorTokens.colorBlue1100,
|
||||
iconOnSolidPrimary = DarkHcColorTokens.colorThemeBg,
|
||||
iconPrimary = DarkHcColorTokens.colorGray1400,
|
||||
iconPrimaryAlpha = DarkHcColorTokens.colorAlphaGray1400,
|
||||
|
|
@ -112,8 +112,8 @@ val compoundColorsHcDark = SemanticColors(
|
|||
textDecorative5 = DarkHcColorTokens.colorPink1100,
|
||||
textDecorative6 = DarkHcColorTokens.colorOrange1100,
|
||||
textDisabled = DarkHcColorTokens.colorGray800,
|
||||
textInfoPrimary = DarkHcColorTokens.colorBlue900,
|
||||
textLinkExternal = DarkHcColorTokens.colorBlue900,
|
||||
textInfoPrimary = DarkHcColorTokens.colorBlue1100,
|
||||
textLinkExternal = DarkHcColorTokens.colorBlue1100,
|
||||
textOnSolidPrimary = DarkHcColorTokens.colorThemeBg,
|
||||
textPrimary = DarkHcColorTokens.colorGray1400,
|
||||
textSecondary = DarkHcColorTokens.colorGray900,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
|
@ -37,9 +34,12 @@ val compoundColorsLight = SemanticColors(
|
|||
bgActionSecondaryHovered = LightColorTokens.colorAlphaGray200,
|
||||
bgActionSecondaryPressed = LightColorTokens.colorAlphaGray300,
|
||||
bgActionSecondaryRest = LightColorTokens.colorThemeBg,
|
||||
bgBadgeAccent = LightColorTokens.colorAlphaGreen300,
|
||||
bgBadgeDefault = LightColorTokens.colorAlphaGray300,
|
||||
bgBadgeInfo = LightColorTokens.colorAlphaBlue300,
|
||||
bgActionTertiaryHovered = LightColorTokens.colorGray300,
|
||||
bgActionTertiaryRest = LightColorTokens.colorThemeBg,
|
||||
bgActionTertiarySelected = LightColorTokens.colorGray400,
|
||||
bgBadgeAccent = LightColorTokens.colorAlphaGreen400,
|
||||
bgBadgeDefault = LightColorTokens.colorAlphaGray400,
|
||||
bgBadgeInfo = LightColorTokens.colorAlphaBlue400,
|
||||
bgCanvasDefault = LightColorTokens.colorThemeBg,
|
||||
bgCanvasDefaultLevel1 = LightColorTokens.colorThemeBg,
|
||||
bgCanvasDisabled = LightColorTokens.colorGray200,
|
||||
|
|
@ -89,7 +89,7 @@ val compoundColorsLight = SemanticColors(
|
|||
iconAccentTertiary = LightColorTokens.colorGreen800,
|
||||
iconCriticalPrimary = LightColorTokens.colorRed900,
|
||||
iconDisabled = LightColorTokens.colorGray700,
|
||||
iconInfoPrimary = LightColorTokens.colorBlue900,
|
||||
iconInfoPrimary = LightColorTokens.colorBlue1100,
|
||||
iconOnSolidPrimary = LightColorTokens.colorThemeBg,
|
||||
iconPrimary = LightColorTokens.colorGray1400,
|
||||
iconPrimaryAlpha = LightColorTokens.colorAlphaGray1400,
|
||||
|
|
@ -112,8 +112,8 @@ val compoundColorsLight = SemanticColors(
|
|||
textDecorative5 = LightColorTokens.colorPink1100,
|
||||
textDecorative6 = LightColorTokens.colorOrange1100,
|
||||
textDisabled = LightColorTokens.colorGray800,
|
||||
textInfoPrimary = LightColorTokens.colorBlue900,
|
||||
textLinkExternal = LightColorTokens.colorBlue900,
|
||||
textInfoPrimary = LightColorTokens.colorBlue1100,
|
||||
textLinkExternal = LightColorTokens.colorBlue1100,
|
||||
textOnSolidPrimary = LightColorTokens.colorThemeBg,
|
||||
textPrimary = LightColorTokens.colorGray1400,
|
||||
textSecondary = LightColorTokens.colorGray900,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
|
@ -37,9 +34,12 @@ val compoundColorsHcLight = SemanticColors(
|
|||
bgActionSecondaryHovered = LightHcColorTokens.colorAlphaGray200,
|
||||
bgActionSecondaryPressed = LightHcColorTokens.colorAlphaGray300,
|
||||
bgActionSecondaryRest = LightHcColorTokens.colorThemeBg,
|
||||
bgBadgeAccent = LightHcColorTokens.colorAlphaGreen300,
|
||||
bgBadgeDefault = LightHcColorTokens.colorAlphaGray300,
|
||||
bgBadgeInfo = LightHcColorTokens.colorAlphaBlue300,
|
||||
bgActionTertiaryHovered = LightHcColorTokens.colorGray300,
|
||||
bgActionTertiaryRest = LightHcColorTokens.colorThemeBg,
|
||||
bgActionTertiarySelected = LightHcColorTokens.colorGray400,
|
||||
bgBadgeAccent = LightHcColorTokens.colorAlphaGreen400,
|
||||
bgBadgeDefault = LightHcColorTokens.colorAlphaGray400,
|
||||
bgBadgeInfo = LightHcColorTokens.colorAlphaBlue400,
|
||||
bgCanvasDefault = LightHcColorTokens.colorThemeBg,
|
||||
bgCanvasDefaultLevel1 = LightHcColorTokens.colorThemeBg,
|
||||
bgCanvasDisabled = LightHcColorTokens.colorGray200,
|
||||
|
|
@ -89,7 +89,7 @@ val compoundColorsHcLight = SemanticColors(
|
|||
iconAccentTertiary = LightHcColorTokens.colorGreen800,
|
||||
iconCriticalPrimary = LightHcColorTokens.colorRed900,
|
||||
iconDisabled = LightHcColorTokens.colorGray700,
|
||||
iconInfoPrimary = LightHcColorTokens.colorBlue900,
|
||||
iconInfoPrimary = LightHcColorTokens.colorBlue1100,
|
||||
iconOnSolidPrimary = LightHcColorTokens.colorThemeBg,
|
||||
iconPrimary = LightHcColorTokens.colorGray1400,
|
||||
iconPrimaryAlpha = LightHcColorTokens.colorAlphaGray1400,
|
||||
|
|
@ -112,8 +112,8 @@ val compoundColorsHcLight = SemanticColors(
|
|||
textDecorative5 = LightHcColorTokens.colorPink1100,
|
||||
textDecorative6 = LightHcColorTokens.colorOrange1100,
|
||||
textDisabled = LightHcColorTokens.colorGray800,
|
||||
textInfoPrimary = LightHcColorTokens.colorBlue900,
|
||||
textLinkExternal = LightHcColorTokens.colorBlue900,
|
||||
textInfoPrimary = LightHcColorTokens.colorBlue1100,
|
||||
textLinkExternal = LightHcColorTokens.colorBlue1100,
|
||||
textOnSolidPrimary = LightHcColorTokens.colorThemeBg,
|
||||
textPrimary = LightHcColorTokens.colorGray1400,
|
||||
textSecondary = LightHcColorTokens.colorGray900,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* !!! WARNING !!!
|
||||
*
|
||||
|
|
@ -14,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated.internal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated.internal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated.internal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
|
|
@ -13,8 +12,6 @@
|
|||
* DO NOT EDIT MANUALLY.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@file:Suppress("all")
|
||||
package io.element.android.compound.tokens.generated.internal
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M10,20a1,1 0,1 1,-2 0v-4L4,16a1,1 0,1 1,0 -2h6zM20,14a1,1 0,1 1,0 2h-4v4a1,1 0,1 1,-2 0v-6zM9,3a1,1 0,0 1,1 1v6L4,10a1,1 0,0 1,0 -2h4L8,4a1,1 0,0 1,1 -1m6,0a1,1 0,0 1,1 1v4h4a1,1 0,1 1,0 2h-6L14,4a1,1 0,0 1,1 -1"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,14a1,1 0,0 1,1 1v4h4a1,1 0,1 1,0 2L3,21v-6a1,1 0,0 1,1 -1m16,0a1,1 0,0 1,1 1v6h-6a1,1 0,1 1,0 -2h4v-4a1,1 0,0 1,1 -1M9,3a1,1 0,0 1,0 2L5,5v4a1,1 0,0 1,-2 0L3,3zM21,9a1,1 0,1 1,-2 0L19,5h-4a1,1 0,1 1,0 -2h6z"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M16.5,14.8L16.5,9.2q0,-0.35 -0.3,-0.475t-0.55,0.125L13.2,11.3q-0.3,0.3 -0.3,0.7t0.3,0.7l2.45,2.45q0.25,0.25 0.55,0.125t0.3,-0.475M5,19q-0.824,0 -1.412,-0.587A1.93,1.93 0,0 1,3 17L3,7q0,-0.824 0.587,-1.412A1.93,1.93 0,0 1,5 5h14q0.824,0 1.413,0.588Q21,6.175 21,7v10q0,0.824 -0.587,1.413A1.93,1.93 0,0 1,19 19zM8,17L8,7L5,7v10zM10,17h9L19,7h-9z"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M6,21q-1.65,0 -2.825,-1.175T2,17t1.175,-2.825T6,13t2.825,1.175T10,17t-1.175,2.825T6,21m12,0q-1.65,0 -2.825,-1.175T14,17t1.175,-2.825T18,13t2.825,1.175T22,17t-1.175,2.825T18,21M6,19q0.824,0 1.412,-0.587Q8,17.825 8,17t-0.588,-1.412A1.93,1.93 0,0 0,6 15q-0.824,0 -1.412,0.588A1.93,1.93 0,0 0,4 17q0,0.824 0.588,1.413Q5.175,19 6,19m12,0q0.824,0 1.413,-0.587Q20,17.825 20,17t-0.587,-1.412A1.93,1.93 0,0 0,18 15q-0.824,0 -1.413,0.588A1.93,1.93 0,0 0,16 17q0,0.824 0.587,1.413Q17.176,19 18,19m-6,-8q-1.65,0 -2.825,-1.175T8,7t1.175,-2.825T12,3t2.825,1.175T16,7t-1.175,2.825T12,11m0,-2q0.825,0 1.412,-0.588Q14,7.826 14,7q0,-0.824 -0.588,-1.412A1.93,1.93 0,0 0,12 5q-0.825,0 -1.412,0.588A1.93,1.93 0,0 0,10 7q0,0.824 0.588,1.412Q11.175,9 12,9"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M3.175,19.825Q4.35,21 6,21t2.825,-1.175T10,17t-1.175,-2.825T6,13t-2.825,1.175T2,17t1.175,2.825m12,0Q16.35,21 18,21t2.825,-1.175T22,17t-1.175,-2.825T18,13t-2.825,1.175T14,17t1.175,2.825m-6,-10Q10.35,11 12,11t2.825,-1.175T16,7t-1.175,-2.825T12,3 9.175,4.175 8,7t1.175,2.825"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7 10a0.97 0.97 0 0 1-0.71-0.29A0.97 0.97 0 0 1 6 9q0-0.42 0.29-0.71A0.97 0.97 0 0 1 7 8h10q0.42 0 0.71 0.29T18 9t-0.29 0.71A0.97 0.97 0 0 1 17 10z m0 4a0.97 0.97 0 0 1-0.71-0.29A0.97 0.97 0 0 1 6 13q0-0.42 0.29-0.71A0.97 0.97 0 0 1 7 12h6q0.42 0 0.71 0.29T14 13q0 0.42-0.29 0.71A0.97 0.97 0 0 1 13 14z"/>
|
||||
android:pathData="M7,10a0.97,0.97 0,0 1,-0.713 -0.287A0.97,0.97 0,0 1,6 9q0,-0.424 0.287,-0.713A0.97,0.97 0,0 1,7 8h10q0.424,0 0.712,0.287Q18,8.576 18,9t-0.288,0.713A0.97,0.97 0,0 1,17 10zM7,14a0.97,0.97 0,0 1,-0.713 -0.287A0.97,0.97 0,0 1,6 13q0,-0.424 0.287,-0.713A0.97,0.97 0,0 1,7 12h6q0.424,0 0.713,0.287 0.287,0.288 0.287,0.713 0,0.424 -0.287,0.713A0.97,0.97 0,0 1,13 14z"
|
||||
android:fillColor="#FF000000"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M3.7 21.3C3.09 21.91 2 21.47 2 20.58V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6zM6 17h14V5H4v13.17l0.59-0.58A2 2 0 0 1 6 17"/>
|
||||
android:pathData="M3.707,21.293c-0.63,0.63 -1.707,0.184 -1.707,-0.707V5a2,2 0,0 1,2 -2h16a2,2 0,0 1,2 2v12a2,2 0,0 1,-2 2H6zM6,17h14V5H4v13.172l0.586,-0.586A2,2 0,0 1,6 17"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M4 3h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6l-2.3 2.3C3.09 21.91 2 21.47 2 20.58V5a2 2 0 0 1 2-2m3 7h10q0.42 0 0.71-0.29A0.97 0.97 0 0 0 18 9a0.97 0.97 0 0 0-0.29-0.71A0.97 0.97 0 0 0 17 8H7a0.97 0.97 0 0 0-0.71 0.29A0.97 0.97 0 0 0 6 9q0 0.42 0.29 0.71T7 10m0 4h6q0.42 0 0.71-0.29A0.97 0.97 0 0 0 14 13a0.97 0.97 0 0 0-0.29-0.71A0.97 0.97 0 0 0 13 12H7a0.97 0.97 0 0 0-0.71 0.29A0.97 0.97 0 0 0 6 13q0 0.42 0.29 0.71T7 14"/>
|
||||
android:pathData="M4,3h16a2,2 0,0 1,2 2v12a2,2 0,0 1,-2 2H6l-2.293,2.293c-0.63,0.63 -1.707,0.184 -1.707,-0.707V5a2,2 0,0 1,2 -2m3,7h10q0.424,0 0.712,-0.287A0.97,0.97 0,0 0,18 9a0.97,0.97 0,0 0,-0.288 -0.713A0.97,0.97 0,0 0,17 8H7a0.97,0.97 0,0 0,-0.713 0.287A0.97,0.97 0,0 0,6 9q0,0.424 0.287,0.713Q6.576,10 7,10m0,4h6q0.424,0 0.713,-0.287A0.97,0.97 0,0 0,14 13a0.97,0.97 0,0 0,-0.287 -0.713A0.97,0.97 0,0 0,13 12H7a0.97,0.97 0,0 0,-0.713 0.287A0.97,0.97 0,0 0,6 13q0,0.424 0.287,0.713Q6.576,14 7,14"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M6,21q-1.65,0 -2.825,-1.175T2,17t1.175,-2.825T6,13t2.825,1.175T10,17t-1.175,2.825T6,21m12,0q-1.65,0 -2.825,-1.175T14,17t1.175,-2.825T18,13t2.825,1.175T22,17t-1.175,2.825T18,21M6,19q0.824,0 1.412,-0.587Q8,17.825 8,17t-0.588,-1.412A1.93,1.93 0,0 0,6 15q-0.824,0 -1.412,0.588A1.93,1.93 0,0 0,4 17q0,0.824 0.588,1.413Q5.175,19 6,19m12,0q0.824,0 1.413,-0.587Q20,17.825 20,17t-0.587,-1.412A1.93,1.93 0,0 0,18 15q-0.824,0 -1.413,0.588A1.93,1.93 0,0 0,16 17q0,0.824 0.587,1.413Q17.176,19 18,19m-6,-8q-1.65,0 -2.825,-1.175T8,7t1.175,-2.825T12,3t2.825,1.175T16,7t-1.175,2.825T12,11m0,-2q0.825,0 1.412,-0.588Q14,7.826 14,7q0,-0.824 -0.588,-1.412A1.93,1.93 0,0 0,12 5q-0.825,0 -1.412,0.588A1.93,1.93 0,0 0,10 7q0,0.824 0.588,1.412Q11.175,9 12,9"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M3.175,19.825Q4.35,21 6,21t2.825,-1.175T10,17t-1.175,-2.825T6,13t-2.825,1.175T2,17t1.175,2.825m12,0Q16.35,21 18,21t2.825,-1.175T22,17t-1.175,-2.825T18,13t-2.825,1.175T14,17t1.175,2.825m-6,-10Q10.35,11 12,11t2.825,-1.175T16,7t-1.175,-2.825T12,3 9.175,4.175 8,7t1.175,2.825"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
|
@ -21,7 +21,7 @@ fun String.md5() = try {
|
|||
digest.digest()
|
||||
.joinToString("") { String.format(locale, "%02X", it) }
|
||||
.lowercase(locale)
|
||||
} catch (exc: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// Should not happen, but just in case
|
||||
hashCode().toString()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fun String.isValidUrl(): Boolean {
|
|||
return try {
|
||||
URI(this).toURL()
|
||||
true
|
||||
} catch (t: Throwable) {
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.libraries.deeplink.impl
|
|||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.text.urlEncoded
|
||||
import io.element.android.libraries.deeplink.api.DeepLinkCreator
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
@ -21,13 +22,13 @@ class DefaultDeepLinkCreator : DeepLinkCreator {
|
|||
override fun create(sessionId: SessionId, roomId: RoomId?, threadId: ThreadId?, eventId: EventId?): String {
|
||||
return buildString {
|
||||
append("$SCHEME://$HOST/")
|
||||
append(sessionId.value)
|
||||
append(sessionId.value.urlEncoded())
|
||||
append("/")
|
||||
append(roomId?.value.orEmpty())
|
||||
append(roomId?.value?.urlEncoded().orEmpty())
|
||||
append("/")
|
||||
append(threadId?.value.orEmpty())
|
||||
append(threadId?.value?.urlEncoded().orEmpty())
|
||||
append("/")
|
||||
append(eventId?.value.orEmpty())
|
||||
append(eventId?.value?.urlEncoded().orEmpty())
|
||||
}
|
||||
// Remove all possible trailing '/' characters:
|
||||
// No event id
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.content.Intent
|
|||
import android.net.Uri
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.text.urlDecoded
|
||||
import io.element.android.libraries.deeplink.api.DeeplinkData
|
||||
import io.element.android.libraries.deeplink.api.DeeplinkParser
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
|
|
@ -31,7 +32,7 @@ class DefaultDeeplinkParser : DeeplinkParser {
|
|||
private fun Uri.toDeeplinkData(): DeeplinkData? {
|
||||
if (scheme != SCHEME) return null
|
||||
if (host != HOST) return null
|
||||
val pathBits = path.orEmpty().split("/").drop(1)
|
||||
val pathBits = encodedPath.orEmpty().split("/").drop(1).map { it.urlDecoded() }
|
||||
val sessionId = pathBits.elementAtOrNull(0)?.let(::SessionId) ?: return null
|
||||
|
||||
return when (val screenPathComponent = pathBits.elementAtOrNull(1)) {
|
||||
|
|
|
|||
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