forked from GitHub-Mirror/riotX-android
Merge pull request #150 from vector-im/feature/rooms_directory
Feature/rooms directory
This commit is contained in:
commit
0feb10315b
@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
|
|||||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||||
import im.vector.matrix.android.api.session.group.GroupService
|
import im.vector.matrix.android.api.session.group.GroupService
|
||||||
|
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||||
import im.vector.matrix.android.api.session.room.RoomService
|
import im.vector.matrix.android.api.session.room.RoomService
|
||||||
import im.vector.matrix.android.api.session.signout.SignOutService
|
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.sync.FilterService
|
||||||
@ -34,6 +35,7 @@ import im.vector.matrix.android.api.session.user.UserService
|
|||||||
*/
|
*/
|
||||||
interface Session :
|
interface Session :
|
||||||
RoomService,
|
RoomService,
|
||||||
|
RoomDirectoryService,
|
||||||
GroupService,
|
GroupService,
|
||||||
UserService,
|
UserService,
|
||||||
CryptoService,
|
CryptoService,
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface defines methods to get and join public rooms. It's implemented at the session level.
|
||||||
|
*/
|
||||||
|
interface RoomDirectoryService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get rooms from directory
|
||||||
|
*/
|
||||||
|
fun getPublicRooms(server: String?,
|
||||||
|
publicRoomsParams: PublicRoomsParams,
|
||||||
|
callback: MatrixCallback<PublicRoomsResponse>): Cancelable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join a room by id
|
||||||
|
*/
|
||||||
|
fun joinRoom(roomId: String,
|
||||||
|
callback: MatrixCallback<Unit>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<Map<String, ThirdPartyProtocol>>)
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 OpenMarket 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.roomdirectory
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the objects returned by /publicRooms call.
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class PublicRoom(
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases of the room. May be empty.
|
||||||
|
*/
|
||||||
|
@Json(name = "aliases")
|
||||||
|
var aliases: List<String>? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The canonical alias of the room, if any.
|
||||||
|
*/
|
||||||
|
@Json(name = "canonical_alias")
|
||||||
|
var canonicalAlias: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the room, if any.
|
||||||
|
*/
|
||||||
|
@Json(name = "name")
|
||||||
|
var name: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. The number of members joined to the room.
|
||||||
|
*/
|
||||||
|
@Json(name = "num_joined_members")
|
||||||
|
var numJoinedMembers: Int = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. The ID of the room.
|
||||||
|
*/
|
||||||
|
@Json(name = "room_id")
|
||||||
|
var roomId: String,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The topic of the room, if any.
|
||||||
|
*/
|
||||||
|
@Json(name = "topic")
|
||||||
|
var topic: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. Whether the room may be viewed by guest users without joining.
|
||||||
|
*/
|
||||||
|
@Json(name = "world_readable")
|
||||||
|
var worldReadable: Boolean = false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required. Whether guest users may join the room and participate in it. If they can, they will be subject to ordinary power level rules like any other user.
|
||||||
|
*/
|
||||||
|
@Json(name = "guest_can_join")
|
||||||
|
var guestCanJoin: Boolean = false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL for the room's avatar, if one is set.
|
||||||
|
*/
|
||||||
|
@Json(name = "avatar_url")
|
||||||
|
var avatarUrl: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented item
|
||||||
|
*/
|
||||||
|
@Json(name = "m.federate")
|
||||||
|
var isFederated: Boolean = false
|
||||||
|
|
||||||
|
)
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 OpenMarket 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.roomdirectory
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to define a filter to retrieve public rooms
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class PublicRoomsFilter(
|
||||||
|
/**
|
||||||
|
* A string to search for in the room metadata, e.g. name, topic, canonical alias etc. (Optional).
|
||||||
|
*/
|
||||||
|
@Json(name = "generic_search_term")
|
||||||
|
var searchTerm: String? = null
|
||||||
|
)
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 OpenMarket Ltd
|
||||||
|
* Copyright 2017 Vector Creations 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.roomdirectory
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to pass parameters to get the public rooms list
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class PublicRoomsParams(
|
||||||
|
/**
|
||||||
|
* Limit the number of results returned.
|
||||||
|
*/
|
||||||
|
@Json(name = "limit")
|
||||||
|
var limit: Int? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pagination token from a previous request, allowing clients to get the next (or previous) batch of rooms.
|
||||||
|
* The direction of pagination is specified solely by which token is supplied, rather than via an explicit flag.
|
||||||
|
*/
|
||||||
|
@Json(name = "since")
|
||||||
|
var since: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to apply to the results.
|
||||||
|
*/
|
||||||
|
@Json(name = "filter")
|
||||||
|
var filter: PublicRoomsFilter? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to include all known networks/protocols from application services on the homeserver. Defaults to false.
|
||||||
|
*/
|
||||||
|
@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 = "third_party_instance_id")
|
||||||
|
var thirdPartyInstanceId: String? = null
|
||||||
|
)
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 OpenMarket 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.roomdirectory
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the public rooms request response
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class PublicRoomsResponse(
|
||||||
|
/**
|
||||||
|
* A pagination token for the response. The absence of this token means there are no more results to fetch and the client should stop paginating.
|
||||||
|
*/
|
||||||
|
@Json(name = "next_batch")
|
||||||
|
var nextBatch: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pagination token that allows fetching previous results. The absence of this token means there are no results before this batch,
|
||||||
|
* i.e. this is the first batch.
|
||||||
|
*/
|
||||||
|
@Json(name = "prev_batch")
|
||||||
|
var prevBatch: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A paginated chunk of public rooms.
|
||||||
|
*/
|
||||||
|
@Json(name = "chunk")
|
||||||
|
var chunk: List<PublicRoom>? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An estimate on the total number of public rooms, if the server has an estimate.
|
||||||
|
*/
|
||||||
|
@Json(name = "total_room_count_estimate")
|
||||||
|
var totalRoomCountEstimate: Int? = null
|
||||||
|
)
|
@ -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
|
||||||
|
)
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<String>? = 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<String>? = 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<String, FieldType>? = 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<ThirdPartyProtocolInstance>? = null
|
||||||
|
)
|
@ -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<String, Any>? = 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
|
||||||
|
)
|
@ -30,13 +30,18 @@ import im.vector.matrix.android.api.session.group.Group
|
|||||||
import im.vector.matrix.android.api.session.group.GroupService
|
import im.vector.matrix.android.api.session.group.GroupService
|
||||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
import im.vector.matrix.android.api.session.room.Room
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
|
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||||
import im.vector.matrix.android.api.session.room.RoomService
|
import im.vector.matrix.android.api.session.room.RoomService
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
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.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.signout.SignOutService
|
||||||
import im.vector.matrix.android.api.session.sync.FilterService
|
import im.vector.matrix.android.api.session.sync.FilterService
|
||||||
import im.vector.matrix.android.api.session.user.UserService
|
import im.vector.matrix.android.api.session.user.UserService
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.api.util.MatrixCallbackDelegate
|
import im.vector.matrix.android.api.util.MatrixCallbackDelegate
|
||||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
||||||
@ -64,6 +69,7 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||||||
private val liveEntityUpdaters by inject<List<LiveEntityObserver>>()
|
private val liveEntityUpdaters by inject<List<LiveEntityObserver>>()
|
||||||
private val sessionListeners by inject<SessionListeners>()
|
private val sessionListeners by inject<SessionListeners>()
|
||||||
private val roomService by inject<RoomService>()
|
private val roomService by inject<RoomService>()
|
||||||
|
private val roomDirectoryService by inject<RoomDirectoryService>()
|
||||||
private val groupService by inject<GroupService>()
|
private val groupService by inject<GroupService>()
|
||||||
private val userService by inject<UserService>()
|
private val userService by inject<UserService>()
|
||||||
private val filterService by inject<FilterService>()
|
private val filterService by inject<FilterService>()
|
||||||
@ -171,6 +177,23 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||||||
return roomService.liveRoomSummaries()
|
return roomService.liveRoomSummaries()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ROOM DIRECTORY SERVICE
|
||||||
|
|
||||||
|
override fun getPublicRooms(server: String?, publicRoomsParams: PublicRoomsParams, callback: MatrixCallback<PublicRoomsResponse>): Cancelable {
|
||||||
|
assert(isOpen)
|
||||||
|
return roomDirectoryService.getPublicRooms(server, publicRoomsParams, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun joinRoom(roomId: String, callback: MatrixCallback<Unit>) {
|
||||||
|
assert(isOpen)
|
||||||
|
return roomDirectoryService.joinRoom(roomId, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getThirdPartyProtocol(callback: MatrixCallback<Map<String, ThirdPartyProtocol>>) {
|
||||||
|
assert(isOpen)
|
||||||
|
return roomDirectoryService.getThirdPartyProtocol(callback)
|
||||||
|
}
|
||||||
|
|
||||||
// GROUP SERVICE
|
// GROUP SERVICE
|
||||||
|
|
||||||
override fun getGroup(groupId: String): Group? {
|
override fun getGroup(groupId: String): Group? {
|
||||||
|
@ -21,6 +21,7 @@ import com.zhuinden.monarchy.Monarchy
|
|||||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||||
import im.vector.matrix.android.api.session.cache.CacheService
|
import im.vector.matrix.android.api.session.cache.CacheService
|
||||||
import im.vector.matrix.android.api.session.group.GroupService
|
import im.vector.matrix.android.api.session.group.GroupService
|
||||||
|
import im.vector.matrix.android.api.session.room.RoomDirectoryService
|
||||||
import im.vector.matrix.android.api.session.room.RoomService
|
import im.vector.matrix.android.api.session.room.RoomService
|
||||||
import im.vector.matrix.android.api.session.signout.SignOutService
|
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.sync.FilterService
|
||||||
@ -33,10 +34,11 @@ import im.vector.matrix.android.internal.session.cache.RealmClearCacheTask
|
|||||||
import im.vector.matrix.android.internal.session.filter.*
|
import im.vector.matrix.android.internal.session.filter.*
|
||||||
import im.vector.matrix.android.internal.session.group.DefaultGroupService
|
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.group.GroupSummaryUpdater
|
||||||
import im.vector.matrix.android.internal.session.room.DefaultRoomService
|
import im.vector.matrix.android.internal.session.room.*
|
||||||
import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater
|
import im.vector.matrix.android.internal.session.room.directory.DefaultGetPublicRoomTask
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAvatarResolver
|
import im.vector.matrix.android.internal.session.room.directory.DefaultGetThirdPartyProtocolsTask
|
||||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
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.RoomDisplayNameResolver
|
||||||
import im.vector.matrix.android.internal.session.room.membership.RoomMemberDisplayNameResolver
|
import im.vector.matrix.android.internal.session.room.membership.RoomMemberDisplayNameResolver
|
||||||
import im.vector.matrix.android.internal.session.room.prune.EventsPruner
|
import im.vector.matrix.android.internal.session.room.prune.EventsPruner
|
||||||
@ -111,6 +113,18 @@ internal class SessionModule(private val sessionParams: SessionParams) {
|
|||||||
DefaultRoomService(get(), get(), get(), get()) as RoomService
|
DefaultRoomService(get(), get(), get(), get()) as RoomService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
DefaultGetPublicRoomTask(get()) as GetPublicRoomTask
|
||||||
|
}
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
DefaultGetThirdPartyProtocolsTask(get()) as GetThirdPartyProtocolsTask
|
||||||
|
}
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
DefaultRoomDirectoryService(get(), get(), get(), get()) as RoomDirectoryService
|
||||||
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
DefaultGroupService(get()) as GroupService
|
DefaultGroupService(get()) as GroupService
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
|||||||
|
|
||||||
|
|
||||||
private const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
|
private const val MATRIX_CONTENT_URI_SCHEME = "mxc://"
|
||||||
internal const val URI_PREFIX_CONTENT_API = "/_matrix/media/v1/"
|
internal const val URI_PREFIX_CONTENT_API = "_matrix/media/v1/"
|
||||||
|
|
||||||
internal class DefaultContentUrlResolver(private val homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {
|
internal class DefaultContentUrlResolver(private val homeServerConnectionConfig: HomeServerConnectionConfig) : ContentUrlResolver {
|
||||||
|
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
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?,
|
||||||
|
publicRoomsParams: PublicRoomsParams,
|
||||||
|
callback: MatrixCallback<PublicRoomsResponse>): Cancelable {
|
||||||
|
return getPublicRoomTask
|
||||||
|
.configureWith(GetPublicRoomTask.Params(server, publicRoomsParams))
|
||||||
|
.dispatchTo(callback)
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun joinRoom(roomId: String, callback: MatrixCallback<Unit>) {
|
||||||
|
joinRoomTask
|
||||||
|
.configureWith(JoinRoomTask.Params(roomId))
|
||||||
|
.dispatchTo(callback)
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getThirdPartyProtocol(callback: MatrixCallback<Map<String, ThirdPartyProtocol>>) {
|
||||||
|
getThirdPartyProtocolsTask
|
||||||
|
.configureWith(Unit)
|
||||||
|
.dispatchTo(callback)
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
}
|
||||||
|
}
|
@ -20,22 +20,39 @@ import im.vector.matrix.android.api.session.events.model.Content
|
|||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse
|
import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse
|
||||||
|
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.internal.network.NetworkConstants
|
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.RoomMembersResponse
|
||||||
import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody
|
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.send.SendResponse
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
|
import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.*
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.POST
|
|
||||||
import retrofit2.http.PUT
|
|
||||||
import retrofit2.http.Path
|
|
||||||
import retrofit2.http.Query
|
|
||||||
|
|
||||||
internal interface RoomAPI {
|
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<Map<String, ThirdPartyProtocol>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-publicrooms
|
||||||
|
*/
|
||||||
|
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "publicRooms")
|
||||||
|
fun publicRooms(@Query("server") server: String?,
|
||||||
|
@Body publicRoomsParams: PublicRoomsParams
|
||||||
|
): Call<PublicRoomsResponse>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a room.
|
* Create a room.
|
||||||
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-createroom
|
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-createroom
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.roomdirectory.PublicRoomsParams
|
||||||
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse
|
||||||
|
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 GetPublicRoomTask : Task<GetPublicRoomTask.Params, PublicRoomsResponse> {
|
||||||
|
data class Params(
|
||||||
|
val server: String?,
|
||||||
|
val publicRoomsParams: PublicRoomsParams
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultGetPublicRoomTask(private val roomAPI: RoomAPI) : GetPublicRoomTask {
|
||||||
|
|
||||||
|
override fun execute(params: GetPublicRoomTask.Params): Try<PublicRoomsResponse> {
|
||||||
|
return executeRequest {
|
||||||
|
apiCall = roomAPI.publicRooms(params.server, params.publicRoomsParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<Unit, Map<String, ThirdPartyProtocol>>
|
||||||
|
|
||||||
|
internal class DefaultGetThirdPartyProtocolsTask(private val roomAPI: RoomAPI) : GetThirdPartyProtocolsTask {
|
||||||
|
|
||||||
|
override fun execute(params: Unit): Try<Map<String, ThirdPartyProtocol>> {
|
||||||
|
return executeRequest {
|
||||||
|
apiCall = roomAPI.thirdPartyProtocols()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -156,7 +156,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
||||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||||
implementation 'com.airbnb.android:mvrx:0.7.0'
|
implementation 'com.airbnb.android:mvrx:1.0.1'
|
||||||
|
|
||||||
// Work
|
// Work
|
||||||
implementation "android.arch.work:work-runtime-ktx:1.0.0"
|
implementation "android.arch.work:work-runtime-ktx:1.0.0"
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
android:name="im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity"
|
android:name="im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity"
|
||||||
android:label="@string/title_activity_emoji_reaction_picker" />
|
android:label="@string/title_activity_emoji_reaction_picker" />
|
||||||
|
|
||||||
|
<activity android:name=".features.roomdirectory.RoomDirectoryActivity" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".core.services.CallService"
|
android:name=".core.services.CallService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
@ -30,6 +30,7 @@ import im.vector.riotredesign.core.di.AppModule
|
|||||||
import im.vector.riotredesign.features.home.HomeModule
|
import im.vector.riotredesign.features.home.HomeModule
|
||||||
import im.vector.riotredesign.features.rageshake.VectorFileLogger
|
import im.vector.riotredesign.features.rageshake.VectorFileLogger
|
||||||
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||||
import org.koin.log.EmptyLogger
|
import org.koin.log.EmptyLogger
|
||||||
import org.koin.standalone.StandAloneContext.startKoin
|
import org.koin.standalone.StandAloneContext.startKoin
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -56,7 +57,8 @@ class VectorApplication : Application() {
|
|||||||
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||||
val appModule = AppModule(applicationContext).definition
|
val appModule = AppModule(applicationContext).definition
|
||||||
val homeModule = HomeModule().definition
|
val homeModule = HomeModule().definition
|
||||||
startKoin(listOf(appModule, homeModule), logger = EmptyLogger())
|
val roomDirectoryModule = RoomDirectoryModule().definition
|
||||||
|
startKoin(listOf(appModule, homeModule, roomDirectoryModule), logger = EmptyLogger())
|
||||||
|
|
||||||
Matrix.getInstance().setApplicationFlavor(BuildConfig.FLAVOR_DESCRIPTION)
|
Matrix.getInstance().setApplicationFlavor(BuildConfig.FLAVOR_DESCRIPTION)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ package im.vector.riotredesign.core.di
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.MODE_PRIVATE
|
import android.content.Context.MODE_PRIVATE
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
|
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||||
import im.vector.riotredesign.core.resources.LocaleProvider
|
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.core.resources.StringProvider
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||||
@ -40,6 +42,10 @@ class AppModule(private val context: Context) {
|
|||||||
StringProvider(context.resources)
|
StringProvider(context.resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
StringArrayProvider(context.resources)
|
||||||
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
|
context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
|
||||||
}
|
}
|
||||||
@ -60,6 +66,10 @@ class AppModule(private val context: Context) {
|
|||||||
RoomSummaryComparator()
|
RoomSummaryComparator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
ErrorFormatter(get())
|
||||||
|
}
|
||||||
|
|
||||||
single {
|
single {
|
||||||
NotificationDrawerManager(context)
|
NotificationDrawerManager(context)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * 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.epoxy
|
||||||
|
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_error_retry)
|
||||||
|
abstract class ErrorWithRetryItem : VectorEpoxyModel<ErrorWithRetryItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var text: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var listener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
holder.textView.text = text
|
||||||
|
holder.buttonView.setOnClickListener { listener?.invoke() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val textView by bind<TextView>(R.id.itemErrorRetryText)
|
||||||
|
val buttonView by bind<Button>(R.id.itemErrorRetryButton)
|
||||||
|
}
|
||||||
|
}
|
@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package im.vector.riotredesign.core.epoxy
|
package im.vector.riotredesign.core.epoxy
|
||||||
|
|
||||||
import android.content.Context
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import android.widget.ProgressBar
|
import im.vector.riotredesign.R
|
||||||
import com.airbnb.epoxy.ModelView
|
|
||||||
|
|
||||||
@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
|
@EpoxyModelClass(layout = R.layout.item_loading)
|
||||||
class LoadingItem(context: Context) : ProgressBar(context)
|
abstract class LoadingItem : VectorEpoxyModel<LoadingItem.Holder>() {
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder()
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * 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.epoxy
|
||||||
|
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_no_result)
|
||||||
|
abstract class NoResultItem : VectorEpoxyModel<NoResultItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var text: String? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
holder.textView.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val textView by bind<TextView>(R.id.itemNoResultText)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.error
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
|
||||||
|
class ErrorFormatter(val stringProvider: StringProvider) {
|
||||||
|
|
||||||
|
|
||||||
|
fun toHumanReadable(failure: Failure): String {
|
||||||
|
// Default
|
||||||
|
return failure.localizedMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toHumanReadable(throwable: Throwable): String {
|
||||||
|
|
||||||
|
return when (throwable) {
|
||||||
|
is Failure.NetworkConnection -> stringProvider.getString(R.string.error_no_network)
|
||||||
|
else -> throwable.localizedMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -18,26 +18,26 @@ package im.vector.riotredesign.core.extensions
|
|||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
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) }
|
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) }
|
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) }
|
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) }
|
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) }
|
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) }
|
childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||||
}
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
85
vector/src/main/java/im/vector/riotredesign/core/platform/ButtonStateView.kt
Executable file
85
vector/src/main/java/im/vector/riotredesign/core/platform/ButtonStateView.kt
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.platform
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import kotlinx.android.synthetic.main.view_button_state.view.*
|
||||||
|
|
||||||
|
class ButtonStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||||
|
: FrameLayout(context, attrs, defStyle) {
|
||||||
|
|
||||||
|
sealed class State {
|
||||||
|
object Button : State()
|
||||||
|
object Loading : State()
|
||||||
|
object Loaded : State()
|
||||||
|
object Error : State()
|
||||||
|
}
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onButtonClicked()
|
||||||
|
fun onRetryClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
View.inflate(context, R.layout.view_button_state, this)
|
||||||
|
layoutParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
|
||||||
|
buttonStateButton.setOnClickListener {
|
||||||
|
callback?.onButtonClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonStateRetry.setOnClickListener {
|
||||||
|
callback?.onRetryClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read attributes
|
||||||
|
context.theme.obtainStyledAttributes(
|
||||||
|
attrs,
|
||||||
|
R.styleable.ButtonStateView,
|
||||||
|
0, 0)
|
||||||
|
.apply {
|
||||||
|
try {
|
||||||
|
buttonStateButton.text = getString(R.styleable.ButtonStateView_bsv_button_text)
|
||||||
|
buttonStateLoaded.setImageDrawable(getDrawable(R.styleable.ButtonStateView_bsv_loaded_image_src))
|
||||||
|
} finally {
|
||||||
|
recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun render(newState: State) {
|
||||||
|
if (newState == State.Button) {
|
||||||
|
buttonStateButton.isVisible = true
|
||||||
|
} else {
|
||||||
|
// We use isInvisible because we want to keep button space in the layout
|
||||||
|
buttonStateButton.isInvisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonStateLoading.isVisible = newState == State.Loading
|
||||||
|
buttonStateLoaded.isVisible = newState == State.Loaded
|
||||||
|
buttonStateRetry.isVisible = newState == State.Error
|
||||||
|
}
|
||||||
|
}
|
@ -93,6 +93,7 @@ abstract class VectorBaseActivity : BaseMvRxActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun Disposable.disposeOnDestroy(): Disposable {
|
protected fun Disposable.disposeOnDestroy(): Disposable {
|
||||||
|
// TODO Ganfra: never disposed...
|
||||||
uiDisposables.add(this)
|
uiDisposables.add(this)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,9 @@ import butterknife.Unbinder
|
|||||||
import com.airbnb.mvrx.BaseMvRxFragment
|
import com.airbnb.mvrx.BaseMvRxFragment
|
||||||
import com.airbnb.mvrx.MvRx
|
import com.airbnb.mvrx.MvRx
|
||||||
import com.bumptech.glide.util.Util.assertMainThread
|
import com.bumptech.glide.util.Util.assertMainThread
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed {
|
abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed {
|
||||||
@ -78,6 +81,12 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed {
|
|||||||
mUnBinder = null
|
mUnBinder = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
|
||||||
|
uiDisposables.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* Restorable
|
* Restorable
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
@ -100,6 +109,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed {
|
|||||||
|
|
||||||
override fun invalidate() {
|
override fun invalidate() {
|
||||||
//no-ops by default
|
//no-ops by default
|
||||||
|
Timber.w("invalidate() method has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun setArguments(args: Parcelable? = null) {
|
protected fun setArguments(args: Parcelable? = null) {
|
||||||
@ -113,6 +123,16 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================================
|
||||||
|
* Disposable
|
||||||
|
* ========================================================================================== */
|
||||||
|
|
||||||
|
private val uiDisposables = CompositeDisposable()
|
||||||
|
|
||||||
|
protected fun Disposable.disposeOnDestroy(): Disposable {
|
||||||
|
uiDisposables.add(this)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* MENU MANAGEMENT
|
* MENU MANAGEMENT
|
||||||
|
@ -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<String> {
|
||||||
|
return resources.getStringArray(resId)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -40,6 +40,7 @@ import im.vector.riotredesign.core.platform.VectorBaseActivity
|
|||||||
import im.vector.riotredesign.features.home.room.detail.LoadingRoomDetailFragment
|
import im.vector.riotredesign.features.home.room.detail.LoadingRoomDetailFragment
|
||||||
import im.vector.riotredesign.features.rageshake.BugReporter
|
import im.vector.riotredesign.features.rageshake.BugReporter
|
||||||
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity
|
||||||
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
||||||
import im.vector.riotredesign.features.workers.signout.SignOutUiWorker
|
import im.vector.riotredesign.features.workers.signout.SignOutUiWorker
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
import kotlinx.android.synthetic.main.activity_home.*
|
||||||
@ -138,7 +139,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
}
|
}
|
||||||
// TODO Temporary code here to create a room
|
// TODO Temporary code here to create a room
|
||||||
R.id.tmp_menu_create_room -> {
|
R.id.tmp_menu_create_room -> {
|
||||||
homeActivityViewModel.createRoom()
|
// Start Activity for now
|
||||||
|
startActivity(Intent(this, RoomDirectoryActivity::class.java))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ import im.vector.matrix.android.api.session.room.model.RoomMember
|
|||||||
import im.vector.matrix.android.api.session.room.model.message.*
|
import im.vector.matrix.android.api.session.room.model.message.*
|
||||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotredesign.core.epoxy.LoadingItemModel_
|
import im.vector.riotredesign.core.epoxy.LoadingItem_
|
||||||
import im.vector.riotredesign.core.extensions.localDateTime
|
import im.vector.riotredesign.core.extensions.localDateTime
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.*
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.*
|
||||||
@ -131,14 +131,14 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun buildModels() {
|
override fun buildModels() {
|
||||||
LoadingItemModel_()
|
LoadingItem_()
|
||||||
.id("forward_loading_item")
|
.id("forward_loading_item")
|
||||||
.addWhen(Timeline.Direction.FORWARDS)
|
.addWhen(Timeline.Direction.FORWARDS)
|
||||||
|
|
||||||
val timelineModels = getModels()
|
val timelineModels = getModels()
|
||||||
add(timelineModels)
|
add(timelineModels)
|
||||||
|
|
||||||
LoadingItemModel_()
|
LoadingItem_()
|
||||||
.id("backward_loading_item")
|
.id("backward_loading_item")
|
||||||
.addWhen(Timeline.Direction.BACKWARDS)
|
.addWhen(Timeline.Direction.BACKWARDS)
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun LoadingItemModel_.addWhen(direction: Timeline.Direction) {
|
private fun LoadingItem_.addWhen(direction: Timeline.Direction) {
|
||||||
val shouldAdd = timeline?.hasMoreToLoad(direction) ?: false
|
val shouldAdd = timeline?.hasMoreToLoad(direction) ?: false
|
||||||
addIf(shouldAdd, this@TimelineEventController)
|
addIf(shouldAdd, this@TimelineEventController)
|
||||||
}
|
}
|
||||||
|
@ -19,21 +19,30 @@ import android.os.Bundle
|
|||||||
import com.airbnb.mvrx.MvRxView
|
import com.airbnb.mvrx.MvRxView
|
||||||
import com.airbnb.mvrx.MvRxViewModelStore
|
import com.airbnb.mvrx.MvRxViewModelStore
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
||||||
*/
|
*/
|
||||||
abstract class BaseMvRxBottomSheetDialog() : BottomSheetDialogFragment(), MvRxView {
|
abstract class BaseMvRxBottomSheetDialog : BottomSheetDialogFragment(), MvRxView {
|
||||||
|
|
||||||
override val mvrxViewModelStore by lazy { MvRxViewModelStore(viewModelStore) }
|
override val mvrxViewModelStore by lazy { MvRxViewModelStore(viewModelStore) }
|
||||||
|
private lateinit var mvrxPersistedViewId: String
|
||||||
|
|
||||||
|
final override val mvrxViewId: String by lazy { mvrxPersistedViewId }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
mvrxViewModelStore.restoreViewModels(this, savedInstanceState)
|
mvrxViewModelStore.restoreViewModels(this, savedInstanceState)
|
||||||
|
mvrxPersistedViewId = savedInstanceState?.getString(PERSISTED_VIEW_ID_KEY)
|
||||||
|
?: this::class.java.simpleName + "_" + UUID.randomUUID().toString()
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
mvrxViewModelStore.saveViewModels(outState)
|
mvrxViewModelStore.saveViewModels(outState)
|
||||||
|
outState.putString(PERSISTED_VIEW_ID_KEY, mvrxViewId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
@ -43,3 +52,5 @@ abstract class BaseMvRxBottomSheetDialog() : BottomSheetDialogFragment(), MvRxVi
|
|||||||
postInvalidate()
|
postInvalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val PERSISTED_VIEW_ID_KEY = "mvrx:bottomsheet_persisted_view_id"
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
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.platform.ButtonStateView
|
||||||
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_public_room)
|
||||||
|
abstract class PublicRoomItem : VectorEpoxyModel<PublicRoomItem.Holder>() {
|
||||||
|
|
||||||
|
enum class JoinState {
|
||||||
|
NOT_JOINED,
|
||||||
|
JOINING,
|
||||||
|
JOINING_ERROR,
|
||||||
|
JOINED
|
||||||
|
}
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var avatarUrl: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var roomId: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var roomName: String? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var nbOfMembers: Int = 0
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var joinState: JoinState = JoinState.NOT_JOINED
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var globalListener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var joinListener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
holder.rootView.setOnClickListener { globalListener?.invoke() }
|
||||||
|
|
||||||
|
AvatarRenderer.render(avatarUrl, roomId!!, roomName, holder.avatarView)
|
||||||
|
holder.nameView.text = roomName
|
||||||
|
// TODO Use formatter for big numbers?
|
||||||
|
holder.counterView.text = nbOfMembers.toString()
|
||||||
|
|
||||||
|
holder.buttonState.render(
|
||||||
|
when (joinState) {
|
||||||
|
JoinState.NOT_JOINED -> ButtonStateView.State.Button
|
||||||
|
JoinState.JOINING -> ButtonStateView.State.Loading
|
||||||
|
JoinState.JOINED -> ButtonStateView.State.Loaded
|
||||||
|
JoinState.JOINING_ERROR -> ButtonStateView.State.Error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
holder.buttonState.callback = object : ButtonStateView.Callback {
|
||||||
|
override fun onButtonClicked() {
|
||||||
|
joinListener?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRetryClicked() {
|
||||||
|
// Same action
|
||||||
|
onButtonClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val rootView by bind<ViewGroup>(R.id.itemPublicRoomLayout)
|
||||||
|
|
||||||
|
val avatarView by bind<ImageView>(R.id.itemPublicRoomAvatar)
|
||||||
|
val nameView by bind<TextView>(R.id.itemPublicRoomName)
|
||||||
|
val counterView by bind<TextView>(R.id.itemPublicRoomMembersCount)
|
||||||
|
|
||||||
|
val buttonState by bind<ButtonStateView>(R.id.itemPublicRoomButtonState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import com.airbnb.epoxy.VisibilityState
|
||||||
|
import com.airbnb.mvrx.Fail
|
||||||
|
import com.airbnb.mvrx.Incomplete
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.epoxy.errorWithRetryItem
|
||||||
|
import im.vector.riotredesign.core.epoxy.loadingItem
|
||||||
|
import im.vector.riotredesign.core.epoxy.noResultItem
|
||||||
|
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||||
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
|
||||||
|
class PublicRoomsController(private val stringProvider: StringProvider,
|
||||||
|
private val errorFormatter: ErrorFormatter) : TypedEpoxyController<PublicRoomsViewState>() {
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
override fun buildModels(viewState: PublicRoomsViewState) {
|
||||||
|
val publicRooms = viewState.publicRooms
|
||||||
|
|
||||||
|
if (publicRooms.isEmpty()
|
||||||
|
&& viewState.asyncPublicRoomsRequest is Success) {
|
||||||
|
// No result
|
||||||
|
noResultItem {
|
||||||
|
id("noResult")
|
||||||
|
text(stringProvider.getString(R.string.no_result_placeholder))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
publicRooms.forEach {
|
||||||
|
buildPublicRoom(it, viewState)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((viewState.hasMore && viewState.asyncPublicRoomsRequest is Success)
|
||||||
|
|| viewState.asyncPublicRoomsRequest is Incomplete) {
|
||||||
|
loadingItem {
|
||||||
|
// Change id to avoid list to scroll automatically when first results are displayed
|
||||||
|
if (publicRooms.isEmpty()) {
|
||||||
|
id("loading")
|
||||||
|
} else {
|
||||||
|
id("loadMore")
|
||||||
|
}
|
||||||
|
onVisibilityStateChanged { _, _, visibilityState ->
|
||||||
|
if (visibilityState == VisibilityState.VISIBLE) {
|
||||||
|
callback?.loadMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewState.asyncPublicRoomsRequest is Fail) {
|
||||||
|
errorWithRetryItem {
|
||||||
|
id("error")
|
||||||
|
text(errorFormatter.toHumanReadable(viewState.asyncPublicRoomsRequest.error))
|
||||||
|
listener { callback?.loadMore() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(PublicRoomItem.JoinState.JOINED)
|
||||||
|
viewState.joiningRoomsIds.contains(publicRoom.roomId) -> joinState(PublicRoomItem.JoinState.JOINING)
|
||||||
|
viewState.joiningErrorRoomsIds.contains(publicRoom.roomId) -> joinState(PublicRoomItem.JoinState.JOINING_ERROR)
|
||||||
|
else -> joinState(PublicRoomItem.JoinState.NOT_JOINED)
|
||||||
|
}
|
||||||
|
joinListener {
|
||||||
|
callback?.onPublicRoomJoin(publicRoom)
|
||||||
|
}
|
||||||
|
globalListener {
|
||||||
|
callback?.onPublicRoomClicked(publicRoom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onPublicRoomClicked(publicRoom: PublicRoom)
|
||||||
|
fun onPublicRoomJoin(publicRoom: PublicRoom)
|
||||||
|
fun loadMore()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||||
|
import com.airbnb.mvrx.activityViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.jakewharton.rxbinding2.widget.RxTextView
|
||||||
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||||
|
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||||
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment
|
||||||
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
|
import kotlinx.android.synthetic.main.fragment_public_rooms.*
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
import org.koin.android.scope.ext.android.bindScope
|
||||||
|
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What can be improved:
|
||||||
|
* - When filtering more (when entering new chars), we could filter on result we already have, during the new server request, to avoid empty screen effect
|
||||||
|
*
|
||||||
|
* 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 PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback {
|
||||||
|
|
||||||
|
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||||
|
private val publicRoomsController: PublicRoomsController by inject()
|
||||||
|
private val errorFormatter: ErrorFormatter by inject()
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.fragment_public_rooms
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
vectorBaseActivity.setSupportActionBar(toolbar)
|
||||||
|
|
||||||
|
vectorBaseActivity.supportActionBar?.let {
|
||||||
|
it.setDisplayShowHomeEnabled(true)
|
||||||
|
it.setDisplayHomeAsUpEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
RxTextView.textChanges(publicRoomsFilter)
|
||||||
|
.debounce(500, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribeBy {
|
||||||
|
viewModel.filterWith(it.toString())
|
||||||
|
}
|
||||||
|
.disposeOnDestroy()
|
||||||
|
|
||||||
|
publicRoomsCreateNewRoom.setOnClickListener {
|
||||||
|
// TODO homeActivityViewModel.createRoom()
|
||||||
|
|
||||||
|
vectorBaseActivity.notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
publicRoomsChangeDirectory.setOnClickListener {
|
||||||
|
vectorBaseActivity.addFragmentToBackstack(RoomDirectoryPickerFragment(), R.id.simpleFragmentContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.joinRoomErrorLiveData.observe(this, Observer {
|
||||||
|
it.getContentIfNotHandled()?.let { throwable ->
|
||||||
|
Snackbar.make(publicRoomsCoordinator, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||||
|
|
||||||
|
setupRecyclerView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRecyclerView() {
|
||||||
|
val epoxyVisibilityTracker = EpoxyVisibilityTracker()
|
||||||
|
epoxyVisibilityTracker.attach(publicRoomsList)
|
||||||
|
|
||||||
|
val layoutManager = LinearLayoutManager(context)
|
||||||
|
|
||||||
|
publicRoomsList.layoutManager = layoutManager
|
||||||
|
publicRoomsController.callback = this
|
||||||
|
|
||||||
|
publicRoomsList.setController(publicRoomsController)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPublicRoomClicked(publicRoom: PublicRoom) {
|
||||||
|
Timber.v("PublicRoomClicked: $publicRoom")
|
||||||
|
vectorBaseActivity.notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPublicRoomJoin(publicRoom: PublicRoom) {
|
||||||
|
Timber.v("PublicRoomJoinClicked: $publicRoom")
|
||||||
|
viewModel.joinRoom(publicRoom)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadMore() {
|
||||||
|
viewModel.loadMore()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
// Populate list with Epoxy
|
||||||
|
publicRoomsController.setData(state)
|
||||||
|
|
||||||
|
// Directory name
|
||||||
|
publicRoomsDirectoryName.text = state.roomDirectoryDisplayName
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.airbnb.mvrx.*
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
|
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
|
||||||
|
import im.vector.riotredesign.core.utils.LiveEvent
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
private const val PUBLIC_ROOMS_LIMIT = 20
|
||||||
|
|
||||||
|
class RoomDirectoryViewModel(initialState: PublicRoomsViewState,
|
||||||
|
private val session: Session) : VectorViewModel<PublicRoomsViewState>(initialState) {
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<RoomDirectoryViewModel, PublicRoomsViewState> {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: PublicRoomsViewState): RoomDirectoryViewModel? {
|
||||||
|
val currentSession = viewModelContext.activity.get<Session>()
|
||||||
|
|
||||||
|
return RoomDirectoryViewModel(state, currentSession)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _joinRoomErrorLiveData = MutableLiveData<LiveEvent<Throwable>>()
|
||||||
|
val joinRoomErrorLiveData: LiveData<LiveEvent<Throwable>>
|
||||||
|
get() = _joinRoomErrorLiveData
|
||||||
|
|
||||||
|
|
||||||
|
// TODO Store in ViewState?
|
||||||
|
private var currentFilter: String = ""
|
||||||
|
|
||||||
|
private var since: String? = null
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeJoinedRooms() {
|
||||||
|
session
|
||||||
|
.rx()
|
||||||
|
.liveRoomSummaries()
|
||||||
|
.execute { async ->
|
||||||
|
val joinedRoomIds = async.invoke()
|
||||||
|
// Keep only joined room
|
||||||
|
?.filter { it.membership == Membership.JOIN }
|
||||||
|
?.map { it.roomId }
|
||||||
|
?.toList()
|
||||||
|
?: emptyList()
|
||||||
|
|
||||||
|
copy(
|
||||||
|
joinedRoomsIds = joinedRoomIds,
|
||||||
|
// Remove (newly) joined room id from the joining room list
|
||||||
|
joiningRoomsIds = joiningRoomsIds.toMutableList().apply { removeAll(joinedRoomIds) },
|
||||||
|
// Remove (newly) joined room id from the joining room list in error
|
||||||
|
joiningErrorRoomsIds = joiningErrorRoomsIds.toMutableList().apply { removeAll(joinedRoomIds) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
publicRooms = emptyList(),
|
||||||
|
asyncPublicRoomsRequest = Loading(),
|
||||||
|
hasMore = false,
|
||||||
|
roomDirectoryDisplayName = roomDirectoryData.displayName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadMore() {
|
||||||
|
if (currentTask == null) {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncPublicRoomsRequest = Loading()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun load() {
|
||||||
|
currentTask = session.getPublicRooms(roomDirectoryData.homeServer,
|
||||||
|
PublicRoomsParams(
|
||||||
|
limit = PUBLIC_ROOMS_LIMIT,
|
||||||
|
filter = PublicRoomsFilter(searchTerm = currentFilter),
|
||||||
|
includeAllNetworks = roomDirectoryData.includeAllNetworks,
|
||||||
|
since = since,
|
||||||
|
thirdPartyInstanceId = roomDirectoryData.thirdPartyInstanceId
|
||||||
|
),
|
||||||
|
object : MatrixCallback<PublicRoomsResponse> {
|
||||||
|
override fun onSuccess(data: PublicRoomsResponse) {
|
||||||
|
currentTask = null
|
||||||
|
|
||||||
|
since = data.nextBatch
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncPublicRoomsRequest = Success(data.chunk!!),
|
||||||
|
// It's ok to append at the end of the list, so I use publicRooms.size()
|
||||||
|
publicRooms = publicRooms.appendAt(data.chunk!!, publicRooms.size),
|
||||||
|
hasMore = since != null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
currentTask = null
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
asyncPublicRoomsRequest = Fail(failure)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun joinRoom(publicRoom: PublicRoom) = withState { state ->
|
||||||
|
if (state.joiningRoomsIds.contains(publicRoom.roomId)) {
|
||||||
|
// Request already sent, should not happen
|
||||||
|
Timber.w("Try to join an already joining room. Should not happen")
|
||||||
|
return@withState
|
||||||
|
}
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
joiningRoomsIds = joiningRoomsIds.toMutableList().apply { add(publicRoom.roomId) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
session.joinRoom(publicRoom.roomId, object : MatrixCallback<Unit> {
|
||||||
|
override fun onSuccess(data: Unit) {
|
||||||
|
// We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
|
||||||
|
// Instead, we wait for the room to be joined
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
// Notify the user
|
||||||
|
_joinRoomErrorLiveData.postValue(LiveEvent(failure))
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
joiningRoomsIds = joiningRoomsIds.toMutableList().apply { remove(publicRoom.roomId) },
|
||||||
|
joiningErrorRoomsIds = joiningErrorRoomsIds.toMutableList().apply { add(publicRoom.roomId) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.features.roomdirectory
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||||
|
|
||||||
|
data class PublicRoomsViewState(
|
||||||
|
// Store cumul of pagination result
|
||||||
|
val publicRooms: List<PublicRoom> = emptyList(),
|
||||||
|
// Current pagination request
|
||||||
|
val asyncPublicRoomsRequest: Async<List<PublicRoom>> = Uninitialized,
|
||||||
|
// True if more result are available server side
|
||||||
|
val hasMore: Boolean = false,
|
||||||
|
// List of roomIds that the user wants to join
|
||||||
|
val joiningRoomsIds: List<String> = emptyList(),
|
||||||
|
// List of roomIds that the user wants to join, but an error occurred
|
||||||
|
val joiningErrorRoomsIds: List<String> = emptyList(),
|
||||||
|
// List of joined roomId,
|
||||||
|
val joinedRoomsIds: List<String> = emptyList(),
|
||||||
|
val roomDirectoryDisplayName: String? = null
|
||||||
|
) : MvRxState
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.extensions.addFragment
|
||||||
|
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||||
|
import org.koin.android.scope.ext.android.bindScope
|
||||||
|
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||||
|
|
||||||
|
class RoomDirectoryActivity : VectorBaseActivity() {
|
||||||
|
|
||||||
|
|
||||||
|
override fun getLayoutRes() = R.layout.activity_simple
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initUiAndData() {
|
||||||
|
if (isFirstCreation()) {
|
||||||
|
addFragment(PublicRoomsFragment(), R.id.simpleFragmentContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryListCreator
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerController
|
||||||
|
import org.koin.dsl.module.module
|
||||||
|
|
||||||
|
// TODO Ganfra: When do we create a new module?
|
||||||
|
class RoomDirectoryModule {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ROOM_DIRECTORY_SCOPE = "ROOM_DIRECTORY_SCOPE"
|
||||||
|
}
|
||||||
|
|
||||||
|
val definition = module(override = true) {
|
||||||
|
|
||||||
|
scope(ROOM_DIRECTORY_SCOPE) {
|
||||||
|
RoomDirectoryPickerController(get(), get(), get())
|
||||||
|
}
|
||||||
|
|
||||||
|
scope(ROOM_DIRECTORY_SCOPE) {
|
||||||
|
RoomDirectoryListCreator(get(), get<Session>().sessionParams.credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
scope(ROOM_DIRECTORY_SCOPE) {
|
||||||
|
PublicRoomsController(get(), get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<RoomDirectoryItem.Holder>() {
|
||||||
|
|
||||||
|
@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<ViewGroup>(R.id.itemRoomDirectoryLayout)
|
||||||
|
|
||||||
|
val avatarView by bind<ImageView>(R.id.itemRoomDirectoryAvatar)
|
||||||
|
val nameView by bind<TextView>(R.id.itemRoomDirectoryName)
|
||||||
|
val descritionView by bind<TextView>(R.id.itemRoomDirectoryDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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 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.resources.StringArrayProvider
|
||||||
|
|
||||||
|
class RoomDirectoryListCreator(private val stringArrayProvider: StringArrayProvider,
|
||||||
|
private val credentials: Credentials) {
|
||||||
|
|
||||||
|
fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>): List<RoomDirectoryData> {
|
||||||
|
val result = ArrayList<RoomDirectoryData>()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.session.room.model.thirdparty.RoomDirectoryData
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.epoxy.errorWithRetryItem
|
||||||
|
import im.vector.riotredesign.core.epoxy.loadingItem
|
||||||
|
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||||
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
|
||||||
|
class RoomDirectoryPickerController(private val stringProvider: StringProvider,
|
||||||
|
private val errorFormatter: ErrorFormatter,
|
||||||
|
private val roomDirectoryListCreator: RoomDirectoryListCreator
|
||||||
|
) : TypedEpoxyController<RoomDirectoryPickerViewState>() {
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
|
||||||
|
override fun buildModels(viewState: RoomDirectoryPickerViewState) {
|
||||||
|
val asyncThirdPartyProtocol = viewState.asyncThirdPartyRequest
|
||||||
|
|
||||||
|
when (asyncThirdPartyProtocol) {
|
||||||
|
is Success -> {
|
||||||
|
val directories = roomDirectoryListCreator.computeDirectories(asyncThirdPartyProtocol.invoke())
|
||||||
|
|
||||||
|
directories.forEach {
|
||||||
|
buildDirectory(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Incomplete -> {
|
||||||
|
loadingItem {
|
||||||
|
id("loading")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Fail -> {
|
||||||
|
errorWithRetryItem {
|
||||||
|
id("error")
|
||||||
|
text(errorFormatter.toHumanReadable(asyncThirdPartyProtocol.error))
|
||||||
|
listener { callback?.retry() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDirectory(roomDirectoryData: RoomDirectoryData) {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.model.thirdparty.RoomDirectoryData
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||||
|
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.inject
|
||||||
|
import org.koin.android.scope.ext.android.bindScope
|
||||||
|
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||||
|
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 by inject()
|
||||||
|
|
||||||
|
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)
|
||||||
|
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||||
|
|
||||||
|
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 best 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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<RoomDirectoryPickerViewState>(initialState) {
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<RoomDirectoryPickerViewModel, RoomDirectoryPickerViewState> {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel? {
|
||||||
|
val currentSession = viewModelContext.activity.get<Session>()
|
||||||
|
|
||||||
|
return RoomDirectoryPickerViewModel(state, currentSession)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load() {
|
||||||
|
session.getThirdPartyProtocol(object : MatrixCallback<Map<String, ThirdPartyProtocol>> {
|
||||||
|
override fun onSuccess(data: Map<String, ThirdPartyProtocol>) {
|
||||||
|
setState {
|
||||||
|
copy(asyncThirdPartyRequest = Success(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
setState {
|
||||||
|
copy(asyncThirdPartyRequest = Fail(failure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<Map<String, ThirdPartyProtocol>> = Uninitialized
|
||||||
|
) : MvRxState
|
13
vector/src/main/res/drawable/ic_plus_circle.xml
Normal file
13
vector/src/main/res/drawable/ic_plus_circle.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<vector android:height="24dp" android:viewportHeight="22"
|
||||||
|
android:viewportWidth="22" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M11,11m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeColor="#03B381" android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="round" android:strokeWidth="1.4"/>
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M11,7L11,15" android:strokeColor="#03B381"
|
||||||
|
android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="1.4"/>
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M7,11L15,11" android:strokeColor="#03B381"
|
||||||
|
android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="1.4"/>
|
||||||
|
</vector>
|
9
vector/src/main/res/drawable/ic_tick.xml
Normal file
9
vector/src/main/res/drawable/ic_tick.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector android:height="24dp" android:viewportHeight="11"
|
||||||
|
android:viewportWidth="15" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M5.3033,10.0815L13.7886,1.5962"
|
||||||
|
android:strokeColor="#7E899C" android:strokeLineCap="round" android:strokeWidth="1.3"/>
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M5.3033,10.0815L1.0607,5.8388"
|
||||||
|
android:strokeColor="#7E899C" android:strokeLineCap="round" android:strokeWidth="1.3"/>
|
||||||
|
</vector>
|
11
vector/src/main/res/drawable/ic_user.xml
Normal file
11
vector/src/main/res/drawable/ic_user.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<vector android:height="24dp" android:viewportHeight="16"
|
||||||
|
android:viewportWidth="15" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M14,15L14,13.4444C14,11.7262 12.5449,10.3333 10.75,10.3333L4.25,10.3333C2.4551,10.3333 1,11.7262 1,13.4444L1,15"
|
||||||
|
android:strokeColor="#7E899C" android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="round" android:strokeWidth="1.16666667"/>
|
||||||
|
<path android:fillColor="#00000000" android:fillType="evenOdd"
|
||||||
|
android:pathData="M4.25,4.1111a3.25,3.1111 0,1 0,6.5 0a3.25,3.1111 0,1 0,-6.5 0z"
|
||||||
|
android:strokeColor="#7E899C" android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="round" android:strokeWidth="1.16666667"/>
|
||||||
|
</vector>
|
5
vector/src/main/res/layout/activity_simple.xml
Normal file
5
vector/src/main/res/layout/activity_simple.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/simpleFragmentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
107
vector/src/main/res/layout/fragment_public_rooms.xml
Normal file
107
vector/src/main/res/layout/fragment_public_rooms.xml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/publicRoomsCoordinator"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/pale_grey">
|
||||||
|
|
||||||
|
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||||
|
android:id="@+id/publicRoomsList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:listitem="@layout/item_public_room" />
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:expandedTitleGravity="top"
|
||||||
|
app:layout_scrollFlags="scroll|enterAlways|exitUntilCollapsed|snap">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/publicRoomsFilter"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="@drawable/bg_search_edit_text"
|
||||||
|
android:drawableStart="@drawable/ic_search_white"
|
||||||
|
android:drawableLeft="@drawable/ic_search_white"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:drawableTint="#9fa9ba"
|
||||||
|
android:hint="@string/home_filter_placeholder_rooms"
|
||||||
|
android:lines="1"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/publicRoomsCreateNewRoom"
|
||||||
|
style="@style/VectorButtonStyleFlat"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:drawableStart="@drawable/ic_plus_circle"
|
||||||
|
android:drawableLeft="@drawable/ic_plus_circle"
|
||||||
|
android:drawablePadding="13dp"
|
||||||
|
android:text="@string/create_new_room" />
|
||||||
|
|
||||||
|
<!-- TODO Layout with Nad -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/publicRoomsDirectoryName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
tools:text="RoomDirectoryName" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/publicRoomsChangeDirectory"
|
||||||
|
style="@style/VectorButtonStyleFlat"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:text="@string/action_change" />
|
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/pale_grey">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||||
|
android:id="@+id/roomDirectoryPickerList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
||||||
|
tools:listitem="@layout/item_room_directory" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
30
vector/src/main/res/layout/item_error_retry.xml
Normal file
30
vector/src/main/res/layout/item_error_retry.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemErrorRetryText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Error" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/itemErrorRetryButton"
|
||||||
|
style="@style/VectorButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="@string/global_retry"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/itemErrorRetryText" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
8
vector/src/main/res/layout/item_no_result.xml
Normal file
8
vector/src/main/res/layout/item_no_result.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/itemNoResultText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:text="@string/no_result_placeholder" />
|
84
vector/src/main/res/layout/item_public_room.xml
Normal file
84
vector/src/main/res/layout/item_public_room.xml
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/itemPublicRoomLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_room_item"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemPublicRoomAvatar"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemPublicRoomName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="#2E2F3E"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/itemPublicRoomMembersCount"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemPublicRoomAvatar"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemPublicRoomMembersCount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:drawableStart="@drawable/ic_user"
|
||||||
|
android:drawableLeft="@drawable/ic_user"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:textColor="#7E899C"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/itemPublicRoomButtonState"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemPublicRoomName"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="148" />
|
||||||
|
|
||||||
|
<im.vector.riotredesign.core.platform.ButtonStateView
|
||||||
|
android:id="@+id/itemPublicRoomButtonState"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
app:bsv_button_text="@string/join"
|
||||||
|
app:bsv_loaded_image_src="@drawable/ic_tick"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/itemPublicRoomBottomSeparator"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="#E9EDF1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
72
vector/src/main/res/layout/item_room_directory.xml
Normal file
72
vector/src/main/res/layout/item_room_directory.xml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/itemRoomDirectoryLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_room_item"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemRoomDirectoryAvatar"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryBottomSeparator"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemRoomDirectoryName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="#2E2F3E"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryDescription"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/itemRoomDirectoryDescription"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textColor="#2E2F3E"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemRoomDirectoryBottomSeparator"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/itemRoomDirectoryAvatar"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/itemRoomDirectoryName"
|
||||||
|
tools:text="@string/directory_server_all_rooms_on_server" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/itemRoomDirectoryBottomSeparator"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="#E9EDF1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
43
vector/src/main/res/layout/view_button_state.xml
Normal file
43
vector/src/main/res/layout/view_button_state.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:parentTag="android.widget.FrameLayout">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonStateButton"
|
||||||
|
style="@style/VectorButtonStyleFlat"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@string/join" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/buttonStateLoading"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:scaleType="center" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/buttonStateLoaded"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
tools:src="@drawable/ic_tick" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonStateRetry"
|
||||||
|
style="@style/VectorButtonStyleFlat"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/global_retry"
|
||||||
|
android:textColor="@color/vector_warning_color" />
|
||||||
|
|
||||||
|
</merge>
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_add_custom_hs"
|
android:id="@+id/action_add_custom_hs"
|
||||||
android:icon="@drawable/ic_add_white"
|
android:icon="@drawable/ic_add_black"
|
||||||
android:title="@string/action_open"
|
android:title="@string/action_open"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
12
vector/src/main/res/values/attrs_state_button.xml
Normal file
12
vector/src/main/res/values/attrs_state_button.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<declare-styleable name="ButtonStateView">
|
||||||
|
|
||||||
|
<attr name="bsv_loaded_image_src" format="reference" />
|
||||||
|
<attr name="bsv_button_text" format="reference|string" />
|
||||||
|
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
|
||||||
|
</resources>
|
@ -17,4 +17,11 @@
|
|||||||
<string name="event_redacted_by_admin_reason">Event moderated by room admin</string>
|
<string name="event_redacted_by_admin_reason">Event moderated by room admin</string>
|
||||||
<string name="last_edited_info_message">Last edited by %s on %s</string>
|
<string name="last_edited_info_message">Last edited by %s on %s</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="create_new_room">Create New Room</string>
|
||||||
|
|
||||||
|
<string name="error_no_network">No network. Please check your Internet connection.</string>
|
||||||
|
|
||||||
|
<string name="action_change">"Change"</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user