diff --git a/app/src/test/kotlin/io/element/android/app/KonsistTest.kt b/app/src/test/kotlin/io/element/android/app/KonsistTest.kt index f2d20d0c37..68d8a5c883 100644 --- a/app/src/test/kotlin/io/element/android/app/KonsistTest.kt +++ b/app/src/test/kotlin/io/element/android/app/KonsistTest.kt @@ -22,6 +22,7 @@ import com.lemonappdev.konsist.api.Konsist import com.lemonappdev.konsist.api.ext.list.modifierprovider.withoutModifier import com.lemonappdev.konsist.api.ext.list.withAllAnnotationsOf import com.lemonappdev.konsist.api.ext.list.withAllParentsOf +import com.lemonappdev.konsist.api.ext.list.withNameEndingWith import com.lemonappdev.konsist.api.ext.list.withTopLevel import com.lemonappdev.konsist.api.ext.list.withoutName import com.lemonappdev.konsist.api.ext.list.withoutNameEndingWith @@ -84,4 +85,19 @@ class KonsistTest { } } } + + @Test + fun `Data class state MUST not have default value`() { + Konsist + .scopeFromProject() + .classes() + .withNameEndingWith("State") + .assertTrue { classDeclaration -> + classDeclaration.constructors.all { constructorDeclaration -> + constructorDeclaration.parameters.all { parameterDeclaration -> + parameterDeclaration.defaultValue == null + } + } + } + } } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt index d58361a82f..7f53876df8 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsState.kt @@ -17,9 +17,9 @@ package io.element.android.features.location.impl.common.permissions data class PermissionsState( - val permissions: Permissions = Permissions.NoneGranted, - val shouldShowRationale: Boolean = false, - val eventSink: (PermissionsEvents) -> Unit = {}, + val permissions: Permissions, + val shouldShowRationale: Boolean, + val eventSink: (PermissionsEvents) -> Unit, ) { sealed interface Permissions { data object AllGranted : Permissions diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationState.kt index 5dae23c998..a41449801b 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationState.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationState.kt @@ -17,11 +17,11 @@ package io.element.android.features.location.impl.send data class SendLocationState( - val permissionDialog: Dialog = Dialog.None, - val mode: Mode = Mode.PinLocation, - val hasLocationPermission: Boolean = false, - val appName: String = "AppName", - val eventSink: (SendLocationEvents) -> Unit = {}, + val permissionDialog: Dialog, + val mode: Mode, + val hasLocationPermission: Boolean, + val appName: String, + val eventSink: (SendLocationEvents) -> Unit, ) { sealed interface Mode { data object SenderLocation : Mode diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationStateProvider.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationStateProvider.kt index 15f16f593a..7cc3534f19 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationStateProvider.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationStateProvider.kt @@ -23,35 +23,44 @@ private const val APP_NAME = "ApplicationName" class SendLocationStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - SendLocationState( + aSendLocationState( permissionDialog = SendLocationState.Dialog.None, mode = SendLocationState.Mode.PinLocation, hasLocationPermission = false, - appName = APP_NAME, ), - SendLocationState( + aSendLocationState( permissionDialog = SendLocationState.Dialog.PermissionDenied, mode = SendLocationState.Mode.PinLocation, hasLocationPermission = false, - appName = APP_NAME, ), - SendLocationState( + aSendLocationState( permissionDialog = SendLocationState.Dialog.PermissionRationale, mode = SendLocationState.Mode.PinLocation, hasLocationPermission = false, - appName = APP_NAME, ), - SendLocationState( + aSendLocationState( permissionDialog = SendLocationState.Dialog.None, mode = SendLocationState.Mode.PinLocation, hasLocationPermission = true, - appName = APP_NAME, ), - SendLocationState( + aSendLocationState( permissionDialog = SendLocationState.Dialog.None, mode = SendLocationState.Mode.SenderLocation, hasLocationPermission = true, - appName = APP_NAME, ), ) } + +private fun aSendLocationState( + permissionDialog: SendLocationState.Dialog, + mode: SendLocationState.Mode, + hasLocationPermission: Boolean, +): SendLocationState { + return SendLocationState( + permissionDialog = permissionDialog, + mode = mode, + hasLocationPermission = hasLocationPermission, + appName = APP_NAME, + eventSink = {} + ) +} diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt new file mode 100644 index 0000000000..8fe90bea57 --- /dev/null +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/PermissionsStateFactory.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.location.impl + +import io.element.android.features.location.impl.common.permissions.PermissionsState + +fun aPermissionsState( + permissions: PermissionsState.Permissions = PermissionsState.Permissions.NoneGranted, + shouldShowRationale: Boolean = false, +): PermissionsState { + return PermissionsState( + permissions = permissions, + shouldShowRationale = shouldShowRationale, + eventSink = {}, + ) +} diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenterFake.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenterFake.kt index ad653e4df4..dfeb18d4db 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenterFake.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/permissions/PermissionsPresenterFake.kt @@ -26,7 +26,11 @@ class PermissionsPresenterFake : PermissionsPresenter { events += event } - private var state = PermissionsState(eventSink = ::handleEvent) + private var state = PermissionsState( + permissions = PermissionsState.Permissions.NoneGranted, + shouldShowRationale = false, + eventSink = ::handleEvent + ) set(value) { field = value.copy(eventSink = ::handleEvent) } diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt index c0b4cb7d35..1bb99f48ce 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt @@ -22,6 +22,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth import im.vector.app.features.analytics.plan.Composer import io.element.android.features.location.api.Location +import io.element.android.features.location.impl.aPermissionsState import io.element.android.features.location.impl.common.actions.FakeLocationActions import io.element.android.features.location.impl.common.permissions.PermissionsEvents import io.element.android.features.location.impl.common.permissions.PermissionsPresenter @@ -65,7 +66,7 @@ class SendLocationPresenterTest { @Test fun `initial state with permissions granted`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.AllGranted, shouldShowRationale = false, ) @@ -92,7 +93,7 @@ class SendLocationPresenterTest { @Test fun `initial state with permissions partially granted`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.SomeGranted, shouldShowRationale = false, ) @@ -119,7 +120,7 @@ class SendLocationPresenterTest { @Test fun `initial state with permissions denied`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -145,7 +146,7 @@ class SendLocationPresenterTest { @Test fun `initial state with permissions denied once`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = true, ) @@ -171,7 +172,7 @@ class SendLocationPresenterTest { @Test fun `rationale dialog dismiss`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = true, ) @@ -202,7 +203,7 @@ class SendLocationPresenterTest { @Test fun `rationale dialog continue`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = true, ) @@ -230,7 +231,7 @@ class SendLocationPresenterTest { @Test fun `permission denied dialog dismiss`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -261,7 +262,7 @@ class SendLocationPresenterTest { @Test fun `share sender location`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.AllGranted, shouldShowRationale = false, ) @@ -317,7 +318,7 @@ class SendLocationPresenterTest { @Test fun `share pin location`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -373,7 +374,7 @@ class SendLocationPresenterTest { @Test fun `composer context passes through analytics`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -419,7 +420,7 @@ class SendLocationPresenterTest { @Test fun `open settings activity`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt index 9eb0c3e1e2..28beb77819 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt @@ -21,6 +21,7 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth import io.element.android.features.location.api.Location +import io.element.android.features.location.impl.aPermissionsState import io.element.android.features.location.impl.common.actions.FakeLocationActions import io.element.android.features.location.impl.common.permissions.PermissionsEvents import io.element.android.features.location.impl.common.permissions.PermissionsPresenter @@ -55,7 +56,7 @@ class ShowLocationPresenterTest { @Test fun `emits initial state with no location permission`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -75,7 +76,7 @@ class ShowLocationPresenterTest { @Test fun `emits initial state location permission denied once`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = true, ) @@ -94,7 +95,7 @@ class ShowLocationPresenterTest { @Test fun `emits initial state with location permission`() = runTest { - permissionsPresenterFake.givenState(PermissionsState(permissions = PermissionsState.Permissions.AllGranted)) + permissionsPresenterFake.givenState(aPermissionsState(permissions = PermissionsState.Permissions.AllGranted)) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -109,7 +110,7 @@ class ShowLocationPresenterTest { @Test fun `emits initial state with partial location permission`() = runTest { - permissionsPresenterFake.givenState(PermissionsState(permissions = PermissionsState.Permissions.SomeGranted)) + permissionsPresenterFake.givenState(aPermissionsState(permissions = PermissionsState.Permissions.SomeGranted)) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -137,7 +138,7 @@ class ShowLocationPresenterTest { @Test fun `centers on user location`() = runTest { - permissionsPresenterFake.givenState(PermissionsState(permissions = PermissionsState.Permissions.AllGranted)) + permissionsPresenterFake.givenState(aPermissionsState(permissions = PermissionsState.Permissions.AllGranted)) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -166,7 +167,7 @@ class ShowLocationPresenterTest { @Test fun `rationale dialog dismiss`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = true, ) @@ -197,7 +198,7 @@ class ShowLocationPresenterTest { @Test fun `rationale dialog continue`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = true, ) @@ -225,7 +226,7 @@ class ShowLocationPresenterTest { @Test fun `permission denied dialog dismiss`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -256,7 +257,7 @@ class ShowLocationPresenterTest { @Test fun `open settings activity`() = runTest { permissionsPresenterFake.givenState( - PermissionsState( + aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, shouldShowRationale = false, ) @@ -290,7 +291,6 @@ class ShowLocationPresenterTest { } } - companion object { private const val A_DESCRIPTION = "My happy place" } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt index 9a2ceb7c4b..16436debf0 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt @@ -19,15 +19,14 @@ package io.element.android.features.roomdetails.impl.invite import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf data class RoomInviteMembersState( - val canInvite: Boolean = false, - val searchQuery: String = "", - val searchResults: SearchBarResultState> = SearchBarResultState.NotSearching(), - val selectedUsers: ImmutableList = persistentListOf(), - val isSearchActive: Boolean = false, - val eventSink: (RoomInviteMembersEvents) -> Unit = {}, + val canInvite: Boolean, + val searchQuery: String, + val searchResults: SearchBarResultState>, + val selectedUsers: ImmutableList, + val isSearchActive: Boolean, + val eventSink: (RoomInviteMembersEvents) -> Unit, ) data class InvitableUser( diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt index 00e9496c2a..f44d518fb5 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt @@ -18,20 +18,22 @@ package io.element.android.features.roomdetails.impl.invite import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList internal class RoomInviteMembersStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - RoomInviteMembersState(), - RoomInviteMembersState(canInvite = true, selectedUsers = aMatrixUserList().toImmutableList()), - RoomInviteMembersState(isSearchActive = true, searchQuery = "some query"), - RoomInviteMembersState(isSearchActive = true, searchQuery = "some query", selectedUsers = aMatrixUserList().toImmutableList()), - RoomInviteMembersState(isSearchActive = true, searchQuery = "some query", searchResults = SearchBarResultState.NoResults()), - RoomInviteMembersState( + aRoomInviteMembersState(), + aRoomInviteMembersState(canInvite = true, selectedUsers = aMatrixUserList().toImmutableList()), + aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query"), + aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query", selectedUsers = aMatrixUserList().toImmutableList()), + aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query", searchResults = SearchBarResultState.NoResults()), + aRoomInviteMembersState( isSearchActive = true, canInvite = true, searchQuery = "some query", @@ -48,7 +50,7 @@ internal class RoomInviteMembersStateProvider : PreviewParameterProvider> = SearchBarResultState.NotSearching(), + selectedUsers: ImmutableList = persistentListOf(), + isSearchActive: Boolean = false, +): RoomInviteMembersState { + return RoomInviteMembersState( + canInvite = canInvite, + searchQuery = searchQuery, + searchResults = searchResults, + selectedUsers = selectedUsers, + isSearchActive = isSearchActive, + eventSink = {}, + ) +} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsState.kt index 0d3423e179..957db2233e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsState.kt @@ -23,7 +23,7 @@ data class RoomMemberDetailsState( val userName: String?, val avatarUrl: String?, val isBlocked: Async, - val displayConfirmationDialog: ConfirmationDialog? = null, + val displayConfirmationDialog: ConfirmationDialog?, val isCurrentUser: Boolean, val eventSink: (RoomMemberDetailsEvents) -> Unit ) { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsStateProvider.kt index 6883b20898..b14b0e3634 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsStateProvider.kt @@ -37,6 +37,7 @@ fun aRoomMemberDetailsState() = RoomMemberDetailsState( userName = "Daniel", avatarUrl = null, isBlocked = Async.Success(false), + displayConfirmationDialog = null, isCurrentUser = false, eventSink = {}, ) diff --git a/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/Symbol.kt b/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/Symbol.kt index 36e8cdc34e..bb40c7dfa9 100644 --- a/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/Symbol.kt +++ b/libraries/maplibre-compose/src/main/kotlin/io/element/android/libraries/maplibre/compose/Symbol.kt @@ -50,7 +50,7 @@ internal class SymbolNode( * @param position the initial symbol position */ public class SymbolState( - position: LatLng = LatLng(0.0, 0.0) + position: LatLng ) { /** * Current position of the symbol.