mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-17 20:40:07 +03:00
Room list : handle direct rooms
This commit is contained in:
parent
ec27951850
commit
bc8055c3cd
20 changed files with 351 additions and 43 deletions
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
|
@ -1,16 +1,30 @@
|
||||||
package im.vector.riotredesign.features.home.room.list
|
package im.vector.riotredesign.features.home.room.list
|
||||||
|
|
||||||
import android.support.annotation.DrawableRes
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
import im.vector.riotredesign.core.epoxy.KotlinModel
|
||||||
|
|
||||||
data class RoomCategoryItem(
|
data class RoomCategoryItem(
|
||||||
val title: CharSequence,
|
val title: CharSequence,
|
||||||
@DrawableRes val expandDrawable: Int,
|
val isExpanded: Boolean,
|
||||||
val listener: (() -> Unit)? = null
|
val listener: (() -> Unit)? = null
|
||||||
) : KotlinModel(R.layout.item_room_category) {
|
) : KotlinModel(R.layout.item_room_category) {
|
||||||
|
|
||||||
override fun bind() {
|
private val titleView by bind<TextView>(R.id.roomCategoryTitleView)
|
||||||
|
private val rootView by bind<ViewGroup>(R.id.roomCategoryRootView)
|
||||||
|
|
||||||
|
private val tintColor by lazy {
|
||||||
|
ContextCompat.getColor(rootView.context, R.color.bluey_grey_two)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind() {
|
||||||
|
val expandedArrowDrawableRes = if (isExpanded) R.drawable.ic_expand_more_white else R.drawable.ic_expand_less_white
|
||||||
|
val expandedArrowDrawable = ContextCompat.getDrawable(rootView.context, expandedArrowDrawableRes)
|
||||||
|
expandedArrowDrawable?.setTint(tintColor)
|
||||||
|
titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null)
|
||||||
|
titleView.text = title
|
||||||
|
rootView.setOnClickListener { listener?.invoke() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,49 @@ class RoomSummaryController(private val context: Context,
|
||||||
private val callback: Callback? = null
|
private val callback: Callback? = null
|
||||||
) : Typed2EpoxyController<List<RoomSummary>, RoomSummary>() {
|
) : Typed2EpoxyController<List<RoomSummary>, RoomSummary>() {
|
||||||
|
|
||||||
|
|
||||||
|
private var directRoomsExpanded = true
|
||||||
|
private var groupRoomsExpanded = true
|
||||||
|
|
||||||
override fun buildModels(summaries: List<RoomSummary>?, selected: RoomSummary?) {
|
override fun buildModels(summaries: List<RoomSummary>?, selected: RoomSummary?) {
|
||||||
|
|
||||||
|
val directRooms = summaries?.filter { it.isDirect } ?: emptyList()
|
||||||
|
val groupRooms = summaries?.filter { !it.isDirect } ?: emptyList()
|
||||||
|
|
||||||
RoomCategoryItem(
|
RoomCategoryItem(
|
||||||
title = "DIRECT MESSAGES",
|
title = "DIRECT MESSAGES",
|
||||||
expandDrawable = R.drawable.ic_expand_more_white
|
isExpanded = directRoomsExpanded,
|
||||||
|
listener = {
|
||||||
|
directRoomsExpanded = !directRoomsExpanded
|
||||||
|
setData(summaries, selected)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.id("direct_messages")
|
.id("direct_messages")
|
||||||
.addTo(this)
|
.addTo(this)
|
||||||
|
|
||||||
summaries?.forEach {
|
if (directRoomsExpanded) {
|
||||||
|
buildRoomModels(directRooms, selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomCategoryItem(
|
||||||
|
title = "GROUPS",
|
||||||
|
isExpanded = groupRoomsExpanded,
|
||||||
|
listener = {
|
||||||
|
groupRoomsExpanded = !groupRoomsExpanded
|
||||||
|
setData(summaries, selected)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.id("group_messages")
|
||||||
|
.addTo(this)
|
||||||
|
|
||||||
|
if (groupRoomsExpanded) {
|
||||||
|
buildRoomModels(groupRooms, selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildRoomModels(summaries: List<RoomSummary>, selected: RoomSummary?) {
|
||||||
|
summaries.forEach {
|
||||||
val roomSummaryViewHelper = RoomSummaryViewHelper(it)
|
val roomSummaryViewHelper = RoomSummaryViewHelper(it)
|
||||||
RoomSummaryItem(
|
RoomSummaryItem(
|
||||||
title = it.displayName,
|
title = it.displayName,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
|
android:id="@+id/roomCategoryRootView"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:minHeight="24dp"
|
android:minHeight="24dp"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
|
|
|
@ -4,5 +4,6 @@ data class RoomSummary(
|
||||||
val roomId: String,
|
val roomId: String,
|
||||||
val displayName: String = "",
|
val displayName: String = "",
|
||||||
val topic: String = "",
|
val topic: String = "",
|
||||||
val avatarUrl: String = ""
|
val avatarUrl: String = "",
|
||||||
|
val isDirect: Boolean
|
||||||
)
|
)
|
|
@ -11,16 +11,8 @@ object RoomSummaryMapper {
|
||||||
roomSummaryEntity.roomId,
|
roomSummaryEntity.roomId,
|
||||||
roomSummaryEntity.displayName ?: "",
|
roomSummaryEntity.displayName ?: "",
|
||||||
roomSummaryEntity.topic ?: "",
|
roomSummaryEntity.topic ?: "",
|
||||||
roomSummaryEntity.avatarUrl ?: ""
|
roomSummaryEntity.avatarUrl ?: "",
|
||||||
)
|
roomSummaryEntity.isDirect
|
||||||
}
|
|
||||||
|
|
||||||
internal fun map(roomSummary: RoomSummary): RoomSummaryEntity {
|
|
||||||
return RoomSummaryEntity(
|
|
||||||
roomSummary.roomId,
|
|
||||||
roomSummary.displayName,
|
|
||||||
roomSummary.topic,
|
|
||||||
roomSummary.avatarUrl
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +20,3 @@ object RoomSummaryMapper {
|
||||||
fun RoomSummaryEntity.asDomain(): RoomSummary {
|
fun RoomSummaryEntity.asDomain(): RoomSummary {
|
||||||
return RoomSummaryMapper.map(this)
|
return RoomSummaryMapper.map(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RoomSummaryEntity.asEntity(): RoomSummary {
|
|
||||||
return RoomSummaryMapper.map(this)
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ import io.realm.RealmList
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
|
|
||||||
// TODO to be completed
|
|
||||||
open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||||
var displayName: String? = "",
|
var displayName: String? = "",
|
||||||
var avatarUrl: String? = "",
|
var avatarUrl: String? = "",
|
||||||
|
@ -13,6 +12,7 @@ open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||||
var heroes: RealmList<String> = RealmList(),
|
var heroes: RealmList<String> = RealmList(),
|
||||||
var joinedMembersCount: Int? = 0,
|
var joinedMembersCount: Int? = 0,
|
||||||
var invitedMembersCount: Int? = 0,
|
var invitedMembersCount: Int? = 0,
|
||||||
|
var isDirect: Boolean = false,
|
||||||
var isLatestSelected: Boolean = false
|
var isLatestSelected: Boolean = false
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
package im.vector.matrix.android.internal.di
|
package im.vector.matrix.android.internal.di
|
||||||
|
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
|
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
|
||||||
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.UserAccountData
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback
|
||||||
|
|
||||||
object MoshiProvider {
|
object MoshiProvider {
|
||||||
|
|
||||||
private val moshi: Moshi = Moshi.Builder()
|
private val moshi: Moshi = Moshi.Builder()
|
||||||
.add(UriMoshiAdapter())
|
.add(UriMoshiAdapter())
|
||||||
|
.add(RuntimeJsonAdapterFactory.of(UserAccountData::class.java, "type", UserAccountDataFallback::class.java)
|
||||||
|
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun providesMoshi(): Moshi {
|
fun providesMoshi(): Moshi {
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Google Inc.
|
||||||
|
*
|
||||||
|
* 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.network.parsing;
|
||||||
|
|
||||||
|
import com.squareup.moshi.JsonAdapter;
|
||||||
|
import com.squareup.moshi.JsonDataException;
|
||||||
|
import com.squareup.moshi.JsonReader;
|
||||||
|
import com.squareup.moshi.JsonWriter;
|
||||||
|
import com.squareup.moshi.Moshi;
|
||||||
|
import com.squareup.moshi.Types;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.CheckReturnValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JsonAdapter factory for polymorphic types. This is useful when the type is not known before
|
||||||
|
* decoding the JSON. This factory's adapters expect JSON in the format of a JSON object with a
|
||||||
|
* key whose value is a label that determines the type to which to map the JSON object.
|
||||||
|
*/
|
||||||
|
public final class RuntimeJsonAdapterFactory<T> implements JsonAdapter.Factory {
|
||||||
|
final Class<T> baseType;
|
||||||
|
final String labelKey;
|
||||||
|
final Class fallbackType;
|
||||||
|
final Map<String, Type> labelToType = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param baseType The base type for which this factory will create adapters. Cannot be Object.
|
||||||
|
* @param labelKey The key in the JSON object whose value determines the type to which to map the
|
||||||
|
* JSON object.
|
||||||
|
*/
|
||||||
|
@CheckReturnValue
|
||||||
|
public static <T> RuntimeJsonAdapterFactory<T> of(Class<T> baseType, String labelKey, Class<? extends T> fallbackType) {
|
||||||
|
if (baseType == null) throw new NullPointerException("baseType == null");
|
||||||
|
if (labelKey == null) throw new NullPointerException("labelKey == null");
|
||||||
|
if (baseType == Object.class) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The base type must not be Object. Consider using a marker interface.");
|
||||||
|
}
|
||||||
|
return new RuntimeJsonAdapterFactory<>(baseType, labelKey, fallbackType);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeJsonAdapterFactory(Class<T> baseType, String labelKey, Class fallbackType) {
|
||||||
|
this.baseType = baseType;
|
||||||
|
this.labelKey = labelKey;
|
||||||
|
this.fallbackType = fallbackType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the subtype that can be created based on the label. When an unknown type is found
|
||||||
|
* during encoding an {@linkplain IllegalArgumentException} will be thrown. When an unknown label
|
||||||
|
* is found during decoding a {@linkplain JsonDataException} will be thrown.
|
||||||
|
*/
|
||||||
|
public RuntimeJsonAdapterFactory<T> registerSubtype(Class<? extends T> subtype, String label) {
|
||||||
|
if (subtype == null) throw new NullPointerException("subtype == null");
|
||||||
|
if (label == null) throw new NullPointerException("label == null");
|
||||||
|
if (labelToType.containsKey(label) || labelToType.containsValue(subtype)) {
|
||||||
|
throw new IllegalArgumentException("Subtypes and labels must be unique.");
|
||||||
|
}
|
||||||
|
labelToType.put(label, subtype);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
|
if (Types.getRawType(type) != baseType || !annotations.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int size = labelToType.size();
|
||||||
|
Map<String, JsonAdapter<Object>> labelToAdapter = new LinkedHashMap<>(size);
|
||||||
|
Map<Type, String> typeToLabel = new LinkedHashMap<>(size);
|
||||||
|
for (Map.Entry<String, Type> entry : labelToType.entrySet()) {
|
||||||
|
String label = entry.getKey();
|
||||||
|
Type typeValue = entry.getValue();
|
||||||
|
typeToLabel.put(typeValue, label);
|
||||||
|
labelToAdapter.put(label, moshi.adapter(typeValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
final JsonAdapter<Object> fallbackAdapter = moshi.adapter(fallbackType);
|
||||||
|
JsonAdapter<Object> objectJsonAdapter = moshi.adapter(Object.class);
|
||||||
|
|
||||||
|
return new RuntimeJsonAdapter(labelKey, labelToAdapter, typeToLabel,
|
||||||
|
objectJsonAdapter, fallbackAdapter).nullSafe();
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class RuntimeJsonAdapter extends JsonAdapter<Object> {
|
||||||
|
final String labelKey;
|
||||||
|
final Map<String, JsonAdapter<Object>> labelToAdapter;
|
||||||
|
final Map<Type, String> typeToLabel;
|
||||||
|
final JsonAdapter<Object> objectJsonAdapter;
|
||||||
|
final JsonAdapter<Object> fallbackAdapter;
|
||||||
|
|
||||||
|
RuntimeJsonAdapter(String labelKey, Map<String, JsonAdapter<Object>> labelToAdapter,
|
||||||
|
Map<Type, String> typeToLabel, JsonAdapter<Object> objectJsonAdapter,
|
||||||
|
JsonAdapter<Object> fallbackAdapter) {
|
||||||
|
this.labelKey = labelKey;
|
||||||
|
this.labelToAdapter = labelToAdapter;
|
||||||
|
this.typeToLabel = typeToLabel;
|
||||||
|
this.objectJsonAdapter = objectJsonAdapter;
|
||||||
|
this.fallbackAdapter = fallbackAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fromJson(JsonReader reader) throws IOException {
|
||||||
|
JsonReader.Token peekedToken = reader.peek();
|
||||||
|
if (peekedToken != JsonReader.Token.BEGIN_OBJECT) {
|
||||||
|
throw new JsonDataException("Expected BEGIN_OBJECT but was " + peekedToken
|
||||||
|
+ " at path " + reader.getPath());
|
||||||
|
}
|
||||||
|
Object jsonValue = reader.readJsonValue();
|
||||||
|
Map<String, Object> jsonObject = (Map<String, Object>) jsonValue;
|
||||||
|
Object label = jsonObject.get(labelKey);
|
||||||
|
if (label == null) {
|
||||||
|
throw new JsonDataException("Missing label for " + labelKey);
|
||||||
|
}
|
||||||
|
if (!(label instanceof String)) {
|
||||||
|
throw new JsonDataException("Label for '"
|
||||||
|
+ labelKey
|
||||||
|
+ "' must be a string but was "
|
||||||
|
+ label
|
||||||
|
+ ", a "
|
||||||
|
+ label.getClass());
|
||||||
|
}
|
||||||
|
JsonAdapter<Object> adapter = labelToAdapter.get(label);
|
||||||
|
if (adapter == null) {
|
||||||
|
return fallbackAdapter.fromJsonValue(jsonValue);
|
||||||
|
}
|
||||||
|
return adapter.fromJsonValue(jsonValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toJson(JsonWriter writer, Object value) throws IOException {
|
||||||
|
Class<?> type = value.getClass();
|
||||||
|
String label = typeToLabel.get(type);
|
||||||
|
if (label == null) {
|
||||||
|
throw new IllegalArgumentException("Expected one of "
|
||||||
|
+ typeToLabel.keySet()
|
||||||
|
+ " but found "
|
||||||
|
+ value
|
||||||
|
+ ", a "
|
||||||
|
+ value.getClass()
|
||||||
|
+ ". Register this subtype.");
|
||||||
|
}
|
||||||
|
JsonAdapter<Object> adapter = labelToAdapter.get(label);
|
||||||
|
Map<String, Object> jsonValue = (Map<String, Object>) adapter.toJsonValue(value);
|
||||||
|
|
||||||
|
Map<String, Object> valueWithLabel = new LinkedHashMap<>(1 + jsonValue.size());
|
||||||
|
valueWithLabel.put(labelKey, label);
|
||||||
|
valueWithLabel.putAll(jsonValue);
|
||||||
|
objectJsonAdapter.toJson(writer, valueWithLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RuntimeJsonAdapter(" + labelKey + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersRequest
|
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersRequest
|
||||||
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||||
|
@ -36,7 +37,7 @@ data class DefaultRoom(
|
||||||
override val roomSummary: LiveData<RoomSummary> by lazy {
|
override val roomSummary: LiveData<RoomSummary> by lazy {
|
||||||
val liveData = monarchy
|
val liveData = monarchy
|
||||||
.findAllMappedWithChanges(
|
.findAllMappedWithChanges(
|
||||||
{ realm -> RoomSummaryEntity.where(realm, roomId) },
|
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
|
||||||
{ from -> from.asDomain() })
|
{ from -> from.asDomain() })
|
||||||
|
|
||||||
Transformations.map(liveData) {
|
Transformations.map(liveData) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||||
import im.vector.matrix.android.internal.database.query.lastSelected
|
import im.vector.matrix.android.internal.database.query.lastSelected
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
||||||
|
|
||||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||||
return monarchy.findAllMappedWithChanges(
|
return monarchy.findAllMappedWithChanges(
|
||||||
{ realm -> RoomSummaryEntity.where(realm) },
|
{ realm -> RoomSummaryEntity.where(realm).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
|
||||||
{ it.asDomain() }
|
{ it.asDomain() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
|
||||||
import im.vector.matrix.android.internal.session.sync.model.RoomSync
|
import im.vector.matrix.android.internal.session.sync.model.RoomSync
|
||||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncEphemeral
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncEphemeral
|
||||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.RoomsSyncResponse
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.kotlin.createObject
|
import io.realm.kotlin.createObject
|
||||||
|
|
||||||
|
@ -29,7 +30,21 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||||
data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy()
|
data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleRoomSync(handlingStrategy: HandlingStrategy) {
|
fun handle(roomsSyncResponse: RoomsSyncResponse) {
|
||||||
|
handleRoomSync(RoomSyncHandler.HandlingStrategy.JOINED(roomsSyncResponse.join))
|
||||||
|
handleRoomSync(RoomSyncHandler.HandlingStrategy.INVITED(roomsSyncResponse.invite))
|
||||||
|
handleRoomSync(RoomSyncHandler.HandlingStrategy.LEFT(roomsSyncResponse.leave))
|
||||||
|
|
||||||
|
monarchy.runTransactionSync { realm ->
|
||||||
|
roomsSyncResponse.join.forEach { (roomId, roomSync) ->
|
||||||
|
handleEphemeral(realm, roomId, roomSync.ephemeral)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
|
private fun handleRoomSync(handlingStrategy: HandlingStrategy) {
|
||||||
monarchy.runTransactionSync { realm ->
|
monarchy.runTransactionSync { realm ->
|
||||||
val rooms = when (handlingStrategy) {
|
val rooms = when (handlingStrategy) {
|
||||||
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) }
|
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) }
|
||||||
|
@ -38,18 +53,8 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||||
}
|
}
|
||||||
realm.insertOrUpdate(rooms)
|
realm.insertOrUpdate(rooms)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlingStrategy is HandlingStrategy.JOINED) {
|
|
||||||
monarchy.runTransactionSync { realm ->
|
|
||||||
handlingStrategy.data.forEach { (roomId, roomSync) ->
|
|
||||||
handleEphemeral(realm, roomId, roomSync.ephemeral)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
|
||||||
|
|
||||||
private fun handleJoinedRoom(realm: Realm,
|
private fun handleJoinedRoom(realm: Realm,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
roomSync: RoomSync): RoomEntity {
|
roomSync: RoomSync): RoomEntity {
|
||||||
|
|
|
@ -30,7 +30,11 @@ class SyncModule : Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
SyncResponseHandler(get())
|
UserAccountDataSyncHandler(get())
|
||||||
|
}
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
SyncResponseHandler(get(), get())
|
||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
|
|
|
@ -3,21 +3,20 @@ package im.vector.matrix.android.internal.session.sync
|
||||||
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler) {
|
internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler,
|
||||||
|
private val userAccountDataSyncHandler: UserAccountDataSyncHandler) {
|
||||||
|
|
||||||
fun handleResponse(syncResponse: SyncResponse?, fromToken: String?, isCatchingUp: Boolean) {
|
fun handleResponse(syncResponse: SyncResponse?, fromToken: String?, isCatchingUp: Boolean) {
|
||||||
if (syncResponse == null) {
|
if (syncResponse == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Timber.v("Handle sync response")
|
Timber.v("Handle sync response")
|
||||||
|
|
||||||
if (syncResponse.rooms != null) {
|
if (syncResponse.rooms != null) {
|
||||||
// joined rooms events
|
roomSyncHandler.handle(syncResponse.rooms)
|
||||||
roomSyncHandler.handleRoomSync(RoomSyncHandler.HandlingStrategy.JOINED(syncResponse.rooms.join))
|
}
|
||||||
roomSyncHandler.handleRoomSync(RoomSyncHandler.HandlingStrategy.INVITED(syncResponse.rooms.invite))
|
if (syncResponse.accountData != null) {
|
||||||
roomSyncHandler.handleRoomSync(RoomSyncHandler.HandlingStrategy.LEFT(syncResponse.rooms.leave))
|
userAccountDataSyncHandler.handle(syncResponse.accountData)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package im.vector.matrix.android.internal.session.sync
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataSync
|
||||||
|
|
||||||
|
class UserAccountDataSyncHandler(private val monarchy: Monarchy) {
|
||||||
|
|
||||||
|
fun handle(accountData: UserAccountDataSync) {
|
||||||
|
accountData.list.forEach {
|
||||||
|
when (it) {
|
||||||
|
is UserAccountDataDirectMessages -> handleDirectChatRooms(it)
|
||||||
|
else -> return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleDirectChatRooms(directMessages: UserAccountDataDirectMessages) {
|
||||||
|
val newDirectRoomIds = directMessages.content.values.flatten()
|
||||||
|
monarchy.runTransactionSync { realm ->
|
||||||
|
|
||||||
|
val oldDirectRooms = RoomSummaryEntity.where(realm).equalTo(RoomSummaryEntityFields.IS_DIRECT, true).findAll()
|
||||||
|
oldDirectRooms.forEach { it.isDirect = false }
|
||||||
|
|
||||||
|
newDirectRoomIds.forEach { roomId ->
|
||||||
|
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||||
|
if (roomSummaryEntity != null) {
|
||||||
|
roomSummaryEntity.isDirect = true
|
||||||
|
realm.insertOrUpdate(roomSummaryEntity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ data class SyncResponse(
|
||||||
/**
|
/**
|
||||||
* The user private data.
|
* The user private data.
|
||||||
*/
|
*/
|
||||||
@Json(name = "account_data") val accountData: Map<String, Any>? = emptyMap(),
|
@Json(name = "account_data") val accountData: UserAccountDataSync? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The opaque token for the end.
|
* The opaque token for the end.
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package im.vector.matrix.android.internal.session.sync.model
|
||||||
|
|
||||||
|
interface UserAccountData {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list"
|
||||||
|
const val TYPE_DIRECT_MESSAGES = "m.direct"
|
||||||
|
const val TYPE_PREVIEW_URLS = "org.matrix.preview_urls"
|
||||||
|
const val TYPE_WIDGETS = "m.widgets"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package im.vector.matrix.android.internal.session.sync.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class UserAccountDataDirectMessages(
|
||||||
|
@Json(name = "content") val content: Map<String, List<String>>
|
||||||
|
) : UserAccountData
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package im.vector.matrix.android.internal.session.sync.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class UserAccountDataFallback(
|
||||||
|
@Json(name = "content") val content: Map<String, Any>
|
||||||
|
) : UserAccountData
|
|
@ -0,0 +1,9 @@
|
||||||
|
package im.vector.matrix.android.internal.session.sync.model
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class UserAccountDataSync(
|
||||||
|
@Json(name = "events") val list: List<UserAccountData> = emptyList()
|
||||||
|
)
|
Loading…
Add table
Reference in a new issue