diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt index 2c6541266c..8b957d0044 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt @@ -23,6 +23,7 @@ import im.vector.riotredesign.core.error.ErrorFormatter import im.vector.riotredesign.core.resources.LocaleProvider import im.vector.riotredesign.core.resources.StringArrayProvider import im.vector.riotredesign.core.resources.StringProvider +import im.vector.riotredesign.features.home.HomeRoomListObservableStore import im.vector.riotredesign.features.home.group.SelectedGroupStore import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator import im.vector.riotredesign.features.notifications.NotificationDrawerManager @@ -52,6 +53,10 @@ class AppModule(private val context: Context) { SelectedGroupStore() } + single { + HomeRoomListObservableStore() + } + single { RoomSummaryComparator() } diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/DateProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/DateProvider.kt index cc01bdf183..8c485b1b73 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/resources/DateProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/DateProvider.kt @@ -29,4 +29,9 @@ object DateProvider { return LocalDateTime.ofInstant(instant, zoneId) } + fun currentLocalDateTime(): LocalDateTime { + val instant = Instant.now() + return LocalDateTime.ofInstant(instant, zoneId) + } + } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index e5f085aa23..ca17d855a2 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -25,14 +25,7 @@ import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserControl import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter import im.vector.riotredesign.features.home.group.GroupSummaryController import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController -import im.vector.riotredesign.features.home.room.detail.timeline.factory.CallItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.DefaultItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.MessageItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomHistoryVisibilityItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomMemberItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomNameItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomTopicItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory +import im.vector.riotredesign.features.home.room.detail.timeline.factory.* import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.riotredesign.features.home.room.list.RoomSummaryController @@ -56,36 +49,36 @@ class HomeModule { HomeNavigator() } - scope(HOME_SCOPE) { - HomeRoomListObservableStore() - } - scope(HOME_SCOPE) { HomePermalinkHandler(get()) } // Fragment scopes + factory { + TimelineDateFormatter(get()) + } + factory { (fragment: Fragment) -> val eventHtmlRenderer = EventHtmlRenderer(GlideApp.with(fragment), fragment.requireContext(), get()) - val timelineDateFormatter = TimelineDateFormatter(get()) val timelineMediaSizeProvider = TimelineMediaSizeProvider() val colorProvider = ColorProvider(fragment.requireContext()) + val timelineDateFormatter = get() val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider, timelineDateFormatter, eventHtmlRenderer) val timelineItemFactory = TimelineItemFactory(messageItemFactory = messageItemFactory, - roomNameItemFactory = RoomNameItemFactory(get()), - roomTopicItemFactory = RoomTopicItemFactory(get()), - roomMemberItemFactory = RoomMemberItemFactory(get()), - roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()), - callItemFactory = CallItemFactory(get()), - defaultItemFactory = DefaultItemFactory() + roomNameItemFactory = RoomNameItemFactory(get()), + roomTopicItemFactory = RoomTopicItemFactory(get()), + roomMemberItemFactory = RoomMemberItemFactory(get()), + roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()), + callItemFactory = CallItemFactory(get()), + defaultItemFactory = DefaultItemFactory() ) TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider) } factory { - RoomSummaryController(get()) + RoomSummaryController(get(), get()) } factory { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt index 1c015aa014..68b158e49c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt @@ -29,6 +29,7 @@ import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.core.utils.LiveEvent import im.vector.riotredesign.features.home.HomeRoomListObservableStore +import io.reactivex.Observable import org.koin.android.ext.android.get typealias RoomListFilterName = CharSequence @@ -50,7 +51,7 @@ class RoomListViewModel(initialState: RoomListViewState, } } - + private val displayMode = initialState.displayMode private val roomListFilter = BehaviorRelay.createDefault>(Option.empty()) private val _openRoomLiveData = MutableLiveData>() @@ -86,15 +87,27 @@ class RoomListViewModel(initialState: RoomListViewState, private fun observeRoomSummaries() { - homeRoomListObservableSource.observe() + homeRoomListObservableSource + .observe() + .flatMapSingle { + Observable.fromIterable(it) + .filter(filterByDisplayMode(displayMode)) + .toList() + } .map { buildRoomSummaries(it) } .execute { async -> - copy( - asyncRooms = async - ) + copy(asyncRooms = async) } } + private fun filterByDisplayMode(displayMode: RoomListFragment.DisplayMode) = { roomSummary: RoomSummary -> + when (displayMode) { + RoomListFragment.DisplayMode.HOME -> roomSummary.notificationCount > 0 + RoomListFragment.DisplayMode.PEOPLE -> roomSummary.isDirect + RoomListFragment.DisplayMode.ROOMS -> !roomSummary.isDirect + } + } + private fun buildRoomSummaries(rooms: List): RoomSummaries { val invites = ArrayList() val favourites = ArrayList() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt index 10c95efa4f..dfe0b7b665 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.riotredesign.R data class RoomListViewState( + val displayMode: RoomListFragment.DisplayMode, val asyncRooms: Async = Uninitialized, val isInviteExpanded: Boolean = true, val isFavouriteRoomsExpanded: Boolean = true, @@ -33,6 +34,8 @@ data class RoomListViewState( val isServerNoticeRoomsExpanded: Boolean = true ) : MvRxState { + constructor(args: RoomListParams) : this(displayMode = args.displayMode) + fun isCategoryExpanded(roomCategory: RoomCategory): Boolean { return when (roomCategory) { RoomCategory.INVITE -> isInviteExpanded diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt index c509af407d..e25560d72f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt @@ -19,9 +19,13 @@ package im.vector.riotredesign.features.home.room.list import androidx.annotation.StringRes import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.room.model.RoomSummary +import im.vector.riotredesign.core.extensions.localDateTime +import im.vector.riotredesign.core.resources.DateProvider import im.vector.riotredesign.core.resources.StringProvider +import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter -class RoomSummaryController(private val stringProvider: StringProvider +class RoomSummaryController(private val stringProvider: StringProvider, + private val timelineDateFormatter: TimelineDateFormatter ) : TypedEpoxyController() { var callback: Callback? = null @@ -76,9 +80,29 @@ class RoomSummaryController(private val stringProvider: StringProvider val unreadCount = roomSummary.notificationCount val showHighlighted = roomSummary.highlightCount > 0 + var lastMessageFormatted: CharSequence = "" + var lastMessageTime: CharSequence = "" + val lastMessage = roomSummary.lastMessage + if (lastMessage != null) { + val date = lastMessage.localDateTime() + val currentData = DateProvider.currentLocalDateTime() + val isSameDay = date.toLocalDate() == currentData.toLocalDate() + //TODO: get formatted + lastMessageFormatted = lastMessage.content?.toString() ?: "" + lastMessageTime = if (isSameDay) { + timelineDateFormatter.formatMessageHour(date) + } else { + //TODO: change this + timelineDateFormatter.formatMessageDay(date) + } + + + } roomSummaryItem { id(roomSummary.roomId) roomId(roomSummary.roomId) + lastEventTime(lastMessageTime) + lastFormattedEvent(lastMessageFormatted) roomName(roomSummary.displayName) avatarUrl(roomSummary.avatarUrl) showHighlighted(showHighlighted) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt index 1cdde14d94..0177757bec 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt @@ -32,6 +32,8 @@ abstract class RoomSummaryItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var roomName: CharSequence @EpoxyAttribute lateinit var roomId: String + @EpoxyAttribute lateinit var lastFormattedEvent: CharSequence + @EpoxyAttribute lateinit var lastEventTime: CharSequence @EpoxyAttribute var avatarUrl: String? = null @EpoxyAttribute var unreadCount: Int = 0 @EpoxyAttribute var showHighlighted: Boolean = false @@ -40,15 +42,17 @@ abstract class RoomSummaryItem : VectorEpoxyModel() { override fun bind(holder: Holder) { super.bind(holder) - holder.unreadCounterBadgeView.render(unreadCount, showHighlighted) holder.rootView.setOnClickListener { listener?.invoke() } holder.titleView.text = roomName + holder.lastEventTimeView.text = lastEventTime + holder.lastEventView.text = lastFormattedEvent AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView) } class Holder : VectorEpoxyHolder() { - val unreadCounterBadgeView by bind(R.id.roomUnreadCounterBadgeView) val titleView by bind(R.id.roomNameView) + val lastEventView by bind(R.id.roomLastEventView) + val lastEventTimeView by bind(R.id.roomLastEventTimeView) val avatarImageView by bind(R.id.roomAvatarImageView) val rootView by bind(R.id.itemRoomLayout) } diff --git a/vector/src/main/res/layout/item_room.xml b/vector/src/main/res/layout/item_room.xml index 807d23636c..e53dc9495c 100644 --- a/vector/src/main/res/layout/item_room.xml +++ b/vector/src/main/res/layout/item_room.xml @@ -9,7 +9,8 @@ android:background="?attr/selectableItemBackground" android:clickable="true" android:focusable="true" - android:minHeight="48dp" + android:paddingBottom="16dp" + android:paddingTop="16dp" android:paddingStart="8dp" android:paddingLeft="8dp" android:paddingEnd="16dp" @@ -17,8 +18,8 @@ - + + + app:layout_constraintStart_toEndOf="@id/messageMemberNameView" + tools:text="@tools:sample/date/hhmm" /> + diff --git a/vector/src/main/res/values/colors.xml b/vector/src/main/res/values/colors.xml index 75bad0824f..a863247f7f 100644 --- a/vector/src/main/res/values/colors.xml +++ b/vector/src/main/res/values/colors.xml @@ -16,6 +16,9 @@ #ebedf8 #a5a5a5 #61708B + #de000000 + #61000000 + #5d000000 #000000 #de000000