mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 09:25:49 +03:00
Scope and error manager
This commit is contained in:
parent
cd5e808bb6
commit
128dea2677
12 changed files with 198 additions and 66 deletions
|
@ -30,6 +30,7 @@ import im.vector.riotredesign.core.di.AppModule
|
|||
import im.vector.riotredesign.features.home.HomeModule
|
||||
import im.vector.riotredesign.features.rageshake.VectorFileLogger
|
||||
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||
import org.koin.log.EmptyLogger
|
||||
import org.koin.standalone.StandAloneContext.startKoin
|
||||
import timber.log.Timber
|
||||
|
@ -56,7 +57,8 @@ class VectorApplication : Application() {
|
|||
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||
val appModule = AppModule(applicationContext).definition
|
||||
val homeModule = HomeModule().definition
|
||||
startKoin(listOf(appModule, homeModule), logger = EmptyLogger())
|
||||
val roomDirectoryModule = RoomDirectoryModule().definition
|
||||
startKoin(listOf(appModule, homeModule, roomDirectoryModule), logger = EmptyLogger())
|
||||
|
||||
Matrix.getInstance().setApplicationFlavor(BuildConfig.FLAVOR_DESCRIPTION)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.riotredesign.core.di
|
|||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||
import im.vector.riotredesign.core.resources.LocaleProvider
|
||||
import im.vector.riotredesign.core.resources.StringArrayProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
|
@ -65,6 +66,10 @@ class AppModule(private val context: Context) {
|
|||
RoomSummaryComparator()
|
||||
}
|
||||
|
||||
single {
|
||||
ErrorFormatter(get())
|
||||
}
|
||||
|
||||
single {
|
||||
NotificationDrawerManager(context)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.core.error
|
||||
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
|
||||
class ErrorFormatter(val stringProvider: StringProvider) {
|
||||
|
||||
|
||||
fun toHumanReadable(failure: Failure): String {
|
||||
// Default
|
||||
return failure.localizedMessage
|
||||
}
|
||||
|
||||
fun toHumanReadable(throwable: Throwable): String {
|
||||
|
||||
return when (throwable) {
|
||||
is Failure.NetworkConnection -> stringProvider.getString(R.string.error_no_network)
|
||||
else -> throwable.localizedMessage
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ import kotlinx.android.synthetic.main.view_state.view.*
|
|||
class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: FrameLayout(context, attrs, defStyle) {
|
||||
|
||||
// TODO Use Async from MvRx?
|
||||
sealed class State {
|
||||
object Content : State()
|
||||
object Loading : State()
|
||||
|
|
|
@ -26,9 +26,11 @@ import im.vector.riotredesign.R
|
|||
import im.vector.riotredesign.core.epoxy.errorWithRetryItem
|
||||
import im.vector.riotredesign.core.epoxy.loadingItem
|
||||
import im.vector.riotredesign.core.epoxy.noResultItem
|
||||
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
|
||||
class PublicRoomsController(private val stringProvider: StringProvider) : TypedEpoxyController<PublicRoomsViewState>() {
|
||||
class PublicRoomsController(private val stringProvider: StringProvider,
|
||||
private val errorFormatter: ErrorFormatter) : TypedEpoxyController<PublicRoomsViewState>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
|
@ -68,7 +70,7 @@ class PublicRoomsController(private val stringProvider: StringProvider) : TypedE
|
|||
if (viewState.asyncPublicRoomsRequest is Fail) {
|
||||
errorWithRetryItem {
|
||||
id("error")
|
||||
text(viewState.asyncPublicRoomsRequest.error.localizedMessage)
|
||||
text(errorFormatter.toHumanReadable(viewState.asyncPublicRoomsRequest.error))
|
||||
listener { callback?.loadMore() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,12 +27,15 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import com.jakewharton.rxbinding2.widget.RxTextView
|
||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import kotlinx.android.synthetic.main.fragment_public_rooms.*
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.android.scope.ext.android.bindScope
|
||||
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
@ -52,8 +55,8 @@ import java.util.concurrent.TimeUnit
|
|||
class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback {
|
||||
|
||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||
|
||||
private val publicRoomsController = PublicRoomsController(get())
|
||||
private val publicRoomsController: PublicRoomsController by inject()
|
||||
private val errorFormatter: ErrorFormatter by inject()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_public_rooms
|
||||
|
||||
|
@ -84,7 +87,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
|||
|
||||
viewModel.joinRoomErrorLiveData.observe(this, Observer {
|
||||
it.getContentIfNotHandled()?.let { throwable ->
|
||||
Snackbar.make(publicRoomsCoordinator, throwable.localizedMessage, Snackbar.LENGTH_SHORT)
|
||||
Snackbar.make(publicRoomsCoordinator, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
})
|
||||
|
@ -92,6 +95,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
|
|
@ -16,15 +16,24 @@
|
|||
|
||||
package im.vector.riotredesign.features.roomdirectory
|
||||
|
||||
import android.os.Bundle
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.addFragment
|
||||
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||
import org.koin.android.scope.ext.android.bindScope
|
||||
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||
|
||||
class RoomDirectoryActivity : VectorBaseActivity() {
|
||||
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_simple
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
}
|
||||
|
||||
override fun initUiAndData() {
|
||||
if (isFirstCreation()) {
|
||||
addFragment(PublicRoomsFragment(), R.id.simpleFragmentContainer)
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.roomdirectory
|
||||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryListCreator
|
||||
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerController
|
||||
import org.koin.dsl.module.module
|
||||
|
||||
// TODO Ganfra: When do we create a new module?
|
||||
class RoomDirectoryModule {
|
||||
|
||||
companion object {
|
||||
const val ROOM_DIRECTORY_SCOPE = "ROOM_DIRECTORY_SCOPE"
|
||||
}
|
||||
|
||||
val definition = module(override = true) {
|
||||
|
||||
scope(ROOM_DIRECTORY_SCOPE) {
|
||||
RoomDirectoryPickerController(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(ROOM_DIRECTORY_SCOPE) {
|
||||
RoomDirectoryListCreator(get(), get<Session>().sessionParams.credentials)
|
||||
}
|
||||
|
||||
scope(ROOM_DIRECTORY_SCOPE) {
|
||||
PublicRoomsController(get(), get())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.roomdirectory.picker
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
|
||||
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.resources.StringArrayProvider
|
||||
|
||||
class RoomDirectoryListCreator(private val stringArrayProvider: StringArrayProvider,
|
||||
private val credentials: Credentials) {
|
||||
|
||||
fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>): List<RoomDirectoryData> {
|
||||
val result = ArrayList<RoomDirectoryData>()
|
||||
|
||||
// Add user homeserver name
|
||||
val userHsName = credentials.userId.substring(credentials.userId.indexOf(":") + 1)
|
||||
|
||||
result.add(RoomDirectoryData(
|
||||
displayName = userHsName,
|
||||
includeAllNetworks = true
|
||||
))
|
||||
|
||||
// Add user's HS but for Matrix public rooms only
|
||||
result.add(RoomDirectoryData())
|
||||
|
||||
// Add custom directory servers
|
||||
val hsNamesList = stringArrayProvider.getStringArray(R.array.room_directory_servers)
|
||||
hsNamesList.forEach {
|
||||
if (it != userHsName) {
|
||||
// Use the server name as a default display name
|
||||
result.add(RoomDirectoryData(
|
||||
displayName = it,
|
||||
includeAllNetworks = true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// Add result of the request
|
||||
thirdPartyProtocolData.forEach {
|
||||
it.value.instances?.forEach { thirdPartyProtocolInstance ->
|
||||
result.add(RoomDirectoryData(
|
||||
homeServer = null,
|
||||
displayName = thirdPartyProtocolInstance.desc ?: "",
|
||||
thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId,
|
||||
includeAllNetworks = false,
|
||||
// Default to protocol icon
|
||||
avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -20,18 +20,16 @@ import com.airbnb.epoxy.TypedEpoxyController
|
|||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Success
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
|
||||
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.errorWithRetryItem
|
||||
import im.vector.riotredesign.core.epoxy.loadingItem
|
||||
import im.vector.riotredesign.core.resources.StringArrayProvider
|
||||
import im.vector.riotredesign.core.error.ErrorFormatter
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
|
||||
class RoomDirectoryPickerController(private val stringProvider: StringProvider,
|
||||
private val stringArrayProvider: StringArrayProvider,
|
||||
private val credentials: Credentials
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
private val roomDirectoryListCreator: RoomDirectoryListCreator
|
||||
) : TypedEpoxyController<RoomDirectoryPickerViewState>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
@ -43,7 +41,7 @@ class RoomDirectoryPickerController(private val stringProvider: StringProvider,
|
|||
|
||||
when (asyncThirdPartyProtocol) {
|
||||
is Success -> {
|
||||
val directories = computeDirectories(asyncThirdPartyProtocol.invoke())
|
||||
val directories = roomDirectoryListCreator.computeDirectories(asyncThirdPartyProtocol.invoke())
|
||||
|
||||
directories.forEach {
|
||||
buildDirectory(it)
|
||||
|
@ -57,59 +55,14 @@ class RoomDirectoryPickerController(private val stringProvider: StringProvider,
|
|||
is Fail -> {
|
||||
errorWithRetryItem {
|
||||
id("error")
|
||||
text(asyncThirdPartyProtocol.error.localizedMessage)
|
||||
text(errorFormatter.toHumanReadable(asyncThirdPartyProtocol.error))
|
||||
listener { callback?.retry() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeDirectories(thirdPartyProtocolData: Map<String, ThirdPartyProtocol>): List<RoomDirectoryData> {
|
||||
val result = ArrayList<RoomDirectoryData>()
|
||||
|
||||
// Add user homeserver name
|
||||
val userHsName = credentials.userId.substring(credentials.userId.indexOf(":") + 1)
|
||||
|
||||
result.add(RoomDirectoryData(
|
||||
displayName = userHsName,
|
||||
includeAllNetworks = true
|
||||
))
|
||||
|
||||
// Add user's HS but for Matrix public rooms only
|
||||
result.add(RoomDirectoryData())
|
||||
|
||||
// Add custom directory servers
|
||||
val hsNamesList = stringArrayProvider.getStringArray(R.array.room_directory_servers)
|
||||
hsNamesList.forEach {
|
||||
if (it != userHsName) {
|
||||
// Use the server name as a default display name
|
||||
result.add(RoomDirectoryData(
|
||||
displayName = it,
|
||||
includeAllNetworks = true
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// Add result of the request
|
||||
thirdPartyProtocolData.forEach {
|
||||
it.value.instances?.forEach { thirdPartyProtocolInstance ->
|
||||
result.add(RoomDirectoryData(
|
||||
homeServer = null,
|
||||
displayName = thirdPartyProtocolInstance.desc ?: "",
|
||||
thirdPartyInstanceId = thirdPartyProtocolInstance.instanceId,
|
||||
includeAllNetworks = false,
|
||||
// Default to protocol icon
|
||||
avatarUrl = thirdPartyProtocolInstance.icon ?: it.value.icon
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun buildDirectory(roomDirectoryData: RoomDirectoryData) {
|
||||
|
||||
// TODO
|
||||
roomDirectoryItem {
|
||||
id(index++)
|
||||
|
||||
|
|
|
@ -23,24 +23,25 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
|
||||
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_public_rooms.toolbar
|
||||
import kotlinx.android.synthetic.main.fragment_room_directory_picker.*
|
||||
import org.koin.android.ext.android.get
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.android.scope.ext.android.bindScope
|
||||
import org.koin.android.scope.ext.android.getOrCreateScope
|
||||
import timber.log.Timber
|
||||
|
||||
// TODO Set title to R.string.select_room_directory
|
||||
// TODO Menu to add custom room directory (not done in RiotWeb so far...)
|
||||
class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerController.Callback {
|
||||
|
||||
private val viewModel: RoomDirectoryViewModel by activityViewModel()
|
||||
|
||||
private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel()
|
||||
|
||||
private val roomDirectoryPickerController = RoomDirectoryPickerController(get(), get(), get<Session>().sessionParams.credentials)
|
||||
private val roomDirectoryPickerController: RoomDirectoryPickerController by inject()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_room_directory_picker
|
||||
|
||||
|
@ -69,6 +70,7 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE))
|
||||
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
@ -87,7 +89,7 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
|
|||
Timber.v("onRoomDirectoryClicked: $roomDirectoryData")
|
||||
viewModel.setRoomDirectoryData(roomDirectoryData)
|
||||
|
||||
// TODO Not the bast way to manage Fragment Backstack...
|
||||
// TODO Not the best way to manage Fragment Backstack...
|
||||
vectorBaseActivity.onBackPressed()
|
||||
}
|
||||
|
||||
|
|
|
@ -20,4 +20,6 @@
|
|||
|
||||
<string name="create_new_room">Create New Room</string>
|
||||
|
||||
<string name="error_no_network">No network. Please check your Internet connection.</string>
|
||||
|
||||
</resources>
|
Loading…
Reference in a new issue