diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt index 4df58ffc..5b66ddd8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomDirectoryService.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.api.session.room import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol import im.vector.matrix.android.api.util.Cancelable /** @@ -39,4 +40,10 @@ interface RoomDirectoryService { fun joinRoom(roomId: String, callback: MatrixCallback) + /** + * Fetches the overall metadata about protocols supported by the homeserver. + * Includes both the available protocols and all fields required for queries against each protocol. + */ + fun getThirdPartyProtocol(callback: MatrixCallback>) + } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/roomdirectory/PublicRoomsParams.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/roomdirectory/PublicRoomsParams.kt index 7b584fe6..e2af1c3c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/roomdirectory/PublicRoomsParams.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/roomdirectory/PublicRoomsParams.kt @@ -46,12 +46,12 @@ data class PublicRoomsParams( /** * Whether or not to include all known networks/protocols from application services on the homeserver. Defaults to false. */ - @Json(name = "includeAllNetworks") + @Json(name = "include_all_networks") var includeAllNetworks: Boolean = false, /** * The specific third party network/protocol to request from the homeserver. Can only be used if include_all_networks is false. */ - @Json(name = "thirdPartyInstanceId") + @Json(name = "third_party_instance_id") var thirdPartyInstanceId: String? = null ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/FieldType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/FieldType.kt new file mode 100644 index 00000000..2e9f6956 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/FieldType.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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 im.vector.matrix.android.api.session.room.model.thirdparty + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class FieldType( + /** + * Required. A regular expression for validation of a field's value. This may be relatively coarse to verify the value as the application + * service providing this protocol may apply additional + */ + @Json(name = "regexp") + val regexp: String? = null, + + /** + * Required. An placeholder serving as a valid example of the field value. + */ + @Json(name = "placeholder") + val placeholder: String? = null +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt new file mode 100644 index 00000000..11a347c0 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/RoomDirectoryData.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2019 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 im.vector.matrix.android.api.session.room.model.thirdparty + +/** + * This class describes a rooms directory server. + */ +data class RoomDirectoryData( + + /** + * The server name (might be null) + * Set null when the server is the current user's home server. + */ + val homeServer: String? = null, + + /** + * The display name (the server description) + */ + val displayName: String = DEFAULT_HOME_SERVER_NAME, + + /** + * The third party server identifier + */ + val thirdPartyInstanceId: String? = null, + + /** + * Tell if all the federated servers must be included + */ + val includeAllNetworks: Boolean = false, + + /** + * the avatar url + */ + val avatarUrl: String? = null +) { + + companion object { + const val DEFAULT_HOME_SERVER_NAME = "Matrix" + } + +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt new file mode 100644 index 00000000..a31df794 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocol.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2019 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 im.vector.matrix.android.api.session.room.model.thirdparty + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ThirdPartyProtocol( + /** + * Required. Fields which may be used to identify a third party user. These should be ordered to suggest the way that entities may be grouped, + * where higher groupings are ordered first. For example, the name of a network should be searched before the nickname of a user. + */ + @Json(name = "user_fields") + var userFields: List? = null, + + /** + * Required. Fields which may be used to identify a third party location. These should be ordered to suggest the way that + * entities may be grouped, where higher groupings are ordered first. For example, the name of a network should be + * searched before the name of a channel. + */ + @Json(name = "location_fields") + var locationFields: List? = null, + + /** + * Required. A content URI representing an icon for the third party protocol. + * + * FIXDOC: This field was not present in legacy Riot, and it is sometimes sent by the server (no not Required?) + */ + @Json(name = "icon") + var icon: String? = null, + + /** + * Required. The type definitions for the fields defined in the user_fields and location_fields. Each entry in those arrays MUST have an entry here. + * The string key for this object is field name itself. + * + * May be an empty object if no fields are defined. + */ + @Json(name = "field_types") + var fieldTypes: Map? = null, + + /** + * Required. A list of objects representing independent instances of configuration. For example, multiple networks on IRC + * if multiple are provided by the same application service. + */ + @Json(name = "instances") + var instances: List? = null +) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt new file mode 100644 index 00000000..d2bea700 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/thirdparty/ThirdPartyProtocolInstance.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2019 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 im.vector.matrix.android.api.session.room.model.thirdparty + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class ThirdPartyProtocolInstance( + /** + * Required. A human-readable description for the protocol, such as the name. + */ + @Json(name = "desc") + var desc: String? = null, + + /** + * An optional content URI representing the protocol. Overrides the one provided at the higher level Protocol object. + */ + @Json(name = "icon") + var icon: String? = null, + + /** + * Required. Preset values for fields the client may use to search by. + */ + @Json(name = "fields") + var fields: Map? = null, + + /** + * Required. A unique identifier across all instances. + */ + @Json(name = "network_id") + var networkId: String? = null, + + /** + * FIXDOC Not documented on matrix.org doc + */ + @Json(name = "instance_id") + var instanceId: String? = null, + + + /** + * FIXDOC Not documented on matrix.org doc + */ + @Json(name = "bot_user_id") + var botUserId: String? = null +) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index 501ae450..420d675c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -36,6 +36,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol import im.vector.matrix.android.api.session.signout.SignOutService import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.user.UserService @@ -188,6 +189,11 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi return roomDirectoryService.joinRoom(roomId, callback) } + override fun getThirdPartyProtocol(callback: MatrixCallback>) { + assert(isOpen) + return roomDirectoryService.getThirdPartyProtocol(callback) + } + // GROUP SERVICE override fun getGroup(groupId: String): Group? { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index ab6b46ca..6d8084c0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -36,7 +36,9 @@ import im.vector.matrix.android.internal.session.group.DefaultGroupService import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater import im.vector.matrix.android.internal.session.room.* import im.vector.matrix.android.internal.session.room.directory.DefaultGetPublicRoomTask +import im.vector.matrix.android.internal.session.room.directory.DefaultGetThirdPartyProtocolsTask import im.vector.matrix.android.internal.session.room.directory.GetPublicRoomTask +import im.vector.matrix.android.internal.session.room.directory.GetThirdPartyProtocolsTask import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver import im.vector.matrix.android.internal.session.room.membership.RoomMemberDisplayNameResolver import im.vector.matrix.android.internal.session.room.prune.EventsPruner @@ -116,7 +118,11 @@ internal class SessionModule(private val sessionParams: SessionParams) { } scope(DefaultSession.SCOPE) { - DefaultRoomDirectoryService(get(), get(), get()) as RoomDirectoryService + DefaultGetThirdPartyProtocolsTask(get()) as GetThirdPartyProtocolsTask + } + + scope(DefaultSession.SCOPE) { + DefaultRoomDirectoryService(get(), get(), get(), get()) as RoomDirectoryService } scope(DefaultSession.SCOPE) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt index 9534f169..1a434dd6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomDirectoryService.kt @@ -20,14 +20,17 @@ import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.room.RoomDirectoryService import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.session.room.directory.GetPublicRoomTask +import im.vector.matrix.android.internal.session.room.directory.GetThirdPartyProtocolsTask import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith internal class DefaultRoomDirectoryService(private val getPublicRoomTask: GetPublicRoomTask, private val joinRoomTask: JoinRoomTask, + private val getThirdPartyProtocolsTask: GetThirdPartyProtocolsTask, private val taskExecutor: TaskExecutor) : RoomDirectoryService { override fun getPublicRooms(server: String?, @@ -45,4 +48,11 @@ internal class DefaultRoomDirectoryService(private val getPublicRoomTask: GetPub .dispatchTo(callback) .executeBy(taskExecutor) } + + override fun getThirdPartyProtocol(callback: MatrixCallback>) { + getThirdPartyProtocolsTask + .configureWith(Unit) + .dispatchTo(callback) + .executeBy(taskExecutor) + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt index 9aed926d..af263970 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRooms import im.vector.matrix.android.internal.network.NetworkConstants import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol import im.vector.matrix.android.internal.session.room.send.SendResponse import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse @@ -33,6 +34,14 @@ import retrofit2.http.* internal interface RoomAPI { + /** + * Get the third party server protocols. + * + * Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-thirdparty-protocols + */ + @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "thirdparty/protocols") + fun thirdPartyProtocols(): Call> + /** * Lists the public rooms on the server, with optional filter. * This API returns paginated responses. The rooms are ordered by the number of joined members, with the largest rooms first. diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/directory/GetThirdPartyProtocolsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/directory/GetThirdPartyProtocolsTask.kt new file mode 100644 index 00000000..58987717 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/directory/GetThirdPartyProtocolsTask.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2019 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 im.vector.matrix.android.internal.session.room.directory + +import arrow.core.Try +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.session.room.RoomAPI +import im.vector.matrix.android.internal.task.Task + +internal interface GetThirdPartyProtocolsTask : Task> + +internal class DefaultGetThirdPartyProtocolsTask(private val roomAPI: RoomAPI) : GetThirdPartyProtocolsTask { + + override fun execute(params: Unit): Try> { + return executeRequest { + apiCall = roomAPI.thirdPartyProtocols() + } + } +} diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt index 9505f80e..10703f88 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.Context.MODE_PRIVATE import im.vector.matrix.android.api.Matrix import im.vector.riotredesign.core.resources.LocaleProvider +import im.vector.riotredesign.core.resources.StringArrayProvider import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.features.home.group.SelectedGroupStore import im.vector.riotredesign.features.home.room.VisibleRoomStore @@ -40,6 +41,10 @@ class AppModule(private val context: Context) { StringProvider(context.resources) } + single { + StringArrayProvider(context.resources) + } + single { context.getSharedPreferences("im.vector.riot", MODE_PRIVATE) } diff --git a/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt index e90be743..1467071b 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt @@ -18,26 +18,26 @@ package im.vector.riotredesign.core.extensions import androidx.fragment.app.Fragment -fun androidx.fragment.app.Fragment.addFragment(fragment: Fragment, frameId: Int) { +fun Fragment.addFragment(fragment: Fragment, frameId: Int) { fragmentManager?.inTransaction { add(frameId, fragment) } } -fun androidx.fragment.app.Fragment.replaceFragment(fragment: Fragment, frameId: Int) { +fun Fragment.replaceFragment(fragment: Fragment, frameId: Int) { fragmentManager?.inTransaction { replace(frameId, fragment) } } -fun androidx.fragment.app.Fragment.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) { +fun Fragment.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) { fragmentManager?.inTransaction { replace(frameId, fragment).addToBackStack(tag) } } -fun androidx.fragment.app.Fragment.addChildFragment(fragment: Fragment, frameId: Int) { +fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) { childFragmentManager.inTransaction { add(frameId, fragment) } } -fun androidx.fragment.app.Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) { +fun Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) { childFragmentManager.inTransaction { replace(frameId, fragment) } } -fun androidx.fragment.app.Fragment.addChildFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) { +fun Fragment.addChildFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) { childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/extensions/TextView.kt b/vector/src/main/java/im/vector/riotredesign/core/extensions/TextView.kt new file mode 100644 index 00000000..30ebbd2b --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/extensions/TextView.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.core.extensions + +import android.widget.TextView +import androidx.core.view.isVisible + +/** + * Set a text in the TextView, or set visibility to GONE it if the text is null + */ +fun TextView.setTextOrHide(newText: String?, hideWhenBlank: Boolean = true) { + if (newText == null + || (newText.isBlank() && hideWhenBlank)) { + isVisible = false + } else { + this.text = newText + isVisible = true + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt index 43dec625..a8ca670a 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt @@ -100,7 +100,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed { override fun invalidate() { //no-ops by default - // TODO Remove default implementation? + Timber.w("invalidate() method has not been implemented") } protected fun setArguments(args: Parcelable? = null) { diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt new file mode 100644 index 00000000..f8e58d76 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.core.resources + +import android.content.res.Resources +import androidx.annotation.ArrayRes +import androidx.annotation.NonNull + +class StringArrayProvider(private val resources: Resources) { + + /** + * Returns a localized string array from the application's package's + * default string array table. + * + * @param resId Resource id for the string array + * @return The string array associated with the resource, stripped of styled + * text information. + */ + @NonNull + fun getStringArray(@ArrayRes resId: Int): Array { + return resources.getStringArray(resId) + } + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt similarity index 78% rename from vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryItem.kt rename to vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt index eea4c8ea..47fb9995 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt @@ -29,10 +29,9 @@ import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder import im.vector.riotredesign.core.epoxy.VectorEpoxyModel import im.vector.riotredesign.features.home.AvatarRenderer -@EpoxyModelClass(layout = R.layout.item_room_directory) -abstract class RoomDirectoryItem : VectorEpoxyModel() { +@EpoxyModelClass(layout = R.layout.item_public_room) +abstract class PublicRoomItem : VectorEpoxyModel() { - // TODO Manage join state waiting from the sync enum class JoinState { NOT_JOINED, JOINING, @@ -82,15 +81,15 @@ abstract class RoomDirectoryItem : VectorEpoxyModel() class Holder : VectorEpoxyHolder() { - val rootView by bind(R.id.itemRoomDirectoryLayout) + val rootView by bind(R.id.itemPublicRoomLayout) - val avatarView by bind(R.id.itemRoomDirectoryAvatar) - val nameView by bind(R.id.itemRoomDirectoryName) - val counterView by bind(R.id.itemRoomDirectoryMembersCount) + val avatarView by bind(R.id.itemPublicRoomAvatar) + val nameView by bind(R.id.itemPublicRoomName) + val counterView by bind(R.id.itemPublicRoomMembersCount) - val joinedView by bind(R.id.itemRoomDirectoryJoined) - val joinButton by bind(R.id.itemRoomDirectoryJoin) - val joiningView by bind(R.id.itemRoomDirectoryJoining) + val joinedView by bind(R.id.itemPublicRoomJoined) + val joinButton by bind(R.id.itemPublicRoomJoin) + val joiningView by bind(R.id.itemPublicRoomJoining) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryController.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt similarity index 89% rename from vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryController.kt rename to vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt index 722d487f..f530a918 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt @@ -28,11 +28,11 @@ import im.vector.riotredesign.core.epoxy.loadingItem import im.vector.riotredesign.core.epoxy.noResultItem import im.vector.riotredesign.core.resources.StringProvider -class RoomDirectoryController(private val stringProvider: StringProvider) : TypedEpoxyController() { +class PublicRoomsController(private val stringProvider: StringProvider) : TypedEpoxyController() { var callback: Callback? = null - override fun buildModels(viewState: RoomDirectoryViewState) { + override fun buildModels(viewState: PublicRoomsViewState) { val publicRooms = viewState.publicRooms if (publicRooms.isEmpty() @@ -74,17 +74,17 @@ class RoomDirectoryController(private val stringProvider: StringProvider) : Type } } - private fun buildPublicRoom(publicRoom: PublicRoom, viewState: RoomDirectoryViewState) { - roomDirectoryItem { + private fun buildPublicRoom(publicRoom: PublicRoom, viewState: PublicRoomsViewState) { + publicRoomItem { id(publicRoom.roomId) roomId(publicRoom.roomId) avatarUrl(publicRoom.avatarUrl) roomName(publicRoom.name) nbOfMembers(publicRoom.numJoinedMembers) when { - viewState.joinedRoomsIds.contains(publicRoom.roomId) -> joinState(RoomDirectoryItem.JoinState.JOINED) - viewState.joiningRoomsIds.contains(publicRoom.roomId) -> joinState(RoomDirectoryItem.JoinState.JOINING) - else -> joinState(RoomDirectoryItem.JoinState.NOT_JOINED) + viewState.joinedRoomsIds.contains(publicRoom.roomId) -> joinState(PublicRoomItem.JoinState.JOINED) + viewState.joiningRoomsIds.contains(publicRoom.roomId) -> joinState(PublicRoomItem.JoinState.JOINING) + else -> joinState(PublicRoomItem.JoinState.NOT_JOINED) } joinListener { callback?.onPublicRoomJoin(publicRoom) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt similarity index 67% rename from vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryFragment.kt rename to vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt index 0e6c450b..0d4b4ab6 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt @@ -21,13 +21,15 @@ import android.text.Editable import android.view.View import androidx.recyclerview.widget.LinearLayoutManager import com.airbnb.epoxy.EpoxyVisibilityTracker -import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom import im.vector.riotredesign.R +import im.vector.riotredesign.core.extensions.addFragmentToBackstack import im.vector.riotredesign.core.platform.SimpleTextWatcher import im.vector.riotredesign.core.platform.VectorBaseFragment -import kotlinx.android.synthetic.main.fragment_room_directory.* +import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment +import kotlinx.android.synthetic.main.fragment_public_rooms.* import org.koin.android.ext.android.get import timber.log.Timber @@ -38,19 +40,21 @@ import timber.log.Timber * * FIXME Rotate screen launch again the request * - * For Nad: + * TODO For Nad: * Display number of rooms? * Picto size are not correct * Where I put the room directory picker? + * World Readable badge + * Guest can join badge * */ -class RoomDirectoryFragment : VectorBaseFragment(), RoomDirectoryController.Callback { +class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback { - private val viewModel: RoomDirectoryViewModel by fragmentViewModel() + private val viewModel: RoomDirectoryViewModel by activityViewModel() - private val roomDirectoryController = RoomDirectoryController(get()) + private val publicRoomsController = PublicRoomsController(get()) - override fun getLayoutResId() = R.layout.fragment_room_directory + override fun getLayoutResId() = R.layout.fragment_public_rooms override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -62,16 +66,20 @@ class RoomDirectoryFragment : VectorBaseFragment(), RoomDirectoryController.Call it.setDisplayHomeAsUpEnabled(true) } - roomDirectoryFilter.addTextChangedListener(object : SimpleTextWatcher() { + publicRoomsFilter.addTextChangedListener(object : SimpleTextWatcher() { override fun afterTextChanged(s: Editable) { // TODO Debounce - viewModel.filterWith(roomDirectoryFilter.text.toString()) + viewModel.filterWith(publicRoomsFilter.text.toString()) } }) - createNewRoom.setOnClickListener { + publicRoomsCreateNewRoom.setOnClickListener { vectorBaseActivity.notImplemented() } + + publicRoomsChangeDirectory.setOnClickListener { + vectorBaseActivity.addFragmentToBackstack(RoomDirectoryPickerFragment(), R.id.simpleFragmentContainer) + } } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -82,14 +90,14 @@ class RoomDirectoryFragment : VectorBaseFragment(), RoomDirectoryController.Call private fun setupRecyclerView() { val epoxyVisibilityTracker = EpoxyVisibilityTracker() - epoxyVisibilityTracker.attach(roomDirectoryList) + epoxyVisibilityTracker.attach(publicRoomsList) val layoutManager = LinearLayoutManager(context) - roomDirectoryList.layoutManager = layoutManager - roomDirectoryController.callback = this + publicRoomsList.layoutManager = layoutManager + publicRoomsController.callback = this - roomDirectoryList.setController(roomDirectoryController) + publicRoomsList.setController(publicRoomsController) } override fun onPublicRoomClicked(publicRoom: PublicRoom) { @@ -108,6 +116,9 @@ class RoomDirectoryFragment : VectorBaseFragment(), RoomDirectoryController.Call override fun invalidate() = withState(viewModel) { state -> // Populate list with Epoxy - roomDirectoryController.setData(state) + publicRoomsController.setData(state) + + // Directory name + publicRoomsDirectoryName.text = state.roomDirectoryDisplayName } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsViewModel.kt similarity index 82% rename from vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt rename to vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsViewModel.kt index 11d92ac1..d00798a9 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsViewModel.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsFilter import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse +import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.rx.rx import im.vector.riotredesign.core.platform.VectorViewModel @@ -32,13 +33,13 @@ import timber.log.Timber private const val PUBLIC_ROOMS_LIMIT = 20 -class RoomDirectoryViewModel(initialState: RoomDirectoryViewState, - private val session: Session) : VectorViewModel(initialState) { +class RoomDirectoryViewModel(initialState: PublicRoomsViewState, + private val session: Session) : VectorViewModel(initialState) { - companion object : MvRxViewModelFactory { + companion object : MvRxViewModelFactory { @JvmStatic - override fun create(viewModelContext: ViewModelContext, state: RoomDirectoryViewState): RoomDirectoryViewModel? { + override fun create(viewModelContext: ViewModelContext, state: PublicRoomsViewState): RoomDirectoryViewModel? { val currentSession = viewModelContext.activity.get() return RoomDirectoryViewModel(state, currentSession) @@ -52,10 +53,19 @@ class RoomDirectoryViewModel(initialState: RoomDirectoryViewState, private var currentTask: Cancelable? = null + // Default RoomDirectoryData + private var roomDirectoryData = RoomDirectoryData() + init { // Load with empty filter load() + setState { + copy( + roomDirectoryDisplayName = roomDirectoryData.displayName + ) + } + // Observe joined room (from the sync) observeJoinedRooms() } @@ -84,11 +94,33 @@ class RoomDirectoryViewModel(initialState: RoomDirectoryViewState, } } + fun setRoomDirectoryData(roomDirectoryData: RoomDirectoryData) { + if (this.roomDirectoryData == roomDirectoryData) { + return + } + + this.roomDirectoryData = roomDirectoryData + + reset() + + load() + } + fun filterWith(filter: String) { + if (currentFilter == filter) { + return + } + currentTask?.cancel() currentFilter = filter + reset() + + load() + } + + private fun reset() { // Reset since token since = null @@ -96,10 +128,10 @@ class RoomDirectoryViewModel(initialState: RoomDirectoryViewState, copy( publicRooms = emptyList(), asyncPublicRoomsRequest = Loading(), - hasMore = false) + hasMore = false, + roomDirectoryDisplayName = roomDirectoryData.displayName + ) } - - load() } fun loadMore() { @@ -115,13 +147,13 @@ class RoomDirectoryViewModel(initialState: RoomDirectoryViewState, } private fun load() { - currentTask = session.getPublicRooms(null, // TODO session.sessionParams.homeServerConnectionConfig.homeServerUri.toString(), + currentTask = session.getPublicRooms(roomDirectoryData.homeServer, PublicRoomsParams( limit = PUBLIC_ROOMS_LIMIT, filter = PublicRoomsFilter(searchTerm = currentFilter), - includeAllNetworks = false, // TODO + includeAllNetworks = roomDirectoryData.includeAllNetworks, since = since, - thirdPartyInstanceId = null // TODO + thirdPartyInstanceId = roomDirectoryData.thirdPartyInstanceId ), object : MatrixCallback { override fun onSuccess(data: PublicRoomsResponse) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewState.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsViewState.kt similarity index 90% rename from vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewState.kt rename to vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsViewState.kt index feab9597..3c02a1f1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewState.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsViewState.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.Uninitialized import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom -data class RoomDirectoryViewState( +data class PublicRoomsViewState( // Store cumul of pagination result val publicRooms: List = emptyList(), // Current pagination request @@ -31,5 +31,6 @@ data class RoomDirectoryViewState( // List of roomIds that the user wants to join val joiningRoomsIds: List = emptyList(), // List of joined roomId, - val joinedRoomsIds: List = emptyList() + val joinedRoomsIds: List = emptyList(), + val roomDirectoryDisplayName: String? = null ) : MvRxState \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt index a32f0a20..96f3c0bf 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt @@ -27,7 +27,7 @@ class RoomDirectoryActivity : VectorBaseActivity() { override fun initUiAndData() { if (isFirstCreation()) { - addFragment(RoomDirectoryFragment(), R.id.simpleFragmentContainer) + addFragment(PublicRoomsFragment(), R.id.simpleFragmentContainer) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryItem.kt new file mode 100644 index 00000000..e4b280f4 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryItem.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.features.roomdirectory.picker + +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.riotredesign.R +import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder +import im.vector.riotredesign.core.epoxy.VectorEpoxyModel +import im.vector.riotredesign.core.extensions.setTextOrHide +import im.vector.riotredesign.core.glide.GlideApp + +@EpoxyModelClass(layout = R.layout.item_room_directory) +abstract class RoomDirectoryItem : VectorEpoxyModel() { + + @EpoxyAttribute + var directoryAvatarUrl: String? = null + + @EpoxyAttribute + var directoryName: String? = null + + @EpoxyAttribute + var directoryDescription: String? = null + + @EpoxyAttribute + var includeAllNetworks: Boolean = false + + @EpoxyAttribute + var globalListener: (() -> Unit)? = null + + override fun bind(holder: Holder) { + holder.rootView.setOnClickListener { globalListener?.invoke() } + + // Avatar + GlideApp.with(holder.avatarView) + .load(directoryAvatarUrl) + .apply { + if (!includeAllNetworks) { + placeholder(R.drawable.network_matrix) + } + } + .into(holder.avatarView) + + holder.nameView.text = directoryName + holder.descritionView.setTextOrHide(directoryDescription) + } + + + class Holder : VectorEpoxyHolder() { + val rootView by bind(R.id.itemRoomDirectoryLayout) + + val avatarView by bind(R.id.itemRoomDirectoryAvatar) + val nameView by bind(R.id.itemRoomDirectoryName) + val descritionView by bind(R.id.itemRoomDirectoryDescription) + } + +} + diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt new file mode 100644 index 00000000..dba68ffc --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.features.roomdirectory.picker + +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Incomplete +import com.airbnb.mvrx.Success +import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol +import im.vector.riotredesign.R +import im.vector.riotredesign.core.epoxy.errorWithRetryItem +import im.vector.riotredesign.core.epoxy.loadingItem +import im.vector.riotredesign.core.resources.StringArrayProvider +import im.vector.riotredesign.core.resources.StringProvider + +class RoomDirectoryPickerController(private val stringProvider: StringProvider, + private val stringArrayProvider: StringArrayProvider, + private val credentials: Credentials +) : TypedEpoxyController() { + + var callback: Callback? = null + + var index = 0 + + override fun buildModels(viewState: RoomDirectoryPickerViewState) { + val asyncThirdPartyProtocol = viewState.asyncThirdPartyRequest + + when (asyncThirdPartyProtocol) { + is Success -> { + val directories = computeDirectories(asyncThirdPartyProtocol.invoke()) + + directories.forEach { + buildDirectory(it) + } + } + is Incomplete -> { + loadingItem { + id("loading") + } + } + is Fail -> { + errorWithRetryItem { + id("error") + text(asyncThirdPartyProtocol.error.localizedMessage) + listener { callback?.retry() } + } + } + } + } + + private fun computeDirectories(thirdPartyProtocolData: Map): List { + val result = ArrayList() + + // Add user homeserver name + val userHsName = credentials.userId.substring(credentials.userId.indexOf(":") + 1) + + result.add(RoomDirectoryData( + displayName = userHsName, + includeAllNetworks = true + )) + + // Add user's HS but for Matrix public rooms only + result.add(RoomDirectoryData()) + + // Add custom directory servers + val hsNamesList = stringArrayProvider.getStringArray(R.array.room_directory_servers) + hsNamesList.forEach { + if (it != userHsName) { + // Use the server name as a default display name + result.add(RoomDirectoryData( + displayName = it, + includeAllNetworks = true + )) + } + } + + // Add result of the request + thirdPartyProtocolData.forEach { + it.value.instances?.forEach { thirdPartyProtocolInstance -> + result.add(RoomDirectoryData( + homeServer = null, + displayName = thirdPartyProtocolInstance.desc ?: "", + thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId, + includeAllNetworks = false, + // Default to protocol icon + avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon + )) + } + } + + return result + } + + private fun buildDirectory(roomDirectoryData: RoomDirectoryData) { + + // TODO + roomDirectoryItem { + id(index++) + + directoryName(roomDirectoryData.displayName) + + val description = when { + roomDirectoryData.includeAllNetworks -> stringProvider.getString(R.string.directory_server_all_rooms_on_server, roomDirectoryData.displayName) + "Matrix" == roomDirectoryData.displayName -> stringProvider.getString(R.string.directory_server_native_rooms, roomDirectoryData.displayName) + else -> null + } + + directoryDescription(description) + directoryAvatarUrl(roomDirectoryData.avatarUrl) + includeAllNetworks(roomDirectoryData.includeAllNetworks) + + globalListener { + callback?.onRoomDirectoryClicked(roomDirectoryData) + } + } + } + + interface Callback { + fun onRoomDirectoryClicked(roomDirectory: RoomDirectoryData) + fun retry() + } + +} diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt new file mode 100644 index 00000000..f27dad0b --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.features.roomdirectory.picker + +import android.os.Bundle +import android.view.MenuItem +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import com.airbnb.mvrx.activityViewModel +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData +import im.vector.riotredesign.R +import im.vector.riotredesign.core.platform.VectorBaseFragment +import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel +import kotlinx.android.synthetic.main.fragment_public_rooms.toolbar +import kotlinx.android.synthetic.main.fragment_room_directory_picker.* +import org.koin.android.ext.android.get +import timber.log.Timber + +// TODO Set title to R.string.select_room_directory +// TODO Menu to add custom room directory (not done in RiotWeb so far...) +class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerController.Callback { + private val viewModel: RoomDirectoryViewModel by activityViewModel() + + private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel() + + private val roomDirectoryPickerController = RoomDirectoryPickerController(get(), get(), get().sessionParams.credentials) + + override fun getLayoutResId() = R.layout.fragment_room_directory_picker + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + vectorBaseActivity.setSupportActionBar(toolbar) + + vectorBaseActivity.supportActionBar?.let { + it.setDisplayShowHomeEnabled(true) + it.setDisplayHomeAsUpEnabled(true) + } + } + + override fun getMenuRes() = R.menu.menu_directory_server_picker + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == R.id.action_add_custom_hs) { + // TODO + vectorBaseActivity.notImplemented() + return true + } + + return super.onOptionsItemSelected(item) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + setupRecyclerView() + } + + private fun setupRecyclerView() { + val layoutManager = LinearLayoutManager(context) + + roomDirectoryPickerList.layoutManager = layoutManager + roomDirectoryPickerController.callback = this + + roomDirectoryPickerList.setController(roomDirectoryPickerController) + } + + + override fun onRoomDirectoryClicked(roomDirectoryData: RoomDirectoryData) { + Timber.v("onRoomDirectoryClicked: $roomDirectoryData") + viewModel.setRoomDirectoryData(roomDirectoryData) + + // TODO Not the bast way to manage Fragment Backstack... + vectorBaseActivity.onBackPressed() + } + + override fun retry() { + Timber.v("Retry") + pickerViewModel.load() + } + + override fun invalidate() = withState(pickerViewModel) { state -> + // Populate list with Epoxy + roomDirectoryPickerController.setData(state) + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt new file mode 100644 index 00000000..30e687e9 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.features.roomdirectory.picker + +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.ViewModelContext +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol +import im.vector.riotredesign.core.platform.VectorViewModel +import org.koin.android.ext.android.get + +class RoomDirectoryPickerViewModel(initialState: RoomDirectoryPickerViewState, + private val session: Session) : VectorViewModel(initialState) { + + companion object : MvRxViewModelFactory { + + @JvmStatic + override fun create(viewModelContext: ViewModelContext, state: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel? { + val currentSession = viewModelContext.activity.get() + + return RoomDirectoryPickerViewModel(state, currentSession) + } + } + + init { + load() + } + + fun load() { + session.getThirdPartyProtocol(object : MatrixCallback> { + override fun onSuccess(data: Map) { + setState { + copy(asyncThirdPartyRequest = Success(data)) + } + } + + override fun onFailure(failure: Throwable) { + setState { + copy(asyncThirdPartyRequest = Fail(failure)) + } + } + }) + } + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt new file mode 100644 index 00000000..81b10812 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2019 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 im.vector.riotredesign.features.roomdirectory.picker + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol + +data class RoomDirectoryPickerViewState( + val asyncThirdPartyRequest: Async> = Uninitialized +) : MvRxState \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_room_directory.xml b/vector/src/main/res/layout/fragment_public_rooms.xml similarity index 69% rename from vector/src/main/res/layout/fragment_room_directory.xml rename to vector/src/main/res/layout/fragment_public_rooms.xml index 5532cb5c..8948af4c 100644 --- a/vector/src/main/res/layout/fragment_room_directory.xml +++ b/vector/src/main/res/layout/fragment_public_rooms.xml @@ -8,11 +8,11 @@ android:background="@color/pale_grey"> + tools:listitem="@layout/item_public_room" />