Merge pull request #372 from vector-im/feature/room_filtering

Room filtering
This commit is contained in:
Benoit Marty 2019-07-16 11:41:08 +02:00 committed by GitHub
commit 42584fc55a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 504 additions and 50 deletions

View file

@ -3,6 +3,7 @@ Changes in RiotX 0.2.1 (2019-XX-XX)
Features:
- Message Editing: View edit history
- Rooms filtering (#304)
Improvements:
- Handle click on redacted events: view source and create permalink

View file

@ -58,8 +58,10 @@
<activity
android:name=".features.reactions.EmojiReactionPickerActivity"
android:label="@string/title_activity_emoji_reaction_picker" />
<activity android:name=".features.roomdirectory.createroom.CreateRoomActivity" />
<activity android:name=".features.roomdirectory.RoomDirectoryActivity" />
<activity android:name=".features.roomdirectory.roompreview.RoomPreviewActivity" />
<activity android:name=".features.home.room.filtered.FilteredRoomsActivity" />
<activity android:name=".features.home.room.detail.RoomDetailActivity" />
<activity android:name=".features.debug.DebugMenuActivity" />

View file

@ -32,10 +32,14 @@ import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupStep1Frag
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupStep2Fragment
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupStep3Fragment
import im.vector.riotx.features.crypto.verification.SASVerificationIncomingFragment
import im.vector.riotx.features.home.*
import im.vector.riotx.features.home.HomeActivity
import im.vector.riotx.features.home.HomeDetailFragment
import im.vector.riotx.features.home.HomeDrawerFragment
import im.vector.riotx.features.home.HomeModule
import im.vector.riotx.features.home.group.GroupListFragment
import im.vector.riotx.features.home.room.detail.RoomDetailFragment
import im.vector.riotx.features.home.room.detail.timeline.action.*
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
import im.vector.riotx.features.home.room.list.RoomListFragment
import im.vector.riotx.features.invite.VectorInviteView
import im.vector.riotx.features.login.LoginActivity
@ -47,6 +51,7 @@ import im.vector.riotx.features.rageshake.RageShake
import im.vector.riotx.features.reactions.EmojiReactionPickerActivity
import im.vector.riotx.features.roomdirectory.PublicRoomsFragment
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomFragment
import im.vector.riotx.features.roomdirectory.picker.RoomDirectoryPickerFragment
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
@ -130,6 +135,10 @@ interface ScreenComponent {
fun inject(imageMediaViewerActivity: ImageMediaViewerActivity)
fun inject(filteredRoomsActivity: FilteredRoomsActivity)
fun inject(createRoomActivity: CreateRoomActivity)
fun inject(vectorInviteView: VectorInviteView)
fun inject(videoMediaViewerActivity: VideoMediaViewerActivity)

View file

@ -23,8 +23,8 @@ fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int) {
supportFragmentManager.inTransaction { add(frameId, fragment) }
}
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int) {
supportFragmentManager.inTransaction { replace(frameId, fragment) }
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int, tag: String? = null) {
supportFragmentManager.inTransaction { replace(frameId, fragment, tag) }
}
fun AppCompatActivity.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {

View file

@ -41,6 +41,7 @@ import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.pushers.PushersManager
import im.vector.riotx.features.disclaimer.showDisclaimerDialog
import im.vector.riotx.features.navigation.Navigator
import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.workers.signout.SignOutViewModel
@ -64,6 +65,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var homeActivityViewModelFactory: HomeActivityViewModel.Factory
@Inject lateinit var homeNavigator: HomeNavigator
@Inject lateinit var navigator: Navigator
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
@Inject lateinit var pushManager: PushersManager
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
@ -192,6 +194,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
bugReporter.openBugReportScreen(this, false)
return true
}
R.id.menu_home_filter -> {
navigator.openRoomsFiltering(this)
return true
}
}
return true

View file

@ -35,7 +35,7 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
super.onCreate(savedInstanceState)
if (isFirstCreation()) {
val roomDetailArgs: RoomDetailArgs = intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
?: return
?: return
val roomDetailFragment = RoomDetailFragment.newInstance(roomDetailArgs)
replaceFragment(roomDetailFragment, R.id.roomDetailContainer)
}

View file

@ -18,7 +18,6 @@ package im.vector.riotx.features.home.room.detail.timeline
import android.os.Handler
import android.os.Looper
import android.util.LongSparseArray
import android.view.View
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
@ -84,7 +83,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim
}
private val collapsedEventIds = linkedSetOf<Long>()
private val mergeItemCollapseStates = HashMap<Long,Boolean>()
private val mergeItemCollapseStates = HashMap<Long, Boolean>()
private val modelCache = arrayListOf<CacheItemData?>()
private var currentSnapshot: List<TimelineEvent> = emptyList()
@ -178,16 +177,19 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim
}
override fun buildModels() {
LoadingItem_()
val loaderAdded = LoadingItem_()
.id("forward_loading_item")
.addWhen(Timeline.Direction.FORWARDS)
val timelineModels = getModels()
add(timelineModels)
LoadingItem_()
.id("backward_loading_item")
.addWhen(Timeline.Direction.BACKWARDS)
// Avoid displaying two loaders if there is no elements between them
if (!loaderAdded || timelineModels.isNotEmpty()) {
LoadingItem_()
.id("backward_loading_item")
.addWhen(Timeline.Direction.BACKWARDS)
}
}
// Timeline.LISTENER ***************************************************************************
@ -310,9 +312,13 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim
}
}
private fun LoadingItem_.addWhen(direction: Timeline.Direction) {
/**
* Return true if added
*/
private fun LoadingItem_.addWhen(direction: Timeline.Direction): Boolean {
val shouldAdd = timeline?.hasMoreToLoad(direction) ?: false
addIf(shouldAdd, this@TimelineEventController)
return shouldAdd
}
fun searchPositionOfEvent(eventId: String): Int? {

View file

@ -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.riotx.features.home.room.filtered
import android.widget.Button
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.features.home.room.list.widget.FabMenuView
@EpoxyModelClass(layout = R.layout.item_room_filter_footer)
abstract class FilteredRoomFooterItem : VectorEpoxyModel<FilteredRoomFooterItem.Holder>() {
@EpoxyAttribute
var listener: FilteredRoomFooterItemListener? = null
override fun bind(holder: Holder) {
holder.createRoomButton.setOnClickListener { listener?.createRoom() }
holder.createDirectChat.setOnClickListener { listener?.createDirectChat() }
holder.openRoomDirectory.setOnClickListener { listener?.openRoomDirectory() }
}
class Holder : VectorEpoxyHolder() {
val createRoomButton by bind<Button>(R.id.roomFilterFooterCreateRoom)
val createDirectChat by bind<Button>(R.id.roomFilterFooterCreateDirect)
val openRoomDirectory by bind<Button>(R.id.roomFilterFooterOpenRoomDirectory)
}
interface FilteredRoomFooterItemListener : FabMenuView.Listener {
fun createRoom()
}
}

View file

@ -0,0 +1,81 @@
/*
* 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.riotx.features.home.room.filtered
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.features.home.room.list.RoomListFragment
import im.vector.riotx.features.home.room.list.RoomListParams
import kotlinx.android.synthetic.main.activity_filtered_rooms.*
class FilteredRoomsActivity : VectorBaseActivity(), ToolbarConfigurable {
private lateinit var roomListFragment: RoomListFragment
override fun getLayoutRes(): Int {
return R.layout.activity_filtered_rooms
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (isFirstCreation()) {
roomListFragment = RoomListFragment.newInstance(RoomListParams(RoomListFragment.DisplayMode.FILTERED))
replaceFragment(roomListFragment, R.id.filteredRoomsFragmentContainer, FRAGMENT_TAG)
} else {
roomListFragment = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as RoomListFragment
}
filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return true
}
override fun onQueryTextChange(newText: String): Boolean {
// TODO Create a viewModel and remove this public fun
roomListFragment.filterRoomsWith(newText)
return true
}
})
// Open the keyboard immediately
filteredRoomsSearchView.requestFocus()
}
override fun configure(toolbar: Toolbar) {
configureToolbar(toolbar)
}
companion object {
private const val FRAGMENT_TAG = "RoomListFragment"
fun newIntent(context: Context): Intent {
return Intent(context, FilteredRoomsActivity::class.java)
}
}
}

View file

@ -28,4 +28,6 @@ sealed class RoomListActions {
data class RejectInvitation(val roomSummary: RoomSummary) : RoomListActions()
data class FilterWith(val filter: String) : RoomListActions()
}

View file

@ -27,9 +27,10 @@ class RoomListDisplayModeFilter(private val displayMode: RoomListFragment.Displa
return false
}
return when (displayMode) {
RoomListFragment.DisplayMode.HOME -> roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE
RoomListFragment.DisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership == Membership.JOIN
RoomListFragment.DisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership == Membership.JOIN
RoomListFragment.DisplayMode.HOME -> roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE
RoomListFragment.DisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership == Membership.JOIN
RoomListFragment.DisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership == Membership.JOIN
RoomListFragment.DisplayMode.FILTERED -> roomSummary.membership == Membership.JOIN
}
}
}

View file

@ -53,7 +53,8 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
enum class DisplayMode(@StringRes val titleRes: Int) {
HOME(R.string.bottom_action_home),
PEOPLE(R.string.bottom_action_people_x),
ROOMS(R.string.bottom_action_rooms)
ROOMS(R.string.bottom_action_rooms),
FILTERED(/* Not used */ R.string.bottom_action_rooms)
}
companion object {
@ -97,9 +98,10 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
private fun setupCreateRoomButton() {
when (roomListParams.displayMode) {
DisplayMode.HOME -> createChatFabMenu.isVisible = true
DisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
else -> createGroupRoomButton.isVisible = true
DisplayMode.HOME -> createChatFabMenu.isVisible = true
DisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
DisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
DisplayMode.FILTERED -> Unit // No button in this mode
}
createChatRoomButton.setOnClickListener {
@ -122,9 +124,10 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> {
when (roomListParams.displayMode) {
DisplayMode.HOME -> createChatFabMenu.hide()
DisplayMode.PEOPLE -> createChatRoomButton.hide()
else -> createGroupRoomButton.hide()
DisplayMode.HOME -> createChatFabMenu.hide()
DisplayMode.PEOPLE -> createChatRoomButton.hide()
DisplayMode.ROOMS -> createGroupRoomButton.hide()
DisplayMode.FILTERED -> Unit
}
}
}
@ -132,6 +135,9 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
})
}
fun filterRoomsWith(filter: String) {
roomListViewModel.accept(RoomListActions.FilterWith(filter))
}
override fun openRoomDirectory() {
navigator.openRoomDirectory(requireActivity())
@ -155,9 +161,10 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
private val showFabRunnable = Runnable {
if (isAdded) {
when (roomListParams.displayMode) {
DisplayMode.HOME -> createChatFabMenu.show()
DisplayMode.PEOPLE -> createChatRoomButton.show()
else -> createGroupRoomButton.show()
DisplayMode.HOME -> createChatFabMenu.show()
DisplayMode.PEOPLE -> createChatRoomButton.show()
DisplayMode.ROOMS -> createGroupRoomButton.show()
DisplayMode.FILTERED -> Unit
}
}
}
@ -188,7 +195,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
}
.isNullOrEmpty()
val emptyState = when (roomListParams.displayMode) {
DisplayMode.HOME -> {
DisplayMode.HOME -> {
if (hasNoRoom) {
StateView.State.Empty(
getString(R.string.room_list_catchup_welcome_title),
@ -202,18 +209,21 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
getString(R.string.room_list_catchup_empty_body))
}
}
DisplayMode.PEOPLE ->
DisplayMode.PEOPLE ->
StateView.State.Empty(
getString(R.string.room_list_people_empty_title),
ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_bottom_chat),
getString(R.string.room_list_people_empty_body)
)
DisplayMode.ROOMS ->
DisplayMode.ROOMS ->
StateView.State.Empty(
getString(R.string.room_list_rooms_empty_title),
ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_bottom_group),
getString(R.string.room_list_rooms_empty_body)
)
DisplayMode.FILTERED ->
// Always display the content in this mode, because if the footer
StateView.State.Content
}
stateView.state = emptyState
}
@ -255,4 +265,10 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
override fun onToggleRoomCategory(roomCategory: RoomCategory) {
roomListViewModel.accept(RoomListActions.ToggleCategory(roomCategory))
}
// TODO Pass title
override fun createRoom() {
navigator.openCreateRoom(requireActivity())
}
}

View file

@ -14,8 +14,21 @@
* limitations under the License.
*/
package im.vector.riotx.features.home.room
package im.vector.riotx.features.home.room.list
import im.vector.riotx.core.utils.RxStore
import im.vector.matrix.android.api.session.room.model.RoomSummary
import io.reactivex.functions.Predicate
class VisibleRoomStore : RxStore<String>()
class RoomListNameFilter : Predicate<RoomSummary> {
var filter: String = ""
override fun test(roomSummary: RoomSummary): Boolean {
if (filter.isBlank()) {
// No filter
return true
}
return roomSummary.displayName.contains(filter, ignoreCase = true)
}
}

View file

@ -76,6 +76,7 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
is RoomListActions.ToggleCategory -> handleToggleCategory(action)
is RoomListActions.AcceptInvitation -> handleAcceptInvitation(action)
is RoomListActions.RejectInvitation -> handleRejectInvitation(action)
is RoomListActions.FilterWith -> handleFilter(action)
}
}
@ -89,10 +90,21 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
this.toggle(action.category)
}
private fun handleFilter(action: RoomListActions.FilterWith) {
setState {
copy(
roomFilter = action.filter
)
}
}
private fun observeRoomSummaries() {
homeRoomListObservableSource
.observe()
.observeOn(Schedulers.computation())
.map {
it.sortedWith(chronologicalRoomComparator)
}
.execute { asyncRooms ->
copy(asyncRooms = asyncRooms)
}
@ -201,9 +213,10 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
}
val roomComparator = when (displayMode) {
RoomListFragment.DisplayMode.HOME -> chronologicalRoomComparator
RoomListFragment.DisplayMode.PEOPLE -> chronologicalRoomComparator
RoomListFragment.DisplayMode.ROOMS -> chronologicalRoomComparator
RoomListFragment.DisplayMode.HOME -> chronologicalRoomComparator
RoomListFragment.DisplayMode.PEOPLE -> chronologicalRoomComparator
RoomListFragment.DisplayMode.ROOMS -> chronologicalRoomComparator
RoomListFragment.DisplayMode.FILTERED -> chronologicalRoomComparator
}
return RoomSummaries().apply {

View file

@ -26,6 +26,7 @@ import im.vector.riotx.R
data class RoomListViewState(
val displayMode: RoomListFragment.DisplayMode,
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
val roomFilter: String = "",
val asyncFilteredRooms: Async<RoomSummaries> = Uninitialized,
// List of roomIds that the user wants to join
val joiningRoomsIds: Set<String> = emptySet(),

View file

@ -20,6 +20,8 @@ import androidx.annotation.StringRes
import com.airbnb.epoxy.TypedEpoxyController
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.room.filtered.FilteredRoomFooterItem
import im.vector.riotx.features.home.room.filtered.filteredRoomFooterItem
import javax.inject.Inject
class RoomSummaryController @Inject constructor(private val stringProvider: StringProvider,
@ -28,27 +30,56 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
var listener: Listener? = null
private val roomListNameFilter = RoomListNameFilter()
override fun buildModels(viewState: RoomListViewState) {
val roomSummaries = viewState.asyncFilteredRooms()
roomSummaries?.forEach { (category, summaries) ->
if (summaries.isEmpty()) {
return@forEach
} else {
val isExpanded = viewState.isCategoryExpanded(category)
buildRoomCategory(viewState, summaries, category.titleRes, viewState.isCategoryExpanded(category)) {
listener?.onToggleRoomCategory(category)
}
if (isExpanded) {
buildRoomModels(summaries,
viewState.joiningRoomsIds,
viewState.joiningErrorRoomsIds,
viewState.rejectingRoomsIds,
viewState.rejectingErrorRoomsIds)
if (viewState.displayMode == RoomListFragment.DisplayMode.FILTERED) {
buildFilteredRooms(viewState)
} else {
val roomSummaries = viewState.asyncFilteredRooms()
roomSummaries?.forEach { (category, summaries) ->
if (summaries.isEmpty()) {
return@forEach
} else {
val isExpanded = viewState.isCategoryExpanded(category)
buildRoomCategory(viewState, summaries, category.titleRes, viewState.isCategoryExpanded(category)) {
listener?.onToggleRoomCategory(category)
}
if (isExpanded) {
buildRoomModels(summaries,
viewState.joiningRoomsIds,
viewState.joiningErrorRoomsIds,
viewState.rejectingRoomsIds,
viewState.rejectingErrorRoomsIds)
}
}
}
}
}
private fun buildFilteredRooms(viewState: RoomListViewState) {
val summaries = viewState.asyncRooms() ?: return
roomListNameFilter.filter = viewState.roomFilter
val filteredSummaries = summaries.filter { roomListNameFilter.test(it) }
buildRoomModels(filteredSummaries,
viewState.joiningRoomsIds,
viewState.joiningErrorRoomsIds,
viewState.rejectingRoomsIds,
viewState.rejectingErrorRoomsIds)
addFilterFooter()
}
private fun addFilterFooter() {
filteredRoomFooterItem {
id("filter_footer")
listener(listener)
}
}
private fun buildRoomCategory(viewState: RoomListViewState,
summaries: List<RoomSummary>,
@StringRes titleRes: Int,
@ -89,7 +120,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
}
}
interface Listener {
interface Listener : FilteredRoomFooterItem.FilteredRoomFooterItemListener {
fun onToggleRoomCategory(roomCategory: RoomCategory)
fun onRoomSelected(room: RoomSummary)
fun onRejectRoomInvitation(room: RoomSummary)

View file

@ -27,7 +27,9 @@ import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupActivity
import im.vector.riotx.features.debug.DebugMenuActivity
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewActivity
import im.vector.riotx.features.settings.VectorSettingsActivity
import timber.log.Timber
@ -61,6 +63,16 @@ class DefaultNavigator @Inject constructor() : Navigator {
context.startActivity(intent)
}
override fun openCreateRoom(context: Context) {
val intent = CreateRoomActivity.getIntent(context)
context.startActivity(intent)
}
override fun openRoomsFiltering(context: Context) {
val intent = FilteredRoomsActivity.newIntent(context)
context.startActivity(intent)
}
override fun openSettings(context: Context) {
val intent = VectorSettingsActivity.getIntent(context, "TODO")
context.startActivity(intent)

View file

@ -27,8 +27,12 @@ interface Navigator {
fun openRoomPreview(publicRoom: PublicRoom, context: Context)
fun openCreateRoom(context: Context)
fun openRoomDirectory(context: Context)
fun openRoomsFiltering(context: Context)
fun openSettings(context: Context)
fun openDebug(context: Context)

View file

@ -0,0 +1,72 @@
/*
* 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.riotx.features.roomdirectory.createroom
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.widget.Toolbar
import androidx.lifecycle.ViewModelProviders
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.addFragment
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.RoomDirectoryNavigationViewModel
/**
* Simple container for [CreateRoomFragment]
*/
class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable {
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
override fun getLayoutRes() = R.layout.activity_simple
override fun configure(toolbar: Toolbar) {
configureToolbar(toolbar)
}
override fun initUiAndData() {
if (isFirstCreation()) {
addFragment(CreateRoomFragment(), R.id.simpleFragmentContainer)
}
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java)
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
when (navigation) {
is RoomDirectoryActivity.Navigation.Back -> finish()
}
}
}
companion object {
fun getIntent(context: Context): Intent {
return Intent(context, CreateRoomActivity::class.java)
}
}
}

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4,6.5h16"
android:strokeWidth="1.8"
android:fillColor="#00000000"
android:strokeColor="#03B381"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M6,12.5h12M9,18.5h6"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#03B381"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="14"
android:viewportHeight="14">
<path
android:pathData="M13,1L1,13M1,1l12,12"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#03B381"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,43 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/filteredRoomsToolbar"
style="@style/VectorToolbarStyle"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.SearchView
android:id="@+id/filteredRoomsSearchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:closeIcon="@drawable/ic_x_green"
app:iconifiedByDefault="false"
app:queryHint="@string/home_filter_placeholder_home"
app:searchIcon="@drawable/ic_filter" />
</androidx.appcompat.widget.Toolbar>
<FrameLayout
android:id="@+id/filteredRoomsFragmentContainer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/filteredRoomsToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -44,6 +44,7 @@
android:maxLines="1"
android:textColor="?riotx_text_primary"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@+id/roomUnreadCounterBadgeView"
app:layout_constraintHorizontal_bias="0.0"

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?riotx_background"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="56dp"
android:text="@string/room_filtering_footer_title"
android:textColor="?riotx_text_secondary"
android:textSize="15sp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/roomFilterFooterCreateRoom"
style="@style/VectorButtonStyleFlat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/layout_vertical_margin"
android:text="@string/room_filtering_footer_create_new_room" />
<com.google.android.material.button.MaterialButton
android:id="@+id/roomFilterFooterCreateDirect"
style="@style/VectorButtonStyleFlat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/room_filtering_footer_create_new_direct_message" />
<com.google.android.material.button.MaterialButton
android:id="@+id/roomFilterFooterOpenRoomDirectory"
style="@style/VectorButtonStyleFlat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/layout_vertical_margin"
android:text="@string/room_filtering_footer_open_room_directory" />
</LinearLayout>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_home_suggestion"
@ -11,4 +12,10 @@
android:icon="@drawable/ic_material_bug_report"
android:title="@string/send_bug_report" />
<item
android:id="@+id/menu_home_filter"
android:icon="@drawable/ic_filter"
android:title="@string/home_filter_placeholder_home"
app:showAsAction="always" />
</menu>

View file

@ -25,4 +25,11 @@
<string name="message_edits">Message Edits</string>
<string name="no_message_edits_found">No edits found</string>
<!-- Room filtering -->
<string name="room_filtering_footer_title">Cant find what youre looking for?</string>
<string name="room_filtering_footer_create_new_room">Create a new room</string>
<string name="room_filtering_footer_create_new_direct_message">Send a new direct message</string>
<string name="room_filtering_footer_open_room_directory">View the room directory</string>
</resources>