mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Merge branch 'develop' into feature/crypto
This commit is contained in:
commit
6dacb9894e
39 changed files with 902 additions and 90 deletions
|
@ -100,7 +100,7 @@ class CreateRoomParams {
|
|||
* private_chat => join_rules is set to invite. history_visibility is set to shared.
|
||||
* trusted_private_chat => join_rules is set to invite. history_visibility is set to shared. All invitees are given the same power level as the
|
||||
* room creator.
|
||||
* public_chat: => join_rules is set to public. history_visibility is set to shared. One of: ["private_chat", "public_chat", "trusted_private_chat"]
|
||||
* public_chat: => join_rules is set to public. history_visibility is set to shared.
|
||||
*/
|
||||
var preset: CreateRoomPreset? = null
|
||||
|
||||
|
|
|
@ -18,12 +18,7 @@ package im.vector.matrix.android.internal.database
|
|||
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmChangeListener
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.RealmResults
|
||||
import io.realm.*
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
private const val THREAD_NAME = "REALM_QUERY_LATCH"
|
||||
|
@ -39,6 +34,7 @@ class RealmQueryLatch<E : RealmObject>(private val realmConfiguration: RealmConf
|
|||
val runnable = Runnable {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
val result = realmQueryBuilder(realm).findAllAsync()
|
||||
|
||||
result.addChangeListener(object : RealmChangeListener<RealmResults<E>> {
|
||||
override fun onChange(t: RealmResults<E>) {
|
||||
if (t.isNotEmpty()) {
|
||||
|
|
|
@ -66,7 +66,7 @@ class NetworkModule {
|
|||
|
||||
single {
|
||||
OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.connectTimeout(1, TimeUnit.MINUTES)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.addNetworkInterceptor(get<StethoInterceptor>())
|
||||
|
|
|
@ -16,23 +16,16 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.room.create
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import arrow.core.Try
|
||||
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.internal.database.RealmQueryLatch
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntityFields
|
||||
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
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmChangeListener
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmResults
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
private const val THREAD_NAME = "CREATE_ROOM_"
|
||||
|
||||
internal interface CreateRoomTask : Task<CreateRoomParams, String>
|
||||
|
||||
|
@ -47,41 +40,15 @@ internal class DefaultCreateRoomTask(private val roomAPI: RoomAPI,
|
|||
}.flatMap { createRoomResponse ->
|
||||
val roomId = createRoomResponse.roomId!!
|
||||
|
||||
val latch = CountDownLatch(1)
|
||||
|
||||
// TODO Maybe do the same code for join room request ?
|
||||
// Wait for room to come back from the sync (but it can maybe be in the DB is the sync response is received before)
|
||||
val handlerThread = HandlerThread(THREAD_NAME + hashCode())
|
||||
handlerThread.start()
|
||||
val handler = Handler(handlerThread.looper)
|
||||
|
||||
handler.post {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
if (realm.where(RoomEntity::class.java)
|
||||
.equalTo(RoomEntityFields.ROOM_ID, roomId)
|
||||
.findAll()
|
||||
.isEmpty()) {
|
||||
val result = realm.where(RoomEntity::class.java)
|
||||
.equalTo(RoomEntityFields.ROOM_ID, roomId)
|
||||
.findAllAsync()
|
||||
|
||||
result.addChangeListener(object : RealmChangeListener<RealmResults<RoomEntity>> {
|
||||
override fun onChange(t: RealmResults<RoomEntity>) {
|
||||
if (t.isNotEmpty()) {
|
||||
result.removeChangeListener(this)
|
||||
realm.close()
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
realm.close()
|
||||
latch.countDown()
|
||||
}
|
||||
val rql = RealmQueryLatch<RoomEntity>(realmConfiguration) { realm ->
|
||||
realm.where(RoomEntity::class.java)
|
||||
.equalTo(RoomEntityFields.ROOM_ID, roomId)
|
||||
}
|
||||
|
||||
latch.await()
|
||||
handlerThread.quit()
|
||||
rql.await()
|
||||
|
||||
return Try.just(roomId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.riotredesign.core.mvrx
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotredesign.core.utils.LiveEvent
|
||||
|
||||
abstract class NavigationViewModel<NavigationClass> : ViewModel() {
|
||||
|
||||
private val _navigateTo = MutableLiveData<LiveEvent<NavigationClass>>()
|
||||
val navigateTo: LiveData<LiveEvent<NavigationClass>>
|
||||
get() = _navigateTo
|
||||
|
||||
|
||||
fun goTo(navigation: NavigationClass) {
|
||||
_navigateTo.postValue(LiveEvent(navigation))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.form
|
||||
|
||||
import android.text.Editable
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
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.SimpleTextWatcher
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_form_text_input)
|
||||
abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var hint: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var value: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var enabled: Boolean = true
|
||||
|
||||
@EpoxyAttribute
|
||||
var onTextChange: ((String) -> Unit)? = null
|
||||
|
||||
private val onTextChangeListener = object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
onTextChange?.invoke(s.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
holder.textInputLayout.isEnabled = enabled
|
||||
holder.textInputLayout.hint = hint
|
||||
|
||||
// Update only if text is different
|
||||
if (holder.textInputEditText.text.toString() != value) {
|
||||
holder.textInputEditText.setText(value)
|
||||
}
|
||||
holder.textInputEditText.isEnabled = enabled
|
||||
|
||||
holder.textInputEditText.addTextChangedListener(onTextChangeListener)
|
||||
}
|
||||
|
||||
override fun shouldSaveViewState(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun unbind(holder: Holder) {
|
||||
super.unbind(holder)
|
||||
holder.textInputEditText.removeTextChangedListener(onTextChangeListener)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textInputLayout by bind<TextInputLayout>(R.id.formTextInputTextInputLayout)
|
||||
val textInputEditText by bind<TextInputEditText>(R.id.formTextInputTextInputEditText)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.form
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||
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
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_form_switch)
|
||||
abstract class FormSwitchItem : VectorEpoxyModel<FormSwitchItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var listener: ((Boolean) -> Unit)? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var enabled: Boolean = true
|
||||
|
||||
@EpoxyAttribute
|
||||
var switchChecked: Boolean = false
|
||||
|
||||
@EpoxyAttribute
|
||||
var title: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var summary: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
holder.titleView.text = title
|
||||
holder.summaryView.setTextOrHide(summary)
|
||||
|
||||
holder.switchView.isEnabled = enabled
|
||||
|
||||
holder.switchView.isChecked = switchChecked
|
||||
|
||||
holder.switchView.setOnCheckedChangeListener { _, isChecked ->
|
||||
listener?.invoke(isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldSaveViewState(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun unbind(holder: Holder) {
|
||||
super.unbind(holder)
|
||||
|
||||
holder.switchView.setOnCheckedChangeListener(null)
|
||||
}
|
||||
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val titleView by bind<TextView>(R.id.formSwitchTitle)
|
||||
val summaryView by bind<TextView>(R.id.formSwitchSummary)
|
||||
val switchView by bind<SwitchMaterial>(R.id.formSwitchSwitch)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,10 +27,12 @@ import androidx.core.view.GravityCompat
|
|||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.hideKeyboard
|
||||
import im.vector.riotredesign.core.extensions.observeEvent
|
||||
import im.vector.riotredesign.core.extensions.replaceFragment
|
||||
import im.vector.riotredesign.core.platform.OnBackPressed
|
||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||
|
@ -47,7 +49,13 @@ import org.koin.android.scope.ext.android.getOrCreateScope
|
|||
|
||||
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||
|
||||
// Supported navigation actions for this Activity
|
||||
sealed class Navigation {
|
||||
object OpenDrawer : Navigation()
|
||||
}
|
||||
|
||||
private val homeActivityViewModel: HomeActivityViewModel by viewModel()
|
||||
private lateinit var navigationViewModel: HomeNavigationViewModel
|
||||
private val homeNavigator by inject<HomeNavigator>()
|
||||
|
||||
// TODO Move this elsewhere
|
||||
|
@ -67,6 +75,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
super.onCreate(savedInstanceState)
|
||||
bindScope(getOrCreateScope(HomeModule.HOME_SCOPE))
|
||||
homeNavigator.activity = this
|
||||
|
||||
navigationViewModel = ViewModelProviders.of(this).get(HomeNavigationViewModel::class.java)
|
||||
|
||||
drawerLayout.addDrawerListener(drawerListener)
|
||||
if (isFirstCreation()) {
|
||||
val homeDrawerFragment = HomeDrawerFragment.newInstance()
|
||||
|
@ -87,6 +98,12 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
}
|
||||
})
|
||||
|
||||
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
}
|
||||
}
|
||||
|
||||
incomingVerificationRequestHandler.ensureStarted()
|
||||
}
|
||||
|
||||
|
@ -119,10 +136,6 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
drawerLayout.openDrawer(GravityCompat.START)
|
||||
return true
|
||||
}
|
||||
R.id.sliding_menu_sign_out -> {
|
||||
SignOutUiWorker(this).perform(Matrix.getInstance().currentSession!!)
|
||||
return true
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.view.forEachIndexed
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -56,6 +57,7 @@ class HomeDetailFragment : VectorBaseFragment() {
|
|||
private lateinit var currentDisplayMode: RoomListFragment.DisplayMode
|
||||
|
||||
private val viewModel: HomeDetailViewModel by fragmentViewModel()
|
||||
private lateinit var navigationViewModel: HomeNavigationViewModel
|
||||
|
||||
override fun getLayoutResId(): Int {
|
||||
return R.layout.fragment_home_detail
|
||||
|
@ -65,6 +67,9 @@ class HomeDetailFragment : VectorBaseFragment() {
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
currentDisplayMode = savedInstanceState?.getSerializable(CURRENT_DISPLAY_MODE) as? RoomListFragment.DisplayMode
|
||||
?: RoomListFragment.DisplayMode.HOME
|
||||
|
||||
navigationViewModel = ViewModelProviders.of(requireActivity()).get(HomeNavigationViewModel::class.java)
|
||||
|
||||
switchDisplayMode(currentDisplayMode)
|
||||
setupBottomNavigationView()
|
||||
setupToolbar()
|
||||
|
@ -89,7 +94,7 @@ class HomeDetailFragment : VectorBaseFragment() {
|
|||
groupToolbarAvatarImageView
|
||||
)
|
||||
groupToolbarAvatarImageView.setOnClickListener {
|
||||
vectorBaseActivity.notImplemented("Group click in toolbar")
|
||||
navigationViewModel.goTo(HomeActivity.Navigation.OpenDrawer)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ class HomeDetailViewModel(initialState: HomeDetailViewState,
|
|||
.filter { it.isDirect }
|
||||
.map { it.notificationCount }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.reduce { acc, i -> acc + i }
|
||||
?.sumBy { i -> i }
|
||||
?: 0
|
||||
val peopleHasHighlight = summaries
|
||||
.filter { it.isDirect }
|
||||
|
@ -62,7 +62,7 @@ class HomeDetailViewModel(initialState: HomeDetailViewState,
|
|||
.filter { !it.isDirect }
|
||||
.map { it.notificationCount }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.reduce { acc, i -> acc + i }
|
||||
?.sumBy { i -> i }
|
||||
?: 0
|
||||
val roomsHasHighlight = summaries
|
||||
.filter { !it.isDirect }
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.home
|
||||
|
||||
import im.vector.riotredesign.core.mvrx.NavigationViewModel
|
||||
|
||||
class HomeNavigationViewModel : NavigationViewModel<HomeActivity.Navigation>()
|
|
@ -64,7 +64,7 @@ class RoomSummaryController(private val stringProvider: StringProvider,
|
|||
val unreadCount = if (summaries.isEmpty()) {
|
||||
0
|
||||
} else {
|
||||
summaries.map { it.notificationCount }.reduce { acc, i -> acc + i }
|
||||
summaries.map { it.notificationCount }.sumBy { i -> i }
|
||||
}
|
||||
val showHighlighted = summaries.any { it.highlightCount > 0 }
|
||||
roomCategoryItem {
|
||||
|
|
|
@ -16,10 +16,8 @@
|
|||
|
||||
package im.vector.riotredesign.features.navigation
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||
import im.vector.riotredesign.features.debug.DebugMenuActivity
|
||||
import im.vector.riotredesign.features.home.room.detail.RoomDetailActivity
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.os.Bundle
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
|
@ -29,9 +30,7 @@ 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 im.vector.riotredesign.features.themes.ThemeUtils
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import kotlinx.android.synthetic.main.fragment_public_rooms.*
|
||||
|
@ -49,6 +48,7 @@ import java.util.concurrent.TimeUnit
|
|||
class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback {
|
||||
|
||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
|
||||
private val publicRoomsController: PublicRoomsController by inject()
|
||||
private val errorFormatter: ErrorFormatter by inject()
|
||||
|
||||
|
@ -76,9 +76,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
|||
.disposeOnDestroy()
|
||||
|
||||
publicRoomsCreateNewRoom.setOnClickListener {
|
||||
// TODO homeActivityViewModel.createRoom()
|
||||
|
||||
vectorBaseActivity.notImplemented()
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.CreateRoom)
|
||||
}
|
||||
|
||||
viewModel.joinRoomErrorLiveData.observe(this, Observer {
|
||||
|
@ -92,7 +90,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_room_directory_change_protocol -> {
|
||||
vectorBaseActivity.addFragmentToBackstack(RoomDirectoryPickerFragment(), R.id.simpleFragmentContainer)
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.ChangeProtocol)
|
||||
true
|
||||
}
|
||||
else ->
|
||||
|
@ -104,6 +102,8 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
|
||||
navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java)
|
||||
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,14 +17,29 @@
|
|||
package im.vector.riotredesign.features.roomdirectory
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.addFragment
|
||||
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotredesign.core.extensions.observeEvent
|
||||
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||
import im.vector.riotredesign.features.roomdirectory.createroom.CreateRoomFragment
|
||||
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment
|
||||
import org.koin.android.scope.ext.android.bindScope
|
||||
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||
|
||||
class RoomDirectoryActivity : VectorBaseActivity() {
|
||||
|
||||
// Supported navigation actions for this Activity
|
||||
sealed class Navigation {
|
||||
object Back : Navigation()
|
||||
object CreateRoom : Navigation()
|
||||
object Close : Navigation()
|
||||
object ChangeProtocol : Navigation()
|
||||
}
|
||||
|
||||
|
||||
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_simple
|
||||
|
||||
|
@ -32,6 +47,17 @@ class RoomDirectoryActivity : VectorBaseActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
|
||||
navigationViewModel = ViewModelProviders.of(this).get(RoomDirectoryNavigationViewModel::class.java)
|
||||
|
||||
navigationViewModel.navigateTo.observeEvent(this) { navigation ->
|
||||
when (navigation) {
|
||||
is Navigation.Back -> onBackPressed()
|
||||
is Navigation.CreateRoom -> addFragmentToBackstack(CreateRoomFragment(), R.id.simpleFragmentContainer)
|
||||
is Navigation.ChangeProtocol -> addFragmentToBackstack(RoomDirectoryPickerFragment(), R.id.simpleFragmentContainer)
|
||||
is Navigation.Close -> finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initUiAndData() {
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
package im.vector.riotredesign.features.roomdirectory
|
||||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotredesign.features.roomdirectory.createroom.CreateRoomController
|
||||
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 {
|
||||
|
@ -41,5 +41,14 @@ class RoomDirectoryModule {
|
|||
scope(ROOM_DIRECTORY_SCOPE) {
|
||||
PublicRoomsController(get(), get())
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
* Create room
|
||||
* ========================================================================================== */
|
||||
|
||||
scope(ROOM_DIRECTORY_SCOPE) {
|
||||
CreateRoomController(get(), get())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.riotredesign.core.mvrx.NavigationViewModel
|
||||
|
||||
class RoomDirectoryNavigationViewModel : NavigationViewModel<RoomDirectoryActivity.Navigation>()
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.createroom
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
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
|
||||
import im.vector.riotredesign.features.form.formEditTextItem
|
||||
import im.vector.riotredesign.features.form.formSwitchItem
|
||||
|
||||
class CreateRoomController(private val stringProvider: StringProvider,
|
||||
private val errorFormatter: ErrorFormatter
|
||||
) : TypedEpoxyController<CreateRoomViewState>() {
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
var index = 0
|
||||
|
||||
override fun buildModels(viewState: CreateRoomViewState) {
|
||||
val asyncCreateRoom = viewState.asyncCreateRoomRequest
|
||||
|
||||
when (asyncCreateRoom) {
|
||||
is Success -> {
|
||||
// Nothing to display, the screen will be closed
|
||||
}
|
||||
is Loading -> {
|
||||
// display the form
|
||||
buildForm(viewState, false)
|
||||
loadingItem {
|
||||
id("loading")
|
||||
}
|
||||
}
|
||||
is Uninitialized -> {
|
||||
// display the form
|
||||
buildForm(viewState, true)
|
||||
}
|
||||
is Fail -> {
|
||||
// display the form
|
||||
buildForm(viewState, true)
|
||||
errorWithRetryItem {
|
||||
id("error")
|
||||
text(errorFormatter.toHumanReadable(asyncCreateRoom.error))
|
||||
listener { listener?.retry() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildForm(viewState: CreateRoomViewState, enableFormElement: Boolean) {
|
||||
formEditTextItem {
|
||||
id("name")
|
||||
enabled(enableFormElement)
|
||||
value(viewState.roomName)
|
||||
hint(stringProvider.getString(R.string.create_room_name_hint))
|
||||
|
||||
onTextChange { text ->
|
||||
listener?.onNameChange(text)
|
||||
}
|
||||
}
|
||||
formSwitchItem {
|
||||
id("public")
|
||||
enabled(enableFormElement)
|
||||
title(stringProvider.getString(R.string.create_room_public_title))
|
||||
summary(stringProvider.getString(R.string.create_room_public_description))
|
||||
switchChecked(viewState.isPublic)
|
||||
|
||||
listener { value ->
|
||||
listener?.setIsPublic(value)
|
||||
}
|
||||
}
|
||||
formSwitchItem {
|
||||
id("directory")
|
||||
enabled(enableFormElement)
|
||||
title(stringProvider.getString(R.string.create_room_directory_title))
|
||||
summary(stringProvider.getString(R.string.create_room_directory_description))
|
||||
switchChecked(viewState.isInRoomDirectory)
|
||||
|
||||
listener { value ->
|
||||
listener?.setIsInRoomDirectory(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun onNameChange(newName: String)
|
||||
fun setIsPublic(isPublic: Boolean)
|
||||
fun setIsInRoomDirectory(isInRoomDirectory: Boolean)
|
||||
fun retry()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.createroom
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryNavigationViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_create_room.*
|
||||
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
|
||||
|
||||
class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
|
||||
|
||||
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
|
||||
private val viewModel: CreateRoomViewModel by fragmentViewModel()
|
||||
private val createRoomController: CreateRoomController by inject()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_create_room
|
||||
|
||||
override fun getMenuRes() = R.menu.vector_room_creation
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
|
||||
vectorBaseActivity.setSupportActionBar(createRoomToolbar)
|
||||
|
||||
navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java)
|
||||
|
||||
setupRecyclerView()
|
||||
|
||||
createRoomClose.setOnClickListener {
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_create_room -> {
|
||||
viewModel.doCreateRoom()
|
||||
true
|
||||
}
|
||||
else ->
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
|
||||
createRoomForm.layoutManager = layoutManager
|
||||
createRoomController.listener = this
|
||||
|
||||
createRoomForm.setController(createRoomController)
|
||||
}
|
||||
|
||||
override fun onNameChange(newName: String) {
|
||||
viewModel.setName(newName)
|
||||
}
|
||||
|
||||
override fun setIsPublic(isPublic: Boolean) {
|
||||
viewModel.setIsPublic(isPublic)
|
||||
}
|
||||
|
||||
override fun setIsInRoomDirectory(isInRoomDirectory: Boolean) {
|
||||
viewModel.setIsInRoomDirectory(isInRoomDirectory)
|
||||
}
|
||||
|
||||
override fun retry() {
|
||||
Timber.v("Retry")
|
||||
viewModel.doCreateRoom()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
val async = state.asyncCreateRoomRequest
|
||||
if (async is Success) {
|
||||
// Navigate to freshly created room
|
||||
navigator.openRoom(async(), requireActivity())
|
||||
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Close)
|
||||
} else {
|
||||
// Populate list with Epoxy
|
||||
createRoomController.setData(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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.riotredesign.features.roomdirectory.createroom
|
||||
|
||||
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.RoomDirectoryVisibility
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomPreset
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class CreateRoomViewModel(initialState: CreateRoomViewState,
|
||||
private val session: Session) : VectorViewModel<CreateRoomViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<CreateRoomViewModel, CreateRoomViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: CreateRoomViewState): CreateRoomViewModel? {
|
||||
val currentSession = viewModelContext.activity.get<Session>()
|
||||
|
||||
return CreateRoomViewModel(state, currentSession)
|
||||
}
|
||||
}
|
||||
|
||||
fun setName(newName: String) = setState { copy(roomName = newName) }
|
||||
|
||||
fun setIsPublic(isPublic: Boolean) = setState { copy(isPublic = isPublic) }
|
||||
|
||||
fun setIsInRoomDirectory(isInRoomDirectory: Boolean) = setState { copy(isInRoomDirectory = isInRoomDirectory) }
|
||||
|
||||
fun doCreateRoom() = withState { state ->
|
||||
if (state.asyncCreateRoomRequest is Loading || state.asyncCreateRoomRequest is Success) {
|
||||
return@withState
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(asyncCreateRoomRequest = Loading())
|
||||
}
|
||||
|
||||
val createRoomParams = CreateRoomParams().apply {
|
||||
name = state.roomName.takeIf { it.isNotBlank() }
|
||||
|
||||
// Directory visibility
|
||||
visibility = if (state.isInRoomDirectory) RoomDirectoryVisibility.PUBLIC else RoomDirectoryVisibility.PRIVATE
|
||||
|
||||
// Public room
|
||||
preset = if (state.isPublic) CreateRoomPreset.PRESET_PUBLIC_CHAT else CreateRoomPreset.PRESET_PRIVATE_CHAT
|
||||
}
|
||||
|
||||
session.createRoom(createRoomParams, object : MatrixCallback<String> {
|
||||
override fun onSuccess(data: String) {
|
||||
setState {
|
||||
copy(asyncCreateRoomRequest = Success(data))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
setState {
|
||||
copy(asyncCreateRoomRequest = Fail(failure))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.createroom
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
|
||||
data class CreateRoomViewState(
|
||||
val roomName: String = "",
|
||||
val isPublic: Boolean = false,
|
||||
val isInRoomDirectory: Boolean = false,
|
||||
val asyncCreateRoomRequest: Async<String> = Uninitialized
|
||||
) : MvRxState
|
|
@ -19,6 +19,7 @@ package im.vector.riotredesign.features.roomdirectory.picker
|
|||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -26,7 +27,9 @@ 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.RoomDirectoryActivity
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryNavigationViewModel
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_room_directory_picker.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
@ -39,6 +42,7 @@ import timber.log.Timber
|
|||
class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerController.Callback {
|
||||
|
||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
|
||||
private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel()
|
||||
private val roomDirectoryPickerController: RoomDirectoryPickerController by inject()
|
||||
|
||||
|
@ -71,6 +75,8 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
|
||||
navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java)
|
||||
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
||||
|
@ -88,8 +94,7 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
|
|||
Timber.v("onRoomDirectoryClicked: $roomDirectoryData")
|
||||
viewModel.setRoomDirectoryData(roomDirectoryData)
|
||||
|
||||
// TODO Not the best way to manage Fragment Backstack...
|
||||
vectorBaseActivity.onBackPressed()
|
||||
navigationViewModel.goTo(RoomDirectoryActivity.Navigation.Back)
|
||||
}
|
||||
|
||||
override fun retry() {
|
||||
|
|
14
vector/src/main/res/drawable/ic_x_18dp.xml
Normal file
14
vector/src/main/res/drawable/ic_x_18dp.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M16,2L2,16M2,2l14,14"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2.333"
|
||||
android:fillColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#03B381"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
71
vector/src/main/res/layout/fragment_create_room.xml
Normal file
71
vector/src/main/res/layout/fragment_create_room.xml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<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">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/createRoomToolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:elevation="4dp"
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/createRoomClose"
|
||||
android:layout_width="@dimen/layout_touch_size"
|
||||
android:layout_height="@dimen/layout_touch_size"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_x_18dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/createRoomTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/create_room_title"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/createRoomClose"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/createRoomForm"
|
||||
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/createRoomToolbar"
|
||||
tools:listitem="@layout/item_form_switch" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -5,22 +5,33 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/publicRoomsCoordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?riotx_header_panel_background">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/publicRoomsList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="?riotx_header_panel_background"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:listitem="@layout/item_public_room" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
style="@style/VectorAppBarLayoutStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/publicRoomsToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:elevation="4dp"
|
||||
android:minHeight="0dp"
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap|enterAlways">
|
||||
|
||||
<!-- Note: Background is modified in the code for other themes -->
|
||||
<EditText
|
||||
|
@ -52,6 +63,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:minHeight="@dimen/layout_touch_size"
|
||||
android:text="@string/create_new_room"
|
||||
|
@ -61,16 +73,6 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/publicRoomsToolbar" />
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/publicRoomsList"
|
||||
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/publicRoomsCreateNewRoom"
|
||||
tools:listitem="@layout/item_public_room" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -5,6 +5,7 @@
|
|||
android:id="@+id/progressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
|
|
62
vector/src/main/res/layout/item_form_switch.xml
Normal file
62
vector/src/main/res/layout/item_form_switch.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?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:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:minHeight="@dimen/item_form_min_height">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/formSwitchTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginRight="@dimen/layout_horizontal_margin"
|
||||
android:duplicateParentState="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/formSwitchSummary"
|
||||
app:layout_constraintEnd_toStartOf="@+id/formSwitchSwitch"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="@string/create_room_public_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/formSwitchSummary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/formSwitchDivider"
|
||||
app:layout_constraintStart_toStartOf="@+id/formSwitchTitle"
|
||||
app:layout_constraintTop_toBottomOf="@+id/formSwitchTitle"
|
||||
tools:text="@string/create_room_public_description" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/formSwitchSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="19dp"
|
||||
android:layout_marginRight="19dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/formSwitchDivider"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/formSwitchDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="?riotx_header_panel_border_mobile"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
39
vector/src/main/res/layout/item_form_text_input.xml
Normal file
39
vector/src/main/res/layout/item_form_text_input.xml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?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:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:minHeight="@dimen/item_form_min_height">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/formTextInputTextInputLayout"
|
||||
style="@style/VectorTextInputLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
app:layout_constraintBottom_toTopOf="@+id/formTextInputDivider"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/formTextInputTextInputEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:hint="@string/create_room_name_hint" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/formTextInputDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="?riotx_header_panel_border_mobile"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -3,6 +3,7 @@
|
|||
android:id="@+id/itemNoResultText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:gravity="center"
|
||||
android:padding="16dp"
|
||||
android:text="@string/no_result_placeholder" />
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
android:background="?riotx_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:minHeight="97dp">
|
||||
|
||||
<ImageView
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomAvatarImageView"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
android:paddingLeft="@dimen/layout_horizontal_margin"
|
||||
android:paddingTop="@dimen/layout_vertical_margin"
|
||||
android:paddingEnd="@dimen/layout_horizontal_margin"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:paddingRight="@dimen/layout_horizontal_margin"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
android:id="@+id/itemRoomDirectoryLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
<menu 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"
|
||||
tools:context="org.matrix.vector.activity.VectorRoomCreationActivity">
|
||||
tools:context=".features.roomdirectory.RoomDirectoryActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_create_room"
|
||||
android:icon="@drawable/ic_material_done_white"
|
||||
android:orderInCategory="0"
|
||||
android:title="@string/room_participants_create"
|
||||
android:title="@string/create_room_action_create"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Status" parent="AppTheme.Base.Status">
|
||||
<style name="AppTheme.Status.v21" parent="AppTheme.Base.Status">
|
||||
<item name="android:statusBarColor">@color/riotx_header_panel_background_light</item>
|
||||
<item name="android:navigationBarColor">@color/riotx_header_panel_background_light</item>
|
||||
|
||||
<!-- enable window content transitions -->
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Status" parent="AppTheme.Status.v21" />
|
||||
|
||||
</resources>
|
||||
|
|
10
vector/src/main/res/values-v23/theme_status.xml
Normal file
10
vector/src/main/res/values-v23/theme_status.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Status.v23" parent="AppTheme.Status.v21">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Status" parent="AppTheme.Status.v23"/>
|
||||
|
||||
</resources>
|
10
vector/src/main/res/values-v27/theme_status.xml
Normal file
10
vector/src/main/res/values-v27/theme_status.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme.Status.v27" parent="AppTheme.Status.v23">
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Status" parent="AppTheme.Status.v27" />
|
||||
|
||||
</resources>
|
|
@ -27,4 +27,7 @@
|
|||
<dimen name="pill_min_height">20dp</dimen>
|
||||
<dimen name="pill_text_padding">4dp</dimen>
|
||||
|
||||
|
||||
<dimen name="item_form_min_height">76dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -42,4 +42,13 @@
|
|||
<string name="fab_menu_create_room">"Rooms"</string>
|
||||
<string name="fab_menu_create_chat">"Direct Messages"</string>
|
||||
|
||||
<!-- Create room screen -->
|
||||
<string name="create_room_title">"New Room"</string>
|
||||
<string name="create_room_action_create">"CREATE"</string>
|
||||
<string name="create_room_name_hint">"Room name"</string>
|
||||
<string name="create_room_public_title">"Public"</string>
|
||||
<string name="create_room_public_description">"Anyone will be able to join this room"</string>
|
||||
<string name="create_room_directory_title">"Room Directory"</string>
|
||||
<string name="create_room_directory_description">"Publish this room in the room directory"</string>
|
||||
|
||||
</resources>
|
Loading…
Reference in a new issue