From 128dea2677f4b1859003d35c3e0cad3819f98b31 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 May 2019 22:27:26 +0200 Subject: [PATCH] Scope and error manager --- .../vector/riotredesign/VectorApplication.kt | 4 +- .../vector/riotredesign/core/di/AppModule.kt | 5 ++ .../riotredesign/core/error/ErrorFormatter.kt | 39 +++++++++++ .../riotredesign/core/platform/StateView.kt | 1 - .../roomdirectory/PublicRoomsController.kt | 6 +- .../roomdirectory/PublicRoomsFragment.kt | 12 ++-- .../roomdirectory/RoomDirectoryActivity.kt | 9 +++ .../roomdirectory/RoomDirectoryModule.kt | 45 ++++++++++++ .../picker/RoomDirectoryListCreator.kt | 70 +++++++++++++++++++ .../picker/RoomDirectoryPickerController.kt | 57 ++------------- .../picker/RoomDirectoryPickerFragment.kt | 14 ++-- vector/src/main/res/values/strings_riotX.xml | 2 + 12 files changed, 198 insertions(+), 66 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotredesign/core/error/ErrorFormatter.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryModule.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryListCreator.kt diff --git a/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt b/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt index 766a19f7ad..d2ae5d4a93 100644 --- a/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt @@ -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) } diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt index 10703f88b2..6aff3e5a21 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt @@ -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) } diff --git a/vector/src/main/java/im/vector/riotredesign/core/error/ErrorFormatter.kt b/vector/src/main/java/im/vector/riotredesign/core/error/ErrorFormatter.kt new file mode 100644 index 0000000000..af676c10fd --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/error/ErrorFormatter.kt @@ -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 + } + + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/StateView.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/StateView.kt index 6c4bc8cd94..e75fb26cb6 100755 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/StateView.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/StateView.kt @@ -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() diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt index 738e4e88ca..50baf6d692 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt @@ -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() { +class PublicRoomsController(private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter) : TypedEpoxyController() { 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() } } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt index 5ca1ee5643..2e61425ac8 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsFragment.kt @@ -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() } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt index 96f3c0bf22..c0ac91ee02 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryActivity.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryModule.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryModule.kt new file mode 100644 index 0000000000..6dcdb93277 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryModule.kt @@ -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().sessionParams.credentials) + } + + scope(ROOM_DIRECTORY_SCOPE) { + PublicRoomsController(get(), get()) + } + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryListCreator.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryListCreator.kt new file mode 100644 index 0000000000..49fed53ec2 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryListCreator.kt @@ -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): List { + val result = ArrayList() + + // 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 + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt index dba68ffc84..36952b6b2b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerController.kt @@ -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() { 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): List { - val result = ArrayList() - - // 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++) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt index f27dad0bdc..6ac801063c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -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().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() } diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index 2ab5467b0f..09071efd23 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -20,4 +20,6 @@ Create New Room + No network. Please check your Internet connection. + \ No newline at end of file