Merge pull request #5844 from element-hq/feature/fga/room_edit_details

Change : room details edit
This commit is contained in:
ganfra 2025-12-03 17:43:59 +01:00 committed by GitHub
commit c6095bb651
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
106 changed files with 632 additions and 171 deletions

View file

@ -59,6 +59,7 @@ dependencies {
implementation(projects.features.roommembermoderation.api)
implementation(projects.features.rolesandpermissions.api)
implementation(projects.features.securityandprivacy.api)
implementation(projects.features.roomdetailsedit.api)
implementation(projects.features.invitepeople.api)
testCommonDependencies(libs, true)
@ -73,6 +74,7 @@ dependencies {
testImplementation(projects.features.call.test)
testImplementation(projects.features.rolesandpermissions.test)
testImplementation(projects.features.securityandprivacy.test)
testImplementation(projects.features.roomdetailsedit.test)
testImplementation(projects.features.knockrequests.test)
testImplementation(projects.features.messages.test)
testImplementation(projects.features.poll.test)

View file

@ -35,11 +35,11 @@ import io.element.android.features.rolesandpermissions.api.ChangeRoomMemberRoles
import io.element.android.features.rolesandpermissions.api.ChangeRoomMemberRolesListType
import io.element.android.features.rolesandpermissions.api.RolesAndPermissionsEntryPoint
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditNode
import io.element.android.features.roomdetails.impl.invite.RoomInviteMembersNode
import io.element.android.features.roomdetails.impl.members.RoomMemberListNode
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode
import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode
import io.element.android.features.roomdetailsedit.api.RoomDetailsEditEntryPoint
import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyEntryPoint
import io.element.android.features.userprofile.shared.UserProfileNodeHelper
import io.element.android.features.verifysession.api.OutgoingVerificationEntryPoint
@ -85,6 +85,7 @@ class RoomDetailsFlowNode(
private val changeRoomMemberRolesEntryPoint: ChangeRoomMemberRolesEntryPoint,
private val rolesAndPermissionsEntryPoint: RolesAndPermissionsEntryPoint,
private val securityAndPrivacyEntryPoint: SecurityAndPrivacyEntryPoint,
private val roomDetailsEditEntryPoint: RoomDetailsEditEntryPoint,
) : BaseFlowNode<RoomDetailsFlowNode.NavTarget>(
backstack = BackStack(
initialElement = plugins.filterIsInstance<RoomDetailsEntryPoint.Params>().first().initialElement.toNavTarget(),
@ -256,7 +257,7 @@ class RoomDetailsFlowNode(
}
NavTarget.RoomDetailsEdit -> {
createNode<RoomDetailsEditNode>(buildContext)
roomDetailsEditEntryPoint.createNode(this, buildContext)
}
NavTarget.InviteMembers -> {

View file

@ -20,6 +20,7 @@ import io.element.android.features.messages.test.FakeMessagesEntryPoint
import io.element.android.features.poll.test.history.FakePollHistoryEntryPoint
import io.element.android.features.reportroom.test.FakeReportRoomEntryPoint
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
import io.element.android.features.roomdetailsedit.test.FakeRoomDetailsEditEntryPoint
import io.element.android.features.securityandprivacy.test.FakeSecurityAndPrivacyEntryPoint
import io.element.android.features.verifysession.test.FakeOutgoingVerificationEntryPoint
import io.element.android.libraries.matrix.api.core.EventId
@ -63,6 +64,7 @@ class DefaultRoomDetailsEntryPointTest {
changeRoomMemberRolesEntryPoint = FakeChangeRoomMemberRolesEntryPoint(),
rolesAndPermissionsEntryPoint = FakeRolesAndPermissionsEntryPoint(),
securityAndPrivacyEntryPoint = FakeSecurityAndPrivacyEntryPoint(),
roomDetailsEditEntryPoint = FakeRoomDetailsEditEntryPoint(),
)
}
val callback = object : RoomDetailsEntryPoint.Callback {

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2022-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.
*/
plugins {
id("io.element.android-library")
id("kotlin-parcelize")
}
android {
namespace = "io.element.android.features.roomdetailsedit.api"
}
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
}

View file

@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.
*/
package io.element.android.features.roomdetailsedit.api
import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
fun interface RoomDetailsEditEntryPoint : SimpleFeatureEntryPoint

View file

@ -0,0 +1,57 @@
import extension.setupDependencyInjection
import extension.testCommonDependencies
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023, 2024 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.
*/
plugins {
id("io.element.android-compose-library")
id("kotlin-parcelize")
}
android {
namespace = "io.element.android.features.roomdetailsedit.impl"
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}
setupDependencyInjection()
dependencies {
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.matrixui)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.mediapickers.api)
implementation(projects.libraries.mediaupload.api)
implementation(projects.libraries.mediaviewer.api)
implementation(projects.libraries.featureflag.api)
implementation(projects.libraries.permissions.api)
implementation(projects.libraries.preferences.api)
implementation(projects.services.analytics.api)
implementation(projects.libraries.testtags)
api(projects.features.roomdetailsedit.api)
api(projects.services.apperror.api)
implementation(libs.coil.compose)
testCommonDependencies(libs, true)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.mediaupload.test)
testImplementation(projects.libraries.mediapickers.test)
testImplementation(projects.libraries.mediaviewer.test)
testImplementation(projects.libraries.permissions.test)
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.services.analytics.test)
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.
*/
package io.element.android.features.roomdetailsedit.impl
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.roomdetailsedit.api.RoomDetailsEditEntryPoint
import io.element.android.libraries.architecture.createNode
@ContributesBinding(AppScope::class)
class DefaultRoomDetailsEditEntryPoint : RoomDetailsEditEntryPoint {
override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
return parentNode.createNode<RoomDetailsEditNode>(buildContext)
}
}

View file

@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import io.element.android.libraries.matrix.ui.media.AvatarAction

View file

@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier

View file

@ -6,8 +6,9 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import android.Manifest
import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -32,9 +33,6 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.powerlevels.canSendState
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.matrix.ui.room.avatarUrl
import io.element.android.libraries.matrix.ui.room.rawName
import io.element.android.libraries.matrix.ui.room.topic
import io.element.android.libraries.mediapickers.api.PickerProvider
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
@ -54,15 +52,15 @@ class RoomDetailsEditPresenter(
permissionsPresenterFactory: PermissionsPresenter.Factory,
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
) : Presenter<RoomDetailsEditState> {
private val cameraPermissionPresenter = permissionsPresenterFactory.create(android.Manifest.permission.CAMERA)
private val cameraPermissionPresenter = permissionsPresenterFactory.create(Manifest.permission.CAMERA)
private var pendingPermissionRequest = false
@Composable
override fun present(): RoomDetailsEditState {
val cameraPermissionState = cameraPermissionPresenter.present()
val roomSyncUpdateFlow = room.syncUpdateFlow.collectAsState()
val roomAvatarUri = room.avatarUrl()
val roomInfo by room.roomInfoFlow.collectAsState()
val roomAvatarUri = roomInfo.avatarUrl
var roomAvatarUriEdited by rememberSaveable { mutableStateOf<String?>(null) }
LaunchedEffect(roomAvatarUri) {
// Every time the roomAvatar change (from sync), we can set the new avatar.
@ -70,13 +68,13 @@ class RoomDetailsEditPresenter(
roomAvatarUriEdited = roomAvatarUri
}
val roomRawNameTrimmed = room.rawName().orEmpty().trim()
val roomRawNameTrimmed = roomInfo.rawName.orEmpty().trim()
var roomRawNameEdited by rememberSaveable { mutableStateOf("") }
LaunchedEffect(roomRawNameTrimmed) {
// Every time the rawName change (from sync), we can set the new name.
roomRawNameEdited = roomRawNameTrimmed
}
val roomTopicTrimmed = room.topic().orEmpty().trim()
val roomTopicTrimmed = roomInfo.topic.orEmpty().trim()
var roomTopicEdited by rememberSaveable { mutableStateOf("") }
LaunchedEffect(roomTopicTrimmed) {
// Every time the topic change (from sync), we can set the new topic.
@ -192,6 +190,7 @@ class RoomDetailsEditPresenter(
saveButtonEnabled = saveButtonEnabled,
saveAction = saveAction.value,
cameraPermissionState = cameraPermissionState,
isSpace = roomInfo.isSpace,
eventSink = ::handleEvent,
)
}

View file

@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
@ -27,5 +27,6 @@ data class RoomDetailsEditState(
val saveButtonEnabled: Boolean,
val saveAction: AsyncAction<Unit>,
val cameraPermissionState: PermissionsState,
val isSpace: Boolean,
val eventSink: (RoomDetailsEditEvents) -> Unit
)

View file

@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncAction
@ -23,6 +23,7 @@ open class RoomDetailsEditStateProvider : PreviewParameterProvider<RoomDetailsEd
aRoomDetailsEditState(roomTopic = ""),
aRoomDetailsEditState(roomRawName = ""),
aRoomDetailsEditState(roomAvatarUrl = "example://uri"),
aRoomDetailsEditState(roomAvatarUrl = "example://uri", isSpace = true, roomTopic = ""),
aRoomDetailsEditState(canChangeName = true, canChangeTopic = false, canChangeAvatar = true, saveButtonEnabled = false),
aRoomDetailsEditState(canChangeName = false, canChangeTopic = true, canChangeAvatar = false, saveButtonEnabled = false),
aRoomDetailsEditState(saveAction = AsyncAction.Loading),
@ -43,6 +44,7 @@ fun aRoomDetailsEditState(
saveButtonEnabled: Boolean = true,
saveAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
cameraPermissionState: PermissionsState = aPermissionsState(showDialog = false),
isSpace: Boolean = false,
eventSink: (RoomDetailsEditEvents) -> Unit = {},
) = RoomDetailsEditState(
roomId = roomId,
@ -56,5 +58,6 @@ fun aRoomDetailsEditState(
saveButtonEnabled = saveButtonEnabled,
saveAction = saveAction,
cameraPermissionState = cameraPermissionState,
isSpace = isSpace,
eventSink = eventSink,
)

View file

@ -8,7 +8,7 @@
@file:OptIn(ExperimentalMaterial3Api::class)
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
@ -31,7 +30,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.roomdetails.impl.R
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
@ -97,7 +95,6 @@ fun RoomDetailsEditView(
modifier = Modifier
.padding(padding)
.padding(horizontal = 16.dp)
.navigationBarsPadding()
.imePadding()
.verticalScroll(rememberScrollState())
) {
@ -108,14 +105,18 @@ fun RoomDetailsEditView(
displayName = state.roomRawName,
avatarUrl = state.roomAvatarUrl,
avatarSize = AvatarSize.EditRoomDetails,
avatarType = AvatarType.Room(),
avatarType = if (state.isSpace) {
AvatarType.Space()
} else {
AvatarType.Room()
},
onAvatarClick = ::onAvatarClick,
modifier = Modifier.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(60.dp))
Spacer(modifier = Modifier.height(32.dp))
TextField(
label = stringResource(id = R.string.screen_room_details_room_name_label),
label = stringResource(id = CommonStrings.common_name),
value = state.roomRawName,
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
singleLine = true,
@ -123,12 +124,16 @@ fun RoomDetailsEditView(
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomName(it)) },
)
Spacer(modifier = Modifier.height(28.dp))
Spacer(modifier = Modifier.height(32.dp))
TextField(
label = stringResource(CommonStrings.common_topic),
value = state.roomTopic,
placeholder = stringResource(CommonStrings.common_topic_placeholder),
placeholder = if (state.isSpace) {
stringResource(CommonStrings.common_space_topic_placeholder)
} else {
stringResource(CommonStrings.common_topic_placeholder)
},
maxLines = 10,
readOnly = !state.canChangeTopic,
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(it)) },

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Рэдагаваць пакой"</string>
<string name="screen_room_details_edition_error">"Адбылася невядомая памылка, і інфармацыю нельга было змяніць."</string>
<string name="screen_room_details_edition_error_title">"Немагчыма абнавіць пакой"</string>
<string name="screen_room_details_updating_room">"Ідзе абнаўленне пакоя…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Редактиране на стаята"</string>
<string name="screen_room_details_edition_error">"Възникна неизвестна грешка и информацията не можа да бъде променена."</string>
<string name="screen_room_details_edition_error_title">"Не може да се обнови стаята"</string>
<string name="screen_room_details_updating_room">"Обновяване на стаята…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Upravit podrobnosti"</string>
<string name="screen_room_details_edition_error">"Došlo k neznámé chybě a informace nebylo možné změnit."</string>
<string name="screen_room_details_edition_error_title">"Nelze aktualizovat místnost"</string>
<string name="screen_room_details_updating_room">"Aktualizace místnosti…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Ystafell Golygu"</string>
<string name="screen_room_details_edition_error">"Roedd gwall anhysbys ac nid oedd modd newid y manylion."</string>
<string name="screen_room_details_edition_error_title">"Methu diweddaru\'r ystafell"</string>
<string name="screen_room_details_updating_room">"Wrthi\'n diweddaru ystafell…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Rediger rum"</string>
<string name="screen_room_details_edition_error">"Der opstod en ukendt fejl, og oplysningerne kunne ikke ændres."</string>
<string name="screen_room_details_edition_error_title">"Rummet kunne ikke opdateres"</string>
<string name="screen_room_details_updating_room">"Opdaterer rum…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Chat bearbeiten"</string>
<string name="screen_room_details_edition_error">"Es ist ein unbekannter Fehler aufgetreten und die Informationen konnten nicht geändert werden."</string>
<string name="screen_room_details_edition_error_title">"Chat kann nicht aktualisiert werden"</string>
<string name="screen_room_details_updating_room">"Chat wird aktualisiert…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Επεξεργασία Αίθουσας"</string>
<string name="screen_room_details_edition_error">"Υπήρξε ένα άγνωστο σφάλμα και οι πληροφορίες δεν μπορούσαν να αλλάξουν."</string>
<string name="screen_room_details_edition_error_title">"Αδυναμία ενημέρωσης αίθουσας"</string>
<string name="screen_room_details_updating_room">"Ενημέρωση αίθουσας…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Editar sala"</string>
<string name="screen_room_details_edition_error">"Se ha producido un error desconocido y no se ha podido cambiar la información."</string>
<string name="screen_room_details_edition_error_title">"No se puede actualizar la sala"</string>
<string name="screen_room_details_updating_room">"Actualizando la sala…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Muuda üksikasju"</string>
<string name="screen_room_details_edition_error">"Tekkis tundmatu viga ja andmed jäid muutmata."</string>
<string name="screen_room_details_edition_error_title">"Jututoa andmete muutmine ei õnnestu"</string>
<string name="screen_room_details_updating_room">"Uuendame jututuba…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Editatu gela"</string>
<string name="screen_room_details_edition_error">"Errore ezezaguna gertatu da eta ezin izan da informazioa aldatu."</string>
<string name="screen_room_details_edition_error_title">"Ezin da gela eguneratu"</string>
<string name="screen_room_details_updating_room">"Gela eguneratzen…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"ویرایش اتاق"</string>
<string name="screen_room_details_edition_error">"خطایی ناشناخته رخ داد و اطّلاعات قابل تغییر نبودند."</string>
<string name="screen_room_details_edition_error_title">"ناتوان در به‌روز رسانی اتاق"</string>
<string name="screen_room_details_updating_room">"به‌روز کردن اتاق…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Muokkaa tietoja"</string>
<string name="screen_room_details_edition_error">"Tuntematon virhe tapahtui, eikä tietoja voitu muuttaa."</string>
<string name="screen_room_details_edition_error_title">"Huoneen muokkaaminen ei onnistunut"</string>
<string name="screen_room_details_updating_room">"Muokataan huonetta…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Modifier les détails"</string>
<string name="screen_room_details_edition_error">"Une erreur inconnue sest produite et les informations nont pas pu être modifiées."</string>
<string name="screen_room_details_edition_error_title">"Impossible de mettre à jour le salon"</string>
<string name="screen_room_details_updating_room">"Mise à jour du salon…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Részletek szerkesztése"</string>
<string name="screen_room_details_edition_error">"Ismeretlen hiba történt, és az információkat nem lehetett megváltoztatni."</string>
<string name="screen_room_details_edition_error_title">"Nem sikerült frissíteni a szobát"</string>
<string name="screen_room_details_updating_room">"Szoba frissítése…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Sunting Ruangan"</string>
<string name="screen_room_details_edition_error">"Terjadi kesalahan yang tidak diketahui dan informasinya tidak dapat diubah."</string>
<string name="screen_room_details_edition_error_title">"Tidak dapat memperbarui ruangan"</string>
<string name="screen_room_details_updating_room">"Memperbarui ruangan…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Modifica dettagli"</string>
<string name="screen_room_details_edition_error">"Si è verificato un errore sconosciuto e non è stato possibile modificare le informazioni."</string>
<string name="screen_room_details_edition_error_title">"Impossibile aggiornare la stanza"</string>
<string name="screen_room_details_updating_room">"Aggiornamento della stanza…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"ოთახის რედაქტირება"</string>
<string name="screen_room_details_edition_error">"უცნობი შეცდომა მოხდა. ინფორმაციის შეცვლა ვერ მოხერხდა."</string>
<string name="screen_room_details_edition_error_title">"ოთახის განახლება შეუძლებელია"</string>
<string name="screen_room_details_updating_room">"ოთახის განახლება…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"방 편집"</string>
<string name="screen_room_details_edition_error">"알 수 없는 오류가 발생하여 정보를 변경할 수 없습니다."</string>
<string name="screen_room_details_edition_error_title">"방을 업데이트할 수 없습니다."</string>
<string name="screen_room_details_updating_room">"방 업데이트 중…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Redaguoti kambarį"</string>
<string name="screen_room_details_edition_error">"Įvyko nežinoma klaida ir informacijos pakeisti nepavyko."</string>
<string name="screen_room_details_edition_error_title">"Nepavyko atnaujinti kambario"</string>
<string name="screen_room_details_updating_room">"Atnaujinamas kambarys…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Rediger rom"</string>
<string name="screen_room_details_edition_error">"Det oppstod en ukjent feil, og informasjonen kunne ikke endres."</string>
<string name="screen_room_details_edition_error_title">"Kan ikke oppdatere rommet"</string>
<string name="screen_room_details_updating_room">"Oppdaterer rommet …"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Kamer bewerken"</string>
<string name="screen_room_details_edition_error">"Er is een onbekende fout opgetreden en de informatie kon niet worden gewijzigd."</string>
<string name="screen_room_details_edition_error_title">"Kan kamer niet bijwerken"</string>
<string name="screen_room_details_updating_room">"Kamer bijwerken…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Edytuj pokój"</string>
<string name="screen_room_details_edition_error">"Wystąpił nieznany błąd i nie można było zmienić informacji."</string>
<string name="screen_room_details_edition_error_title">"Nie można zaktualizować pokoju"</string>
<string name="screen_room_details_updating_room">"Aktualizuję pokój…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Editar detalhes"</string>
<string name="screen_room_details_edition_error">"Ocorreu um erro desconhecido e as informações não puderam ser alteradas."</string>
<string name="screen_room_details_edition_error_title">"Não foi possível atualizar a sala"</string>
<string name="screen_room_details_updating_room">"Atualizando a sala…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Editar sala"</string>
<string name="screen_room_details_edition_error">"Ocorreu um erro desconhecido e não foi possível alterar a informação."</string>
<string name="screen_room_details_edition_error_title">"Não foi possível atualizar a sala"</string>
<string name="screen_room_details_updating_room">"A atualizar sala…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Editați camera"</string>
<string name="screen_room_details_edition_error">"A apărut o eroare la actualizarea detaliilor camerei"</string>
<string name="screen_room_details_edition_error_title">"Nu s-a putut actualiza camera"</string>
<string name="screen_room_details_updating_room">"Se actualizează camera…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Редактировать комнату"</string>
<string name="screen_room_details_edition_error">"Произошла неизвестная ошибка и информацию не удалось изменить."</string>
<string name="screen_room_details_edition_error_title">"Не удалось обновить комнату"</string>
<string name="screen_room_details_updating_room">"Обновление комнаты…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_updating_room">"Aktualizácia miestnosti…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Redigera rummet"</string>
<string name="screen_room_details_edition_error">"Ett okänt fel uppstod och informationen kunde inte ändras."</string>
<string name="screen_room_details_edition_error_title">"Kunde inte uppdatera rummet"</string>
<string name="screen_room_details_updating_room">"Uppdaterar rummet …"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Odayı Düzenle"</string>
<string name="screen_room_details_edition_error">"Bilinmeyen bir hata oluştu ve bilgiler değiştirilemedi."</string>
<string name="screen_room_details_edition_error_title">"Oda güncellenemiyor"</string>
<string name="screen_room_details_updating_room">"Oda güncelleniyor…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Редагувати кімнату"</string>
<string name="screen_room_details_edition_error">"Сталася невідома помилка, й інформацію не вдалося змінити."</string>
<string name="screen_room_details_edition_error_title">"Не вдалося оновити кімнату"</string>
<string name="screen_room_details_updating_room">"Оновлення кімнати…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"کمرے میں ترمیم کریں"</string>
<string name="screen_room_details_edition_error">"ایک نامعلوم خلل تھا اور معلومات تبدیل نہیں ہوسکی۔"</string>
<string name="screen_room_details_edition_error_title">"کمرے کی تجدید کرنے سے قاصر"</string>
<string name="screen_room_details_updating_room">"کمرے کی تجدید کر رہا ہے…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"Xonani tahrirlash"</string>
<string name="screen_room_details_edition_error">"Nomaʼlum xatolik yuz berdi va maʼlumotni oʻzgartirib boʻlmadi."</string>
<string name="screen_room_details_edition_error_title">"Xonani yangilab bolmadi"</string>
<string name="screen_room_details_updating_room">"Xona yangilanmoqda…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"編輯詳細資訊"</string>
<string name="screen_room_details_edition_error">"發生未知錯誤,無法變更資訊。"</string>
<string name="screen_room_details_edition_error_title">"無法更新聊天室"</string>
<string name="screen_room_details_updating_room">"正在更新聊天室…"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_details_edit_room_title">"编辑聊天室"</string>
<string name="screen_room_details_edition_error">"出现未知错误,无法更改信息。"</string>
<string name="screen_room_details_edition_error_title">"无法更新聊天室"</string>
<string name="screen_room_details_updating_room">"正在更新聊天室……"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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>
</resources>

View file

@ -1,25 +1,28 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import android.net.Uri
import app.cash.turbine.ReceiveTurbine
import com.google.common.truth.Truth.assertThat
import io.element.android.features.roomdetails.impl.aJoinedRoom
import io.element.android.libraries.androidutils.file.TemporaryUriDeleter
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_ROOM_RAW_NAME
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.mediapickers.test.FakePickerProvider
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
@ -124,16 +127,17 @@ class RoomDetailsEditPresenterTest {
@Test
fun `present - sets canChangeName if user has permission`() = runTest {
val room = aJoinedRoom(
avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, stateEventType ->
when (stateEventType) {
StateEventType.ROOM_NAME -> Result.success(true)
StateEventType.ROOM_AVATAR -> Result.success(false)
StateEventType.ROOM_TOPIC -> Result.failure(RuntimeException("Oops"))
else -> lambdaError()
}
},
val room = FakeJoinedRoom(
FakeBaseRoom(
canSendStateResult = { _, stateEventType ->
when (stateEventType) {
StateEventType.ROOM_NAME -> Result.success(true)
StateEventType.ROOM_AVATAR -> Result.success(false)
StateEventType.ROOM_TOPIC -> Result.failure(RuntimeException("Oops"))
else -> lambdaError()
}
},
)
)
val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter(
@ -769,6 +773,34 @@ class RoomDetailsEditPresenterTest {
)
}
private fun aJoinedRoom(
avatarUrl: String? = AN_AVATAR_URL,
displayName: String = A_ROOM_NAME,
rawName: String = displayName,
topic: String? = A_ROOM_TOPIC,
setNameResult: (String) -> Result<Unit> = { Result.success(Unit) },
setTopicResult: (String) -> Result<Unit> = { Result.success(Unit) },
updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> Result.success(Unit) },
removeAvatarResult: () -> Result<Unit> = { Result.success(Unit) },
canSendStateResult: (UserId, StateEventType) -> Result<Boolean>,
): JoinedRoom {
return FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canSendStateResult = canSendStateResult,
initialRoomInfo = aRoomInfo(
name = displayName,
topic = topic,
avatarUrl = avatarUrl,
rawName = rawName
)
),
setNameResult = setNameResult,
setTopicResult = setTopicResult,
updateAvatarResult = updateAvatarResult,
removeAvatarResult = removeAvatarResult,
)
}
companion object {
private const val ANOTHER_AVATAR_URL = "example://camera/foo.jpg"
}

View file

@ -1,12 +1,11 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 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.
*/
package io.element.android.features.roomdetails.impl.edit
package io.element.android.features.roomdetailsedit.impl
import androidx.activity.ComponentActivity
import androidx.annotation.StringRes

View file

@ -0,0 +1,22 @@
/*
* 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.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.features.roomdetetailsedit.test"
}
dependencies {
implementation(projects.features.roomdetailsedit.api)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.tests.testutils)
}

View file

@ -0,0 +1,19 @@
/*
* 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.roomdetailsedit.test
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import io.element.android.features.roomdetailsedit.api.RoomDetailsEditEntryPoint
import io.element.android.tests.testutils.lambda.lambdaError
class FakeRoomDetailsEditEntryPoint : RoomDetailsEditEntryPoint {
override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
lambdaError()
}
}

View file

@ -8,20 +8,25 @@
package io.element.android.libraries.matrix.ui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
@ -52,23 +57,42 @@ fun EditableAvatarView(
onAvatarClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
val a11yAvatar = stringResource(CommonStrings.a11y_avatar)
val editIconRadius = 15.dp
val parentHeight = avatarSize.dp
val parentWidth = avatarSize.dp + editIconRadius / 2f
Box(
modifier = modifier
.wrapContentSize()
.size(height = parentHeight, width = parentWidth)
.clickable(
interactionSource = remember { MutableInteractionSource() },
onClickLabel = stringResource(CommonStrings.a11y_edit_avatar),
onClick = onAvatarClick,
indication = ripple(bounded = false),
)
.testTag(TestTags.editAvatar)
.clearAndSetSemantics {
contentDescription = a11yAvatar
},
) {
val a11yAvatar = stringResource(CommonStrings.a11y_avatar)
Box(
modifier = Modifier
.clickable(
interactionSource = remember { MutableInteractionSource() },
onClickLabel = stringResource(CommonStrings.a11y_edit_avatar),
onClick = onAvatarClick,
indication = ripple(bounded = false),
)
.testTag(TestTags.editAvatar)
.clearAndSetSemantics {
contentDescription = a11yAvatar
},
.graphicsLayer {
compositingStrategy = CompositingStrategy.Offscreen
}
.drawWithContent {
drawContent()
drawCircle(
color = Color.Black,
center = Offset(
x = parentWidth.toPx() - editIconRadius.toPx(),
y = size.height - editIconRadius.toPx(),
),
radius = (editIconRadius + 4.dp).toPx(),
blendMode = BlendMode.Clear,
)
}
) {
when {
avatarUrl == null || avatarUrl.startsWith("mxc://") -> {
@ -90,23 +114,17 @@ fun EditableAvatarView(
)
}
}
Box(
modifier = Modifier
.align(Alignment.BottomEnd)
.clip(CircleShape)
.background(ElementTheme.colors.iconPrimary)
.size(24.dp),
contentAlignment = Alignment.Center,
) {
Icon(
modifier = Modifier.size(16.dp),
imageVector = CompoundIcons.EditSolid(),
contentDescription = null,
tint = ElementTheme.colors.iconOnSolidPrimary,
)
}
}
Icon(
modifier = Modifier
.align(Alignment.BottomEnd)
.size(editIconRadius * 2)
.border(1.dp, ElementTheme.colors.borderInteractiveSecondary, CircleShape)
.padding(6.dp),
imageVector = CompoundIcons.Edit(),
contentDescription = null,
tint = ElementTheme.colors.iconPrimary,
)
}
}
@ -119,9 +137,9 @@ internal fun EditableAvatarViewPreview(
) {
EditableAvatarView(
matrixId = "id",
displayName = "A room",
displayName = "Room",
avatarUrl = uri,
avatarSize = AvatarSize.EditRoomDetails,
avatarSize = AvatarSize.RoomDetailsHeader,
avatarType = AvatarType.User,
onAvatarClick = {},
)

View file

@ -111,21 +111,3 @@ fun BaseRoom.isOwnUserAdmin(): Boolean {
val role = roomInfo.roleOf(sessionId)
return role == RoomMember.Role.Admin || role is RoomMember.Role.Owner
}
@Composable
fun BaseRoom.rawName(): String? {
val roomInfo by roomInfoFlow.collectAsState()
return roomInfo.rawName
}
@Composable
fun BaseRoom.topic(): String? {
val roomInfo by roomInfoFlow.collectAsState()
return roomInfo.topic
}
@Composable
fun BaseRoom.avatarUrl(): String? {
val roomInfo by roomInfoFlow.collectAsState()
return roomInfo.avatarUrl
}

View file

@ -251,6 +251,7 @@ Reason: %1$s."</string>
<string name="common_message_removed">"Message removed"</string>
<string name="common_modern">"Modern"</string>
<string name="common_mute">"Mute"</string>
<string name="common_name">"Name"</string>
<string name="common_name_and_id">"%1$s (%2$s)"</string>
<string name="common_no_results">"No results"</string>
<string name="common_no_room_name">"No room name"</string>
@ -325,6 +326,7 @@ Reason: %1$s."</string>
<string name="common_something_went_wrong">"Something went wrong"</string>
<string name="common_something_went_wrong_message">"We encountered an issue. Please try again."</string>
<string name="common_space">"Space"</string>
<string name="common_space_topic_placeholder">"What is this space about?"</string>
<plurals name="common_spaces">
<item quantity="one">"%1$d Space"</item>
<item quantity="other">"%1$d Spaces"</item>

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e036fd006454f8dad5ca62109e047e33ded820b23ba1338e90489cc6af194256
size 20122
oid sha256:5896d5e6fd21697d6270aedb4389eee0d57a9796536b847ae657f57e6c2dab3d
size 20974

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:23c48ba14e151edf2669cd8a7804517bd4282b0b86e0482ed16c351c8d5da61e
size 68392
oid sha256:95100c25fb085329f8968a765a4f4359678be67309d5e086ead311c48cfda29f
size 67826

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da49d0867fdaa28fbe7db7dc21c5de09268e7bb3afdb0b2289df372d537c2abb
size 33570
oid sha256:f2a443d3d6733e4fb9c618c4a689c8fb95195f47d3b08513a955f18251028b2f
size 34203

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cba22353e2689d211508e5b2726d751a31109c490e242708fbdf0bab2b31870c
size 20257
oid sha256:7f103f89c71cc97a837cf0edc1035c580bfdf2d682857897241a6dec23c91436
size 21163

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8ac052ff95c121119d5dd99d07b41b0f78f83ce59b6644aeb596f45e673f1b03
size 67341
oid sha256:9989d429a1ed9f3190a19c0678168de77aca597ed8fda5208e19bbe109ab9ada
size 66391

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:60fe1926cf8d66a8086268f3e4e1b6b1616f860668e1e5f4dc670d5c57ec4d24
size 31943
oid sha256:b2166579c462025a6bff38b05da7574502f7200d5f0a4949b31ea4e4fbc25a67
size 32467

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21ef482132a717f7c45bb5775f16344da2a96932d5f6854d73660c599e48d9ca
size 28141

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:36b5337f5edcbcc1b6eafe504ba2a6edd20078e1a22df34c6ff3ddaeade82d55
size 21966

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:32a649e6c9555bdf4d3a87bc18a51ca226167dd561b868d0b9310ded4a782c0d
size 29622

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:47ceaff5ef3c3244faa2ba389a7a84c5c9a6860fd3bf6d84e0728288037edad5
size 53852

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:91f992a8a82e04fef07c5efacf882ac188061b105bea2867edac9fef94c58be7
size 28099

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2289b612f53068f68f5d4bfe5cbaabb29f93564509d27694ddf54617ce3fa9b
size 28192

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:65c3f2a886d68749d9169945f6ab796bae00dfaaf5a1bc07af395c3d8e3fd8db
size 26561

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3e653ac4f6a735766b47fe6b9653160c60b79a13836dac84cb1b00d8b3a9ad5e
size 24928

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9e241c5acd53a70d1dee2a7f4542fdbcfab43774d13263a652cd9c0e5e6614a3
size 31103

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6326a107a0e9d5ddf524311b4d650986e26fdce172ed8ee79a587b9c2a7b92a8
size 27605

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3edb943c28ebc38755f2167431a75702d21b69ff9188adc76f18bc9085002360
size 21729

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6a4432faa27f3e46f8b2abb91215ba68136daefea50e7cfdec86d77b65773d35
size 29108

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9ceccd6b99a12d22ea5f8b2e1634c9f0abcd52732a3ad7533a5e4a6263064aab
size 52768

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21881980c4cd55f521e4bd72b477577c0e2d6887fdc1827fd9d82a9b609a9312
size 27598

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:efeec7c32edd8d822c9ccebb5c4765862b1b236b150aa1157f2773b69b8f183b
size 27584

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:616f78d6ddd065169c577a3ecf24accaa793a668786c52ab1eae8e26382cd790
size 25645

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8e8b4d9d65eefe2c0343fa5d563d16ba90c1eb2468e2b5f6395f2872bf453db0
size 23162

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:74cb40864ab2e480af32a3929f2f9a3ff74e2c9e40f11fce6384f259c7e7dcc4
size 29185

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c200761849da1ba650f38adfeed65fcc35f4fda94a4b1302447faf55d4196c16
size 28211

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:282680791aed814f49e25134742e55270ffa155004d48a4f4645ef160450c529
size 21933

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fc04e9e69f8111c2837d998f6503e2ea146d91284d1839ac8619d5d9325645d7
size 29613

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c7579d7b70e81228d997f8390285210a6e6a7c764523a82b59cd68b2e1969656
size 52193

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:eaad1ca1ef992a03aae784836139963e5ac8867d5fc70871eb63d273acf05948
size 49266

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:44331b9967290ab96c55cce7a5f8a3531564ad0c074ea6b25adf9299a6ec0239
size 28165

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d037d7c70b304980c4c0a2c292fdcf800eafff15aee8c3c3adbf180e7e47a557
size 28293

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3f2d14cff976468c7a2408c9e9d0dabcfbed4a0cfb1406f71db459f660305269
size 24794

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:109a1451e031bcc46e55c2c111a4ce65eb5635a3b66b1ba6a5e6a0980184ec0d
size 26087

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:25d60c4025a15e283978fb15abf8417bc896714ebc1faf198a3735978bbbfb18
size 32392

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d797584eca407120de11bdac2792a4501dd414274e5acf786fab74b7df668209
size 27518

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0ba88593c26798de646f331f68c48b4675f33090e7533b88f6a31e0c5cfbd081
size 21538

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:16c5f05bb20e9a1f5b3480827fe7c7c4384daa60496da0ee0dc9bcdd77ccdddd
size 29004

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7616b1926b6b6f1c6aa19d797866a74cb7db487fa72e59b291e715f22d961607
size 50787

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f2c9d431942b442b2620268cec8f06166db18b5df732b7a77cd71a11228106c6
size 48325

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bd244116c434d143950d0bb7c291d3a4faf4540f34112286b9069c41eb7de576
size 27509

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3e98e5bdd03bdd7c2da11595416987398ec4af4ba88010a0eab25f11da149ea7
size 27520

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b904f634f9668cc207a922979e0b3abc92c586f3986cf3c57630da8aa2eb22fe
size 23835

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c95f90eba87b390c09894087d4c55dfe8e7797af712315ccbee3f927be4e5d5
size 24314

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:29cea35b4105715561f34e4c6fe80a57272444b34b01bd9dd1f0adec67ea8878
size 30270

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:31664f09c84f66bca77ae15dc10ab8a9f57a8f4362ce0a1712fe47668950bb04
size 7149
oid sha256:a0635fa0f0ca2b150f598279fee291f25203c6313f8d5fe449e4c1629c96637a
size 8528

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