From 9c1f8706946b11bb6c02651a810d2d670281e599 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 18 Jun 2019 20:00:20 +0200 Subject: [PATCH] Dagger: start handling app dependencies [WIP] --- .../session/room/membership/RoomMembers.kt | 2 +- vector/build.gradle | 7 +- .../riotredesign/EmojiCompatFontProvider.kt | 4 +- .../vector/riotredesign/VectorApplication.kt | 52 ++-- .../vector/riotredesign/core/di/AppModule.kt | 107 ------- .../riotredesign/core/di/HasInjector.kt | 23 ++ .../riotredesign/core/di/ScreenComponent.kt | 55 ++++ .../di/ScreenModule.kt} | 26 +- .../riotredesign/core/di/ScreenScope.java | 29 ++ .../core/di/VectorAssistedModule.kt | 25 ++ .../riotredesign/core/di/VectorComponent.kt | 65 +++++ .../riotredesign/core/di/VectorModule.kt | 67 +++++ .../core/di/VectorViewModelFactory.kt | 50 ++++ .../riotredesign/core/di/ViewModelKey.kt | 26 ++ .../riotredesign/core/di/ViewModelModule.kt | 150 ++++++++++ .../riotredesign/core/error/ErrorFormatter.kt | 3 +- .../riotredesign/core/extensions/Activity.kt | 2 +- .../riotredesign/core/extensions/Fragment.kt | 2 +- .../core/platform/ConfigurationViewModel.kt | 10 +- .../core/platform/SimpleFragmentActivity.kt | 11 +- .../core/platform/VectorBaseActivity.kt | 33 ++- .../core/platform/VectorBaseFragment.kt | 22 +- .../core/resources/ColorProvider.kt | 5 +- .../core/resources/LocaleProvider.kt | 3 +- .../core/resources/StringArrayProvider.kt | 3 +- .../core/resources/StringProvider.kt | 3 +- .../core/services/EventStreamServiceX.kt | 23 +- .../command/AutocompleteCommandController.kt | 3 +- .../command/AutocompleteCommandPresenter.kt | 5 +- .../command/CommandAutocompletePolicy.kt | 5 +- .../user/AutocompleteUserController.kt | 3 +- .../user/AutocompleteUserPresenter.kt | 5 +- .../configuration/VectorConfiguration.kt | 14 +- .../restore/KeysBackupRestoreActivity.kt | 4 +- .../KeysBackupRestoreFromKeyFragment.kt | 5 +- .../KeysBackupRestoreFromKeyViewModel.kt | 4 +- ...KeysBackupRestoreFromPassphraseFragment.kt | 5 +- ...eysBackupRestoreFromPassphraseViewModel.kt | 4 +- .../KeysBackupRestoreSharedViewModel.kt | 7 +- .../KeysBackupRestoreSuccessFragment.kt | 3 +- .../settings/KeysBackupManageActivity.kt | 15 +- .../settings/KeysBackupSettingsFragment.kt | 14 +- ...eysBackupSettingsRecyclerViewController.kt | 12 +- .../settings/KeysBackupSettingsViewModel.kt | 44 +-- .../setup/KeysBackupSetupActivity.kt | 3 +- .../setup/KeysBackupSetupSharedViewModel.kt | 5 +- .../setup/KeysBackupSetupStep1Fragment.kt | 3 +- .../setup/KeysBackupSetupStep2Fragment.kt | 3 +- .../setup/KeysBackupSetupStep3Fragment.kt | 3 +- .../crypto/keysrequest/KeyRequestHandler.kt | 21 +- .../IncomingVerificationRequestHandler.kt | 24 +- .../verification/SASVerificationActivity.kt | 2 +- .../SASVerificationIncomingFragment.kt | 2 +- .../SASVerificationShortCodeFragment.kt | 2 +- .../SASVerificationStartFragment.kt | 12 +- .../SASVerificationVerifiedFragment.kt | 2 +- .../verification/SasVerificationViewModel.kt | 5 +- .../features/home/HomeActivity.kt | 15 +- .../features/home/HomeActivityViewModel.kt | 27 +- .../features/home/HomeDetailFragment.kt | 9 +- .../features/home/HomeDetailViewModel.kt | 40 +-- .../features/home/HomeDrawerFragment.kt | 4 +- .../riotredesign/features/home/HomeModule.kt | 93 +----- .../features/home/HomeNavigationViewModel.kt | 3 +- .../features/home/HomeNavigator.kt | 4 +- .../features/home/HomePermalinkHandler.kt | 13 +- .../home/HomeRoomListObservableStore.kt | 5 +- .../features/home/group/GroupListFragment.kt | 8 +- .../features/home/group/GroupListViewModel.kt | 24 +- .../home/group/GroupSummaryController.kt | 3 +- .../features/home/group/SelectedGroupStore.kt | 5 +- .../home/room/detail/RoomDetailFragment.kt | 55 ++-- .../home/room/detail/RoomDetailViewModel.kt | 21 +- .../detail/composer/TextComposerViewModel.kt | 21 +- .../timeline/TimelineEventController.kt | 31 +- .../TimelineEventControllerHandler.kt | 23 ++ .../detail/timeline/action/ActionsHandler.kt | 3 +- .../action/MessageActionsBottomSheet.kt | 2 + .../action/MessageActionsViewModel.kt | 128 +++++---- .../timeline/action/MessageMenuFragment.kt | 4 +- .../timeline/action/MessageMenuViewModel.kt | 270 ++++++++++-------- .../timeline/action/QuickReactionFragment.kt | 17 +- .../timeline/action/QuickReactionViewModel.kt | 152 +++++----- .../timeline/factory/DefaultItemFactory.kt | 3 +- .../timeline/factory/EncryptedItemFactory.kt | 3 +- .../timeline/factory/EncryptionItemFactory.kt | 5 +- .../timeline/factory/MessageItemFactory.kt | 113 +++++--- .../timeline/factory/NoticeItemFactory.kt | 3 +- .../timeline/factory/TimelineItemFactory.kt | 30 +- .../timeline/format/NoticeEventFormatter.kt | 16 +- .../timeline/helper/TimelineDateFormatter.kt | 4 +- .../helper/TimelineMediaSizeProvider.kt | 3 +- .../room/list/AlphabeticalRoomComparator.kt | 4 +- .../room/list/ChronologicalRoomComparator.kt | 3 +- .../home/room/list/RoomListFragment.kt | 11 +- .../home/room/list/RoomListViewModel.kt | 26 +- .../home/room/list/RoomSummaryController.kt | 7 +- .../features/html/EventHtmlRenderer.kt | 12 +- .../VectorActivityLifecycleCallbacks.kt | 3 +- .../features/navigation/DefaultNavigator.kt | 4 +- .../NotificationBroadcastReceiver.kt | 7 +- .../NotificationDrawerManager.kt | 6 +- .../reactions/EmojiChooserFragment.kt | 24 +- .../reactions/EmojiChooserViewModel.kt | 3 +- .../reactions/EmojiReactionPickerActivity.kt | 6 +- .../roomdirectory/PublicRoomsFragment.kt | 12 +- .../roomdirectory/RoomDirectoryActivity.kt | 10 +- .../RoomDirectoryNavigationViewModel.kt | 3 +- .../roomdirectory/RoomDirectoryViewModel.kt | 93 +++--- .../picker/RoomDirectoryListCreator.kt | 9 +- .../picker/RoomDirectoryPickerController.kt | 7 +- .../picker/RoomDirectoryPickerFragment.kt | 13 +- .../picker/RoomDirectoryPickerViewModel.kt | 19 +- .../roompreview/RoomPreviewActivity.kt | 10 - .../RoomPreviewNoPreviewFragment.kt | 11 +- .../roompreview/RoomPreviewViewModel.kt | 18 +- .../SignOutBottomSheetDialogFragment.kt | 21 +- .../workers/signout/SignOutViewModel.kt | 23 +- 118 files changed, 1562 insertions(+), 1010 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt rename vector/src/main/java/im/vector/riotredesign/{features/crypto/keysbackup/KeysBackupModule.kt => core/di/ScreenModule.kt} (51%) create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/ScreenScope.java create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/VectorAssistedModule.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/VectorViewModelFactory.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/ViewModelKey.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/core/di/ViewModelModule.kt create mode 100644 vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventControllerHandler.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt index ff8b8ce4..dd395909 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt @@ -54,7 +54,7 @@ internal class RoomMembers(private val realm: Realm, } return EventEntity .where(realm, roomId, EventType.STATE_ROOM_MEMBER) - .contains(EventEntityFields.CONTENT, displayName) + .equalTo(EventEntityFields.CONTENT, displayName) .distinct(EventEntityFields.STATE_KEY) .findAll() .size == 1 diff --git a/vector/build.gradle b/vector/build.gradle index 10953eb4..3754ceee 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -138,6 +138,7 @@ dependencies { def big_image_viewer_version = '1.5.6' def glide_version = '4.9.0' def moshi_version = '1.8.0' + def daggerVersion = '2.23.1' implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android-rx") @@ -219,8 +220,10 @@ dependencies { implementation 'com.github.jaiselrahman:FilePicker:1.2.2' // DI - implementation "org.koin:koin-android:$koin_version" - implementation "org.koin:koin-android-scope:$koin_version" + implementation "com.google.dagger:dagger:$daggerVersion" + kapt "com.google.dagger:dagger-compiler:$daggerVersion" + compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0' + kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0' // gplay flavor only gplayImplementation 'com.google.firebase:firebase-core:16.0.8' diff --git a/vector/src/main/java/im/vector/riotredesign/EmojiCompatFontProvider.kt b/vector/src/main/java/im/vector/riotredesign/EmojiCompatFontProvider.kt index a928d48b..c7fc7a95 100644 --- a/vector/src/main/java/im/vector/riotredesign/EmojiCompatFontProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/EmojiCompatFontProvider.kt @@ -3,9 +3,9 @@ package im.vector.riotredesign import android.graphics.Typeface import androidx.core.provider.FontsContractCompat import timber.log.Timber +import javax.inject.Inject - -class EmojiCompatFontProvider : FontsContractCompat.FontRequestCallback() { +class EmojiCompatFontProvider @Inject constructor(): FontsContractCompat.FontRequestCallback() { var typeface: Typeface? = null set(value) { diff --git a/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt b/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt index 3e51cdec..ed57d347 100644 --- a/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt @@ -31,67 +31,56 @@ import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.loader.glide.GlideImageLoader import com.jakewharton.threetenabp.AndroidThreeTen import im.vector.matrix.android.api.Matrix -import im.vector.riotredesign.core.di.AppModule +import im.vector.riotredesign.core.di.HasInjector +import im.vector.riotredesign.core.di.VectorComponent import im.vector.riotredesign.features.configuration.VectorConfiguration -import im.vector.riotredesign.features.crypto.keysbackup.KeysBackupModule -import im.vector.riotredesign.features.home.HomeModule import im.vector.riotredesign.features.lifecycle.VectorActivityLifecycleCallbacks import im.vector.riotredesign.features.rageshake.VectorFileLogger import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler -import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule -import org.koin.android.ext.android.inject -import org.koin.log.EmptyLogger -import org.koin.standalone.StandAloneContext.startKoin import timber.log.Timber +import javax.inject.Inject -class VectorApplication : Application() { +class VectorApplication : Application(), HasInjector { lateinit var appContext: Context //font thread handler - private var mFontThreadHandler: Handler? = null - - val vectorConfiguration: VectorConfiguration by inject() + @Inject lateinit var vectorConfiguration: VectorConfiguration + @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider + lateinit var vectorComponent: VectorComponent + private var fontThreadHandler: Handler? = null override fun onCreate() { super.onCreate() appContext = this - VectorUncaughtExceptionHandler.activate(this) - // Log VectorFileLogger.init(this) Timber.plant(Timber.DebugTree(), VectorFileLogger) - if (BuildConfig.DEBUG) { Stetho.initializeWithDefaults(this) } - AndroidThreeTen.init(this) BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() - val appModule = AppModule(applicationContext).definition - val homeModule = HomeModule().definition - val roomDirectoryModule = RoomDirectoryModule().definition - val keysBackupModule = KeysBackupModule().definition - val koin = startKoin(listOf(appModule, homeModule, roomDirectoryModule, keysBackupModule), logger = EmptyLogger()) + Matrix.getInstance().setApplicationFlavor(BuildConfig.FLAVOR_DESCRIPTION) registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks()) - val fontRequest = FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Noto Color Emoji Compat", R.array.com_google_android_gms_fonts_certs ) - -// val efp = koin.koinContext.get() - FontsContractCompat.requestFont(this, fontRequest, koin.koinContext.get(), getFontThreadHandler()) - + FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) vectorConfiguration.initConfiguration() } + override fun injector(): VectorComponent { + return vectorComponent + } + override fun attachBaseContext(base: Context) { super.attachBaseContext(base) MultiDex.install(this) @@ -103,12 +92,15 @@ class VectorApplication : Application() { } private fun getFontThreadHandler(): Handler { - if (mFontThreadHandler == null) { - val handlerThread = HandlerThread("fonts") - handlerThread.start() - mFontThreadHandler = Handler(handlerThread.looper) + return fontThreadHandler ?: createFontThreadHandler().also { + fontThreadHandler = it } - return mFontThreadHandler!! + } + + private fun createFontThreadHandler(): Handler { + val handlerThread = HandlerThread("fonts") + handlerThread.start() + return Handler(handlerThread.looper) } } \ No newline at end of file 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 deleted file mode 100644 index 5b875fd1..00000000 --- a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.di - -import android.content.Context -import android.content.Context.MODE_PRIVATE -import im.vector.matrix.android.api.Matrix -import im.vector.riotredesign.EmojiCompatFontProvider -import im.vector.riotredesign.core.error.ErrorFormatter -import im.vector.riotredesign.core.resources.LocaleProvider -import im.vector.riotredesign.core.resources.StringArrayProvider -import im.vector.riotredesign.core.resources.StringProvider -import im.vector.riotredesign.features.configuration.VectorConfiguration -import im.vector.riotredesign.features.crypto.keysrequest.KeyRequestHandler -import im.vector.riotredesign.features.crypto.verification.IncomingVerificationRequestHandler -import im.vector.riotredesign.features.home.HomeRoomListObservableStore -import im.vector.riotredesign.features.home.group.SelectedGroupStore -import im.vector.riotredesign.features.home.room.list.AlphabeticalRoomComparator -import im.vector.riotredesign.features.home.room.list.ChronologicalRoomComparator -import im.vector.riotredesign.features.navigation.DefaultNavigator -import im.vector.riotredesign.features.navigation.Navigator -import im.vector.riotredesign.features.notifications.NotificationDrawerManager -import org.koin.dsl.module.module - -class AppModule(private val context: Context) { - - val definition = module { - - single { - VectorConfiguration(context) - } - - single { - LocaleProvider(context.resources) - } - - single { - StringProvider(context.resources) - } - - single { - StringArrayProvider(context.resources) - } - - single { - context.getSharedPreferences("im.vector.riot", MODE_PRIVATE) - } - - single { - SelectedGroupStore() - } - - single { - HomeRoomListObservableStore() - } - - single { - ChronologicalRoomComparator() - } - - single { - AlphabeticalRoomComparator() - } - - single { - ErrorFormatter(get()) - } - - single { - NotificationDrawerManager(context) - } - - factory { - Matrix.getInstance().currentSession!! - } - - single { - KeyRequestHandler(context, get()) - } - - single { - IncomingVerificationRequestHandler(context, get()) - } - - factory { - DefaultNavigator() as Navigator - } - - single { - EmojiCompatFontProvider() - } - } -} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt b/vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt new file mode 100644 index 00000000..ca2e27ab --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt @@ -0,0 +1,23 @@ +/* + * 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.di + +interface HasInjector { + + fun injector(): C + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt new file mode 100644 index 00000000..1f20979a --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt @@ -0,0 +1,55 @@ +/* + * 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.di + +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.ViewModelProvider +import dagger.BindsInstance +import dagger.Component +import im.vector.riotredesign.core.platform.SimpleFragmentActivity +import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupSettingsFragment +import im.vector.riotredesign.features.home.HomeActivity +import im.vector.riotredesign.features.home.HomeModule +import im.vector.riotredesign.features.home.room.detail.RoomDetailFragment +import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment +import im.vector.riotredesign.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment + +@Component(dependencies = [VectorComponent::class], modules = [ViewModelModule::class, HomeModule::class]) +@ScreenScope +interface ScreenComponent { + + fun viewModelFactory(): ViewModelProvider.Factory + + fun inject(activity: SimpleFragmentActivity) + + fun inject(activity: HomeActivity) + + fun inject(roomDetailFragment: RoomDetailFragment) + + fun inject(roomDirectoryPickerFragment: RoomDirectoryPickerFragment) + + fun inject(roomPreviewNoPreviewFragment: RoomPreviewNoPreviewFragment) + + fun inject(keysBackupSettingsFragment: KeysBackupSettingsFragment) + + @Component.Factory + interface Factory { + fun create(vectorComponent: VectorComponent, + @BindsInstance context: AppCompatActivity + ): ScreenComponent + } +} diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/KeysBackupModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenModule.kt similarity index 51% rename from vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/KeysBackupModule.kt rename to vector/src/main/java/im/vector/riotredesign/core/di/ScreenModule.kt index c9cebfc3..3ea64332 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/KeysBackupModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenModule.kt @@ -5,7 +5,7 @@ * 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 + * 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, @@ -14,22 +14,18 @@ * limitations under the License. */ -package im.vector.riotredesign.features.crypto.keysbackup +package im.vector.riotredesign.core.di -import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupSettingsRecyclerViewController -import org.koin.dsl.module.module +import androidx.appcompat.app.AppCompatActivity +import dagger.Module +import dagger.Provides +import im.vector.riotredesign.core.glide.GlideApp -class KeysBackupModule { +@Module +object ScreenModule { - companion object { - const val KEYS_BACKUP_SCOPE = "KEYS_BACKUP_SCOPE" - } + @Provides + @JvmStatic + fun providesGlideRequests(context: AppCompatActivity) = GlideApp.with(context) - val definition = module(override = true) { - - scope(KEYS_BACKUP_SCOPE) { - KeysBackupSettingsRecyclerViewController(get(), get()) - } - - } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/ScreenScope.java b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenScope.java new file mode 100644 index 00000000..d3915f7d --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenScope.java @@ -0,0 +1,29 @@ +/* + * 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.di; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Scope +@Documented +@Retention(RUNTIME) +public @interface ScreenScope {} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/VectorAssistedModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/VectorAssistedModule.kt new file mode 100644 index 00000000..cd69d182 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/VectorAssistedModule.kt @@ -0,0 +1,25 @@ +/* + * 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.di + +import com.squareup.inject.assisted.dagger2.AssistedModule +import dagger.Module + +/* +@Module(includes = [AssistedInject_VectorAssistedModule::class]) +@AssistedModule +class VectorAssistedModule*/ diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt new file mode 100644 index 00000000..6517c4b9 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt @@ -0,0 +1,65 @@ +/* + * 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.di + +import android.content.Context +import android.content.res.Resources +import dagger.BindsInstance +import dagger.Component +import im.vector.matrix.android.api.Matrix +import im.vector.matrix.android.api.session.Session +import im.vector.riotredesign.features.configuration.VectorConfiguration +import im.vector.riotredesign.features.crypto.keysrequest.KeyRequestHandler +import im.vector.riotredesign.features.crypto.verification.IncomingVerificationRequestHandler +import im.vector.riotredesign.features.home.HomeRoomListObservableStore +import im.vector.riotredesign.features.home.group.SelectedGroupStore +import im.vector.riotredesign.features.navigation.Navigator +import im.vector.riotredesign.features.notifications.NotificationDrawerManager +import javax.inject.Singleton + +@Component(modules = [VectorModule::class]) +@Singleton +interface VectorComponent { + + fun matrix(): Matrix + + fun currentSession(): Session + + fun notificationDrawerManager(): NotificationDrawerManager + + fun appContext(): Context + + fun resources(): Resources + + fun vectorConfiguration(): VectorConfiguration + + fun navigator(): Navigator + + fun homeRoomListObservableStore(): HomeRoomListObservableStore + + fun selectedGroupStore(): SelectedGroupStore + + fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler + + fun incomingKeyRequestHandler(): KeyRequestHandler + + @Component.Factory + interface Factory { + fun create(@BindsInstance context: Context): VectorComponent + } + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt new file mode 100644 index 00000000..4b4f4467 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt @@ -0,0 +1,67 @@ +/* + * 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.di + +import android.content.Context +import android.content.Context.MODE_PRIVATE +import android.content.SharedPreferences +import android.content.res.Resources +import dagger.Binds +import dagger.Module +import dagger.Provides +import im.vector.matrix.android.api.Matrix +import im.vector.matrix.android.api.session.Session +import im.vector.riotredesign.features.navigation.DefaultNavigator +import im.vector.riotredesign.features.navigation.Navigator + +@Module +abstract class VectorModule { + + @Module + companion object { + + @Provides + @JvmStatic + fun providesResources(context: Context): Resources { + return context.resources + } + + @Provides + @JvmStatic + fun providesSharedPreferences(context: Context): SharedPreferences { + return context.getSharedPreferences("im.vector.riot", MODE_PRIVATE) + } + + @Provides + @JvmStatic + fun providesMatrix(): Matrix { + return Matrix.getInstance() + } + + @Provides + @JvmStatic + fun providesCurrentSession(matrix: Matrix): Session { + //TODO: handle session injection better + return matrix.currentSession!! + } + } + + @Binds + abstract fun bindNavigator(navigator: DefaultNavigator): Navigator + + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/VectorViewModelFactory.kt b/vector/src/main/java/im/vector/riotredesign/core/di/VectorViewModelFactory.kt new file mode 100644 index 00000000..eac1b52e --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/VectorViewModelFactory.kt @@ -0,0 +1,50 @@ +/* + * 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.di + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import javax.inject.Inject +import javax.inject.Provider + +/** + * ViewModelFactory which uses Dagger to create the instances. + */ +class VectorViewModelFactory @Inject constructor( + private val creators: @JvmSuppressWildcards Map, Provider> +) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + var creator: Provider? = creators[modelClass] + if (creator == null) { + for ((key, value) in creators) { + if (modelClass.isAssignableFrom(key)) { + creator = value + break + } + } + } + if (creator == null) { + throw IllegalArgumentException("Unknown model class: $modelClass") + } + try { + @Suppress("UNCHECKED_CAST") + return creator.get() as T + } catch (e: Exception) { + throw RuntimeException(e) + } + } +} diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/ViewModelKey.kt b/vector/src/main/java/im/vector/riotredesign/core/di/ViewModelKey.kt new file mode 100644 index 00000000..c0887423 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ViewModelKey.kt @@ -0,0 +1,26 @@ +/* + * 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.di + +import androidx.lifecycle.ViewModel +import dagger.MapKey +import kotlin.reflect.KClass + +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +@Retention(AnnotationRetention.RUNTIME) +@MapKey +annotation class ViewModelKey(val value: KClass) \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/ViewModelModule.kt new file mode 100644 index 00000000..c38608ff --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ViewModelModule.kt @@ -0,0 +1,150 @@ +/* + * 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.di + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import im.vector.riotredesign.features.crypto.keysbackup.restore.KeysBackupRestoreFromKeyViewModel +import im.vector.riotredesign.features.crypto.keysbackup.restore.KeysBackupRestoreFromPassphraseViewModel +import im.vector.riotredesign.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel +import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupSettingsViewModel +import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupSettingsViewModel_AssistedFactory +import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupSharedViewModel +import im.vector.riotredesign.features.crypto.verification.SasVerificationViewModel +import im.vector.riotredesign.features.home.HomeActivityViewModel +import im.vector.riotredesign.features.home.HomeActivityViewModel_AssistedFactory +import im.vector.riotredesign.features.home.HomeDetailViewModel +import im.vector.riotredesign.features.home.HomeDetailViewModel_AssistedFactory +import im.vector.riotredesign.features.home.HomeNavigationViewModel +import im.vector.riotredesign.features.home.group.GroupListViewModel +import im.vector.riotredesign.features.home.group.GroupListViewModel_AssistedFactory +import im.vector.riotredesign.features.home.room.detail.RoomDetailViewModel +import im.vector.riotredesign.features.home.room.detail.RoomDetailViewModel_AssistedFactory +import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewModel +import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewModel_AssistedFactory +import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageActionsViewModel +import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageActionsViewModel_AssistedFactory +import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageMenuViewModel +import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageMenuViewModel_AssistedFactory +import im.vector.riotredesign.features.home.room.detail.timeline.action.QuickReactionViewModel +import im.vector.riotredesign.features.home.room.detail.timeline.action.QuickReactionViewModel_AssistedFactory +import im.vector.riotredesign.features.home.room.list.RoomListViewModel +import im.vector.riotredesign.features.home.room.list.RoomListViewModel_AssistedFactory +import im.vector.riotredesign.features.reactions.EmojiChooserViewModel +import im.vector.riotredesign.features.roomdirectory.RoomDirectoryNavigationViewModel +import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel +import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel_AssistedFactory +import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerViewModel +import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerViewModel_AssistedFactory +import im.vector.riotredesign.features.roomdirectory.roompreview.RoomPreviewViewModel +import im.vector.riotredesign.features.roomdirectory.roompreview.RoomPreviewViewModel_AssistedFactory +import im.vector.riotredesign.features.workers.signout.SignOutViewModel + +@Module +interface ViewModelModule { + + @Binds + fun bindViewModelFactory(factory: VectorViewModelFactory): ViewModelProvider.Factory + + @Binds + @IntoMap + @ViewModelKey(SignOutViewModel::class) + fun bindSignOutViewModel(viewModel: SignOutViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(EmojiChooserViewModel::class) + fun bindEmojiChooserViewModel(viewModel: EmojiChooserViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(SasVerificationViewModel::class) + fun bindSasVerificationViewModel(viewModel: SasVerificationViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(KeysBackupRestoreFromKeyViewModel::class) + fun bindKeysBackupRestoreFromKeyViewModel(viewModel: KeysBackupRestoreFromKeyViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(KeysBackupRestoreSharedViewModel::class) + fun bindKeysBackupRestoreSharedViewModel(viewModel: KeysBackupRestoreSharedViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(KeysBackupRestoreFromPassphraseViewModel::class) + fun bindKeysBackupRestoreFromPassphraseViewModel(viewModel: KeysBackupRestoreFromPassphraseViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(RoomDirectoryNavigationViewModel::class) + fun bindRoomDirectoryNavigationViewModel(viewModel: RoomDirectoryNavigationViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(HomeNavigationViewModel::class) + fun bindHomeNavigationViewModel(viewModel: HomeNavigationViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(KeysBackupSetupSharedViewModel::class) + fun bindKeysBackupSetupSharedViewModel(viewModel: KeysBackupSetupSharedViewModel): ViewModel + + @Binds + fun bind_im_vector_riotredesign_features_home_HomeActivityViewModel(factory: HomeActivityViewModel_AssistedFactory): HomeActivityViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_room_detail_composer_TextComposerViewModel(factory: TextComposerViewModel_AssistedFactory): TextComposerViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_room_detail_RoomDetailViewModel(factory: RoomDetailViewModel_AssistedFactory): RoomDetailViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_room_detail_timeline_action_QuickReactionViewModel(factory: QuickReactionViewModel_AssistedFactory): QuickReactionViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_room_detail_timeline_action_MessageActionsViewModel(factory: MessageActionsViewModel_AssistedFactory): MessageActionsViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_room_detail_timeline_action_MessageMenuViewModel(factory: MessageMenuViewModel_AssistedFactory): MessageMenuViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_room_list_RoomListViewModel(factory: RoomListViewModel_AssistedFactory): RoomListViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_group_GroupListViewModel(factory: GroupListViewModel_AssistedFactory): GroupListViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_home_HomeDetailViewModel(factory: HomeDetailViewModel_AssistedFactory): HomeDetailViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_crypto_keysbackup_settings_KeysBackupSettingsViewModel(factory: KeysBackupSettingsViewModel_AssistedFactory): KeysBackupSettingsViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_roomdirectory_picker_RoomDirectoryPickerViewModel(factory: RoomDirectoryPickerViewModel_AssistedFactory): RoomDirectoryPickerViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_roomdirectory_RoomDirectoryViewModel(factory: RoomDirectoryViewModel_AssistedFactory): RoomDirectoryViewModel.Factory + + @Binds + fun bind_im_vector_riotredesign_features_roomdirectory_roompreview_RoomPreviewViewModel(factory: RoomPreviewViewModel_AssistedFactory): RoomPreviewViewModel.Factory + +} \ No newline at end of file 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 index 114e08b8..284bd192 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/error/ErrorFormatter.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/error/ErrorFormatter.kt @@ -19,8 +19,9 @@ 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 +import javax.inject.Inject -class ErrorFormatter(val stringProvider: StringProvider) { +class ErrorFormatter @Inject constructor(val stringProvider: StringProvider) { fun toHumanReadable(failure: Failure): String { diff --git a/vector/src/main/java/im/vector/riotredesign/core/extensions/Activity.kt b/vector/src/main/java/im/vector/riotredesign/core/extensions/Activity.kt index 8c23d795..78796d5e 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/extensions/Activity.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/extensions/Activity.kt @@ -33,4 +33,4 @@ fun AppCompatActivity.addFragmentToBackstack(fragment: Fragment, frameId: Int, t fun AppCompatActivity.hideKeyboard() { currentFocus?.hideKeyboard() -} \ No newline at end of file +} diff --git a/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt index 1467071b..e0eb4bac 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/extensions/Fragment.kt @@ -40,4 +40,4 @@ fun Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) { fun Fragment.addChildFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) { childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) } -} \ No newline at end of file +} diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/ConfigurationViewModel.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/ConfigurationViewModel.kt index af7d0e5d..24fa889b 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/ConfigurationViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/ConfigurationViewModel.kt @@ -21,13 +21,12 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import im.vector.riotredesign.core.utils.LiveEvent import im.vector.riotredesign.features.configuration.VectorConfiguration -import org.koin.standalone.KoinComponent -import org.koin.standalone.inject import timber.log.Timber +import javax.inject.Inject -class ConfigurationViewModel : ViewModel(), KoinComponent { - - private val vectorConfiguration: VectorConfiguration by inject() +class ConfigurationViewModel @Inject constructor( + private val vectorConfiguration: VectorConfiguration +) : ViewModel() { private var currentConfigurationValue: String? = null @@ -47,7 +46,6 @@ class ConfigurationViewModel : ViewModel(), KoinComponent { if (newHash != currentConfigurationValue) { Timber.v("Configuration: recreate the Activity") currentConfigurationValue = newHash - _activityRestarter.postValue(LiveEvent(Unit)) } } diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/SimpleFragmentActivity.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/SimpleFragmentActivity.kt index dfac10b5..2b891275 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/SimpleFragmentActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/SimpleFragmentActivity.kt @@ -15,6 +15,7 @@ */ package im.vector.riotredesign.core.platform +import android.os.Bundle import android.view.View import android.widget.ProgressBar import android.widget.TextView @@ -25,7 +26,7 @@ import im.vector.matrix.android.api.session.Session import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.hideKeyboard import kotlinx.android.synthetic.main.activity.* -import org.koin.android.ext.android.get +import javax.inject.Inject /** * Simple activity with a toolbar, a waiting overlay, and a fragment container and a session. @@ -43,7 +44,13 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() { @BindView(R.id.waiting_view_status_horizontal_progress) lateinit var waitingHorizontalProgress: ProgressBar - protected val session = get() + @Inject + lateinit var session: Session + + override fun onCreate(savedInstanceState: Bundle?) { + injector().inject(this) + super.onCreate(savedInstanceState) + } override fun initUiAndData() { configureToolbar(toolbar) diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt index 3507788b..830ebcf6 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt @@ -22,35 +22,48 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View -import androidx.annotation.* +import androidx.annotation.AttrRes +import androidx.annotation.LayoutRes +import androidx.annotation.MainThread +import androidx.annotation.MenuRes +import androidx.annotation.Nullable +import androidx.annotation.StringRes import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.isVisible import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.ButterKnife import butterknife.Unbinder import com.airbnb.mvrx.BaseMvRxActivity +import com.airbnb.mvrx.MvRxState import com.bumptech.glide.util.Util import com.google.android.material.snackbar.Snackbar import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.HasInjector +import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.utils.toast import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.rageshake.BugReportActivity import im.vector.riotredesign.features.rageshake.BugReporter import im.vector.riotredesign.features.rageshake.RageShake +import im.vector.riotredesign.features.roomdirectory.PublicRoomsViewState +import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel import im.vector.riotredesign.features.themes.ActivityOtherThemes import im.vector.riotredesign.features.themes.ThemeUtils import im.vector.riotredesign.receivers.DebugReceiver import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable -import org.koin.android.ext.android.inject import timber.log.Timber +import javax.inject.Provider +import kotlin.reflect.KClass -abstract class VectorBaseActivity : BaseMvRxActivity() { +abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector { /* ========================================================================================== * UI * ========================================================================================== */ @@ -64,8 +77,8 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { * DATA * ========================================================================================== */ - private val vectorConfiguration: VectorConfiguration by inject() - + protected lateinit var viewModelFactory: ViewModelProvider.Factory + private lateinit var vectorConfiguration: VectorConfiguration private lateinit var configurationViewModel: ConfigurationViewModel private var unBinder: Unbinder? = null @@ -79,6 +92,7 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { private val restorables = ArrayList() private var rageShake: RageShake? = null + private lateinit var screenComponent: ScreenComponent override fun attachBaseContext(base: Context) { super.attachBaseContext(vectorConfiguration.getLocalisedContext(base)) @@ -107,10 +121,9 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { } override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) - - configurationViewModel = ViewModelProviders.of(this).get(ConfigurationViewModel::class.java) - + configurationViewModel = ViewModelProviders.of(this, viewModelFactory).get(ConfigurationViewModel::class.java) configurationViewModel.activityRestarter.observe(this, Observer { if (!it.hasBeenHandled) { // Recreate the Activity because configuration has changed @@ -202,6 +215,10 @@ abstract class VectorBaseActivity : BaseMvRxActivity() { } + override fun injector(): ScreenComponent { + return screenComponent + } + /* ========================================================================================== * PRIVATE METHODS * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt index f291746e..137c680c 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt @@ -18,24 +18,29 @@ package im.vector.riotredesign.core.platform import android.os.Bundle import android.os.Parcelable -import android.view.* +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.View +import android.view.ViewGroup import androidx.annotation.CallSuper import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.appcompat.widget.Toolbar +import androidx.lifecycle.ViewModelProvider import butterknife.ButterKnife import butterknife.Unbinder import com.airbnb.mvrx.BaseMvRxFragment import com.airbnb.mvrx.MvRx import com.bumptech.glide.util.Util.assertMainThread +import im.vector.riotredesign.core.di.HasInjector +import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.features.navigation.Navigator import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable -import org.koin.android.ext.android.inject -import org.koin.core.parameter.parametersOf import timber.log.Timber -abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed { +abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed, HasInjector { // Butterknife unbinder private var mUnBinder: Unbinder? = null @@ -48,7 +53,8 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed { * Navigator * ========================================================================================== */ - protected val navigator: Navigator by inject { parametersOf(this) } + protected lateinit var viewModelFactory: ViewModelProvider.Factory + protected lateinit var navigator: Navigator /* ========================================================================================== * Life cycle @@ -57,7 +63,6 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed { @CallSuper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (getMenuRes() != -1) { setHasOptionsMenu(true) } @@ -92,10 +97,13 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed { override fun onDestroy() { super.onDestroy() - uiDisposables.dispose() } + override fun injector(): ScreenComponent { + return vectorBaseActivity.injector() + } + /* ========================================================================================== * Restorable * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt index cfc48891..88844be4 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/ColorProvider.kt @@ -18,14 +18,15 @@ package im.vector.riotredesign.core.resources -import android.content.Context import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.annotation.ColorRes +import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import im.vector.riotredesign.features.themes.ThemeUtils +import javax.inject.Inject -class ColorProvider(private val context: Context) { +class ColorProvider @Inject constructor(private val context: AppCompatActivity) { fun getColor(@ColorRes colorRes: Int): Int { return ContextCompat.getColor(context, colorRes) diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/LocaleProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/LocaleProvider.kt index 991177a7..f1f8fecf 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/resources/LocaleProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/LocaleProvider.kt @@ -19,8 +19,9 @@ package im.vector.riotredesign.core.resources import android.content.res.Resources import androidx.core.os.ConfigurationCompat import java.util.* +import javax.inject.Inject -class LocaleProvider(private val resources: Resources) { +class LocaleProvider @Inject constructor(private val resources: Resources) { fun current(): Locale { return ConfigurationCompat.getLocales(resources.configuration)[0] diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt index f8e58d76..fe058ca3 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/StringArrayProvider.kt @@ -19,8 +19,9 @@ package im.vector.riotredesign.core.resources import android.content.res.Resources import androidx.annotation.ArrayRes import androidx.annotation.NonNull +import javax.inject.Inject -class StringArrayProvider(private val resources: Resources) { +class StringArrayProvider @Inject constructor(private val resources: Resources) { /** * Returns a localized string array from the application's package's diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/StringProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/StringProvider.kt index e6b0452e..f575f354 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/resources/StringProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/StringProvider.kt @@ -20,8 +20,9 @@ import android.content.res.Resources import androidx.annotation.NonNull import androidx.annotation.PluralsRes import androidx.annotation.StringRes +import javax.inject.Inject -class StringProvider(private val resources: Resources) { +class StringProvider @Inject constructor(private val resources: Resources) { /** * Returns a localized string from the application's package's diff --git a/vector/src/main/java/im/vector/riotredesign/core/services/EventStreamServiceX.kt b/vector/src/main/java/im/vector/riotredesign/core/services/EventStreamServiceX.kt index 108b27d5..0f26887e 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/services/EventStreamServiceX.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/services/EventStreamServiceX.kt @@ -28,7 +28,6 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.riotredesign.R import im.vector.riotredesign.features.notifications.NotifiableEventResolver import im.vector.riotredesign.features.notifications.NotificationUtils -import org.koin.android.ext.android.inject import timber.log.Timber import java.util.concurrent.TimeUnit @@ -162,7 +161,7 @@ class EventStreamServiceX : VectorService() { val notification = NotificationUtils.buildForegroundServiceNotification(this, R.string.notification_sync_in_progress) startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification) } - ACTION_GO_TO_FOREGROUND -> { + ACTION_GO_TO_FOREGROUND -> { // Stop foreground notification display Timber.i("stopForeground") stopForeground(true) @@ -177,9 +176,9 @@ class EventStreamServiceX : VectorService() { when (action) { ACTION_START, - ACTION_GO_TO_FOREGROUND -> + ACTION_GO_TO_FOREGROUND -> when (serviceState) { - ServiceState.INIT -> + ServiceState.INIT -> start(false) ServiceState.CATCHUP -> // A push has been received before, just change state, to avoid stopping the service when catchup is over @@ -190,12 +189,12 @@ class EventStreamServiceX : VectorService() { } ACTION_STOP, ACTION_GO_TO_BACKGROUND, - ACTION_LOGOUT -> + ACTION_LOGOUT -> stop() ACTION_PUSH_RECEIVED, ACTION_SIMULATED_PUSH_RECEIVED -> when (serviceState) { - ServiceState.INIT -> + ServiceState.INIT -> start(true) ServiceState.CATCHUP -> catchup(true) @@ -203,17 +202,17 @@ class EventStreamServiceX : VectorService() { // Nothing to do Unit } - ACTION_PUSH_UPDATE -> pushStatusUpdate() - ACTION_BOOT_COMPLETE -> { + ACTION_PUSH_UPDATE -> pushStatusUpdate() + ACTION_BOOT_COMPLETE -> { // No FCM only mSimulatePushImmediate = true stop() } - ACTION_APPLICATION_UPGRADE -> { + ACTION_APPLICATION_UPGRADE -> { // FDroid only catchup(true) } - else -> { + else -> { // Should not happen } } @@ -247,8 +246,8 @@ class EventStreamServiceX : VectorService() { val pushSimulatorRequest = OneTimeWorkRequestBuilder() .setInitialDelay(delay.toLong(), TimeUnit.MILLISECONDS) .setConstraints(Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build()) + .setRequiredNetworkType(NetworkType.CONNECTED) + .build()) .addTag(PUSH_SIMULATOR_REQUEST_TAG) .build() diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandController.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandController.kt index 7356364c..484ee2ce 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandController.kt @@ -20,8 +20,9 @@ import com.airbnb.epoxy.TypedEpoxyController import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.features.autocomplete.AutocompleteClickListener import im.vector.riotredesign.features.command.Command +import javax.inject.Inject -class AutocompleteCommandController(private val stringProvider: StringProvider) : TypedEpoxyController>() { +class AutocompleteCommandController @Inject constructor(private val stringProvider: StringProvider) : TypedEpoxyController>() { var listener: AutocompleteClickListener? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandPresenter.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandPresenter.kt index ca894948..4449d2ed 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandPresenter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandPresenter.kt @@ -20,9 +20,10 @@ import android.content.Context import com.airbnb.epoxy.EpoxyController import im.vector.riotredesign.features.autocomplete.EpoxyAutocompletePresenter import im.vector.riotredesign.features.command.Command +import javax.inject.Inject -class AutocompleteCommandPresenter(context: Context, - private val controller: AutocompleteCommandController) : +class AutocompleteCommandPresenter @Inject constructor(context: Context, + private val controller: AutocompleteCommandController) : EpoxyAutocompletePresenter(context) { init { diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandAutocompletePolicy.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandAutocompletePolicy.kt index 38556cdb..a6f9aa72 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandAutocompletePolicy.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandAutocompletePolicy.kt @@ -18,8 +18,9 @@ package im.vector.riotredesign.features.autocomplete.command import android.text.Spannable import com.otaliastudios.autocomplete.AutocompletePolicy +import javax.inject.Inject -class CommandAutocompletePolicy : AutocompletePolicy { +class CommandAutocompletePolicy @Inject constructor() : AutocompletePolicy { var enabled: Boolean = true @@ -37,7 +38,7 @@ class CommandAutocompletePolicy : AutocompletePolicy { // Only if text which starts with '/' and without space override fun shouldShowPopup(text: Spannable?, cursorPos: Int): Boolean { return enabled && text?.startsWith("/") == true - && !text.contains(" ") + && !text.contains(" ") } override fun shouldDismissPopup(text: Spannable?, cursorPos: Int): Boolean { diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt index 6f174e0d..dfc1f93f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt @@ -19,8 +19,9 @@ package im.vector.riotredesign.features.autocomplete.user import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.user.model.User import im.vector.riotredesign.features.autocomplete.AutocompleteClickListener +import javax.inject.Inject -class AutocompleteUserController : TypedEpoxyController>() { +class AutocompleteUserController @Inject constructor(): TypedEpoxyController>() { var listener: AutocompleteClickListener? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserPresenter.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserPresenter.kt index be4ec7e7..b525cfac 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserPresenter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserPresenter.kt @@ -22,9 +22,10 @@ import com.airbnb.mvrx.Async import com.airbnb.mvrx.Success import im.vector.matrix.android.api.session.user.model.User import im.vector.riotredesign.features.autocomplete.EpoxyAutocompletePresenter +import javax.inject.Inject -class AutocompleteUserPresenter(context: Context, - private val controller: AutocompleteUserController +class AutocompleteUserPresenter @Inject constructor(context: Context, + private val controller: AutocompleteUserController ) : EpoxyAutocompletePresenter(context) { var callback: Callback? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt b/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt index 1f408554..3790661a 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/configuration/VectorConfiguration.kt @@ -25,20 +25,22 @@ import im.vector.riotredesign.features.settings.VectorLocale import im.vector.riotredesign.features.themes.ThemeUtils import timber.log.Timber import java.util.* +import javax.inject.Inject /** * Handle locale configuration change, such as theme, font size and locale chosen by the user */ -class VectorConfiguration(private val context: Context) { + +class VectorConfiguration @Inject constructor(private val context: Context) { // TODO Import mLanguageReceiver From Riot? fun onConfigurationChanged(newConfig: Configuration?) { if (Locale.getDefault().toString() != VectorLocale.applicationLocale.toString()) { Timber.v("## onConfigurationChanged() : the locale has been updated to " + Locale.getDefault().toString() - + ", restore the expected value " + VectorLocale.applicationLocale.toString()) + + ", restore the expected value " + VectorLocale.applicationLocale.toString()) updateApplicationSettings(VectorLocale.applicationLocale, - FontScale.getFontScalePrefValue(context), - ThemeUtils.getApplicationTheme(context)) + FontScale.getFontScalePrefValue(context), + ThemeUtils.getApplicationTheme(context)) } } @@ -65,8 +67,8 @@ class VectorConfiguration(private val context: Context) { fun updateApplicationTheme(theme: String) { ThemeUtils.setApplicationTheme(context, theme) updateApplicationSettings(VectorLocale.applicationLocale, - FontScale.getFontScalePrefValue(context), - theme) + FontScale.getFontScalePrefValue(context), + theme) } /** diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt index 5083dd9a..333342e1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt @@ -23,7 +23,6 @@ import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import im.vector.fragments.keysbackup.restore.KeysBackupRestoreFromPassphraseFragment -import im.vector.fragments.keysbackup.restore.KeysBackupRestoreSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.observeEvent import im.vector.riotredesign.core.platform.SimpleFragmentActivity @@ -43,9 +42,8 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() { override fun initUiAndData() { super.initUiAndData() - viewModel = ViewModelProviders.of(this).get(KeysBackupRestoreSharedViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreSharedViewModel::class.java) viewModel.initSession(session) - viewModel.keyVersionResult.observe(this, Observer { keyVersion -> if (keyVersion != null && supportFragmentManager.fragments.isEmpty()) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt index 8d07b3af..f104791f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt @@ -27,7 +27,6 @@ import butterknife.BindView import butterknife.OnClick import butterknife.OnTextChanged import com.google.android.material.textfield.TextInputLayout -import im.vector.fragments.keysbackup.restore.KeysBackupRestoreSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.core.utils.startImportTextFromFileIntent @@ -53,9 +52,9 @@ class KeysBackupRestoreFromKeyFragment : VectorBaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProviders.of(this).get(KeysBackupRestoreFromKeyViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreFromKeyViewModel::class.java) sharedViewModel = activity?.run { - ViewModelProviders.of(this).get(KeysBackupRestoreSharedViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreSharedViewModel::class.java) } ?: throw Exception("Invalid Activity") mKeyTextEdit.setText(viewModel.recoveryCode.value) diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt index dd536944..99a36f30 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt @@ -18,7 +18,6 @@ package im.vector.riotredesign.features.crypto.keysbackup.restore import android.content.Context import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import im.vector.fragments.keysbackup.restore.KeysBackupRestoreSharedViewModel import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.listeners.StepProgressListener import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService @@ -28,8 +27,9 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.WaitingViewData import im.vector.riotredesign.core.ui.views.KeysBackupBanner import timber.log.Timber +import javax.inject.Inject -class KeysBackupRestoreFromKeyViewModel : ViewModel() { +class KeysBackupRestoreFromKeyViewModel @Inject constructor() : ViewModel() { var recoveryCode: MutableLiveData = MutableLiveData() var recoveryCodeErrorText: MutableLiveData = MutableLiveData() diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index 41d0a4e5..57ca3743 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -36,6 +36,7 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.showPassword import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.crypto.keysbackup.restore.KeysBackupRestoreFromPassphraseViewModel +import im.vector.riotredesign.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel class KeysBackupRestoreFromPassphraseFragment : VectorBaseFragment() { @@ -68,9 +69,9 @@ class KeysBackupRestoreFromPassphraseFragment : VectorBaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProviders.of(this).get(KeysBackupRestoreFromPassphraseViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreFromPassphraseViewModel::class.java) sharedViewModel = activity?.run { - ViewModelProviders.of(this).get(KeysBackupRestoreSharedViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreSharedViewModel::class.java) } ?: throw Exception("Invalid Activity") diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt index e60923fd..bdbfd23b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt @@ -18,7 +18,6 @@ package im.vector.riotredesign.features.crypto.keysbackup.restore import android.content.Context import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import im.vector.fragments.keysbackup.restore.KeysBackupRestoreSharedViewModel import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.listeners.StepProgressListener import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService @@ -28,8 +27,9 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.WaitingViewData import im.vector.riotredesign.core.ui.views.KeysBackupBanner import timber.log.Timber +import javax.inject.Inject -class KeysBackupRestoreFromPassphraseViewModel : ViewModel() { +class KeysBackupRestoreFromPassphraseViewModel @Inject constructor() : ViewModel() { var passphrase: MutableLiveData = MutableLiveData() var passphraseErrorText: MutableLiveData = MutableLiveData() diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt index 3db0191e..d6c618ba 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSharedViewModel.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package im.vector.fragments.keysbackup.restore +package im.vector.riotredesign.features.crypto.keysbackup.restore import android.content.Context import androidx.lifecycle.LiveData @@ -21,13 +21,14 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session -import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult +import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.WaitingViewData import im.vector.riotredesign.core.utils.LiveEvent +import javax.inject.Inject -class KeysBackupRestoreSharedViewModel : ViewModel() { +class KeysBackupRestoreSharedViewModel @Inject constructor() : ViewModel() { companion object { const val NAVIGATE_TO_RECOVER_WITH_KEY = "NAVIGATE_TO_RECOVER_WITH_KEY" diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt index 106ed764..6b4cc8b7 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt @@ -20,7 +20,6 @@ import android.widget.TextView import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.OnClick -import im.vector.fragments.keysbackup.restore.KeysBackupRestoreSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.core.utils.LiveEvent @@ -40,7 +39,7 @@ class KeysBackupRestoreSuccessFragment : VectorBaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) sharedViewModel = activity?.run { - ViewModelProviders.of(this).get(KeysBackupRestoreSharedViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreSharedViewModel::class.java) } ?: throw Exception("Invalid Activity") sharedViewModel.importKeyResult?.let { diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt index 98b6716b..bc83aaf9 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt @@ -17,16 +17,16 @@ package im.vector.riotredesign.features.crypto.keysbackup.settings import android.content.Context import android.content.Intent +import android.os.Bundle import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading import com.airbnb.mvrx.viewModel import im.vector.riotredesign.R +import im.vector.riotredesign.core.extensions.injector import im.vector.riotredesign.core.platform.SimpleFragmentActivity import im.vector.riotredesign.core.platform.WaitingViewData -import im.vector.riotredesign.features.crypto.keysbackup.KeysBackupModule -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope +import javax.inject.Inject class KeysBackupManageActivity : SimpleFragmentActivity() { @@ -41,12 +41,15 @@ class KeysBackupManageActivity : SimpleFragmentActivity() { override fun getTitleRes() = R.string.encryption_message_recovery private val viewModel: KeysBackupSettingsViewModel by viewModel() + @Inject lateinit var keysBackupSettingsViewModelFactory: KeysBackupSettingsViewModel.Factory + + override fun onCreate(savedInstanceState: Bundle?) { + injector.inject(this) + super.onCreate(savedInstanceState) + } override fun initUiAndData() { super.initUiAndData() - - bindScope(getOrCreateScope(KeysBackupModule.KEYS_BACKUP_SCOPE)) - if (supportFragmentManager.fragments.isEmpty()) { supportFragmentManager.beginTransaction() .replace(R.id.container, KeysBackupSettingsFragment.newInstance()) diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt index 983a3e2a..3a0239d0 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt @@ -21,17 +21,15 @@ import androidx.appcompat.app.AlertDialog import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.riotredesign.R +import im.vector.riotredesign.core.extensions.injector import im.vector.riotredesign.core.platform.VectorBaseFragment -import im.vector.riotredesign.features.crypto.keysbackup.KeysBackupModule import im.vector.riotredesign.features.crypto.keysbackup.restore.KeysBackupRestoreActivity import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupActivity import kotlinx.android.synthetic.main.fragment_keys_backup_settings.* -import org.koin.android.ext.android.inject -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope +import javax.inject.Inject class KeysBackupSettingsFragment : VectorBaseFragment(), - KeysBackupSettingsRecyclerViewController.Listener { + KeysBackupSettingsRecyclerViewController.Listener { companion object { fun newInstance() = KeysBackupSettingsFragment() @@ -39,14 +37,12 @@ class KeysBackupSettingsFragment : VectorBaseFragment(), override fun getLayoutResId() = R.layout.fragment_keys_backup_settings - private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController by inject() - + @Inject lateinit var keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController private val viewModel: KeysBackupSettingsViewModel by activityViewModel() override fun onCreate(savedInstanceState: Bundle?) { + injector().inject(this) super.onCreate(savedInstanceState) - - bindScope(getOrCreateScope(KeysBackupModule.KEYS_BACKUP_SCOPE)) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt index 80e716cc..6e555b58 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt @@ -17,11 +17,14 @@ package im.vector.riotredesign.features.crypto.keysbackup.settings import android.view.View import com.airbnb.epoxy.TypedEpoxyController -import com.airbnb.mvrx.* +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust -import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult import im.vector.riotredesign.R import im.vector.riotredesign.core.epoxy.errorWithRetryItem import im.vector.riotredesign.core.epoxy.loadingItem @@ -29,9 +32,10 @@ import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.core.ui.list.GenericItem import im.vector.riotredesign.core.ui.list.genericItem import java.util.* +import javax.inject.Inject -class KeysBackupSettingsRecyclerViewController(val stringProvider: StringProvider, - val session: Session) : TypedEpoxyController() { +class KeysBackupSettingsRecyclerViewController @Inject constructor(val stringProvider: StringProvider, + val session: Session) : TypedEpoxyController() { var listener: Listener? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt index 969ff028..d656d90c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt @@ -15,7 +15,15 @@ */ package im.vector.riotredesign.features.crypto.keysbackup.settings -import com.airbnb.mvrx.* +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService @@ -23,33 +31,37 @@ import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust import im.vector.riotredesign.core.platform.VectorViewModel -import org.koin.android.ext.android.get -class KeysBackupSettingsViewModel(initialState: KeysBackupSettingViewState, - session: Session) : VectorViewModel(initialState), - KeysBackupStateListener { +class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialState: KeysBackupSettingViewState, + session: Session +) : VectorViewModel(initialState), + KeysBackupStateListener { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: KeysBackupSettingViewState): KeysBackupSettingsViewModel + } companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: KeysBackupSettingViewState): KeysBackupSettingsViewModel? { - val session = viewModelContext.activity.get() - - val firstState = state.copy( - keysBackupState = session.getKeysBackupService().state, - keysBackupVersion = session.getKeysBackupService().keysBackupVersion - ) - - return KeysBackupSettingsViewModel(firstState, session) + val activity: KeysBackupManageActivity = (viewModelContext as ActivityViewModelContext).activity() + return activity.keysBackupSettingsViewModelFactory.create(state) } } private var keysBackupService: KeysBackupService = session.getKeysBackupService() init { + setState { + this.copy( + keysBackupState = session.getKeysBackupService().state, + keysBackupVersion = session.getKeysBackupService().keysBackupVersion + ) + } keysBackupService.addListener(this) - getKeysBackupTrust() } @@ -90,8 +102,8 @@ class KeysBackupSettingsViewModel(initialState: KeysBackupSettingViewState, } override fun onCleared() { - super.onCleared() keysBackupService.removeListener(this) + super.onCleared() } override fun onStateChange(newState: KeysBackupState) { @@ -142,6 +154,6 @@ class KeysBackupSettingsViewModel(initialState: KeysBackupSettingViewState, val currentBackupState = keysBackupService.state return currentBackupState == KeysBackupState.Unknown - || currentBackupState == KeysBackupState.CheckingBackUpOnHomeserver + || currentBackupState == KeysBackupState.CheckingBackUpOnHomeserver } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt index 7ab0ab49..c4b88ead 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt @@ -22,7 +22,6 @@ import androidx.core.view.isVisible import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.dialogs.ExportKeysDialog import im.vector.riotredesign.core.extensions.observeEvent @@ -42,7 +41,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() { .commitNow() } - viewModel = ViewModelProviders.of(this).get(KeysBackupSetupSharedViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(KeysBackupSetupSharedViewModel::class.java) viewModel.showManualExport.value = intent.getBooleanExtra(EXTRA_SHOW_MANUAL_EXPORT, false) viewModel.initSession(session) diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt index c9d11d16..81ccb5a0 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.fragments.keysbackup.setup +package im.vector.riotredesign.features.crypto.keysbackup.setup import android.content.Context import androidx.lifecycle.MutableLiveData @@ -30,11 +30,12 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.WaitingViewData import im.vector.riotredesign.core.utils.LiveEvent import timber.log.Timber +import javax.inject.Inject /** * The shared view model between all fragments. */ -class KeysBackupSetupSharedViewModel : ViewModel() { +class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() { companion object { const val NAVIGATE_TO_STEP_2 = "NAVIGATE_TO_STEP_2" diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt index 0fccd510..f90983f7 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt @@ -24,7 +24,6 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.OnClick -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.core.utils.LiveEvent @@ -51,7 +50,7 @@ class KeysBackupSetupStep1Fragment : VectorBaseFragment() { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(KeysBackupSetupSharedViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(KeysBackupSetupSharedViewModel::class.java) } ?: throw Exception("Invalid Activity") viewModel.showManualExport.observe(this, Observer { diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index 47ade276..5267c22b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -30,7 +30,6 @@ import butterknife.OnClick import butterknife.OnTextChanged import com.google.android.material.textfield.TextInputLayout import com.nulabinc.zxcvbn.Zxcvbn -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.showPassword import im.vector.riotredesign.core.platform.VectorBaseFragment @@ -82,7 +81,7 @@ class KeysBackupSetupStep2Fragment : VectorBaseFragment() { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(KeysBackupSetupSharedViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(KeysBackupSetupSharedViewModel::class.java) } ?: throw Exception("Invalid Activity") viewModel.shouldPromptOnBack = true diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index a951b4c1..0a738bf5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -28,7 +28,6 @@ import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.OnClick import com.google.android.material.bottomsheet.BottomSheetDialog -import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel import im.vector.riotredesign.R import im.vector.riotredesign.core.files.addEntryToDownloadManager import im.vector.riotredesign.core.files.saveStringToFile @@ -58,7 +57,7 @@ class KeysBackupSetupStep3Fragment : VectorBaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(KeysBackupSetupSharedViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(KeysBackupSetupSharedViewModel::class.java) } ?: throw Exception("Invalid Activity") diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysrequest/KeyRequestHandler.kt index 30d16a62..a583760a 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/keysrequest/KeyRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/keysrequest/KeyRequestHandler.kt @@ -40,6 +40,8 @@ import timber.log.Timber import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* +import javax.inject.Inject +import javax.inject.Singleton import kotlin.collections.ArrayList import kotlin.collections.HashMap @@ -50,21 +52,20 @@ import kotlin.collections.HashMap * If several requests come from same user/device, a single alert is displayed (this alert will accept/reject all request * depending on user action) */ -class KeyRequestHandler(val context: Context, - val session: Session) + +@Singleton +class KeyRequestHandler @Inject constructor(val context: Context, + val session: Session) : RoomKeysRequestListener, - SasVerificationService.SasVerificationListener { + SasVerificationService.SasVerificationListener { private val alertsToRequests = HashMap>() init { session.getSasVerificationService().addListener(this) - session.addRoomKeysRequestListener(this) } - fun ensureStarted() = Unit - /** * Handle incoming key request. * @@ -194,8 +195,8 @@ class KeyRequestHandler(val context: Context, Runnable { alert.weakCurrentActivity?.get()?.let { val intent = SASVerificationActivity.outgoingIntent(it, - session.sessionParams.credentials.userId, - userId, deviceId) + session.sessionParams.credentials.userId, + userId, deviceId) it.startActivity(intent) } }, @@ -246,8 +247,8 @@ class KeyRequestHandler(val context: Context, val alertMgrUniqueKey = alertManagerId(deviceId!!, userId!!) alertsToRequests[alertMgrUniqueKey]?.removeAll { it.deviceId == request.deviceId - && it.userId == request.userId - && it.requestId == request.requestId + && it.userId == request.userId + && it.requestId == request.requestId } if (alertsToRequests[alertMgrUniqueKey]?.isEmpty() == true) { PopupAlertManager.cancelAlert(alertMgrUniqueKey) diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/IncomingVerificationRequestHandler.kt index 87cb3b54..f670a599 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -23,19 +23,21 @@ import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransactio import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState import im.vector.riotredesign.R import im.vector.riotredesign.features.popup.PopupAlertManager +import javax.inject.Inject +import javax.inject.Singleton /** * Listens to the VerificationManager and add a new notification when an incoming request is detected. */ -class IncomingVerificationRequestHandler(val context: Context, - private val session: Session) : SasVerificationService.SasVerificationListener { +@Singleton +class IncomingVerificationRequestHandler @Inject constructor(val context: Context, + private val session: Session +) : SasVerificationService.SasVerificationListener { init { session.getSasVerificationService().addListener(this) } - fun ensureStarted() = Unit - override fun transactionCreated(tx: SasVerificationTransaction) {} override fun transactionUpdated(tx: SasVerificationTransaction) { @@ -44,7 +46,7 @@ class IncomingVerificationRequestHandler(val context: Context, //Add a notification for every incoming request val session = Matrix.getInstance().currentSession!! val name = session.getUser(tx.otherUserId)?.displayName - ?: tx.otherUserId + ?: tx.otherUserId val alert = PopupAlertManager.VectorAlert( "kvr_${tx.transactionId}", @@ -54,9 +56,9 @@ class IncomingVerificationRequestHandler(val context: Context, .apply { contentAction = Runnable { val intent = SASVerificationActivity.incomingIntent(context, - session.sessionParams.credentials.userId, - tx.otherUserId, - tx.transactionId) + session.sessionParams.credentials.userId, + tx.otherUserId, + tx.transactionId) weakCurrentActivity?.get()?.startActivity(intent) } dismissedAction = Runnable { @@ -72,9 +74,9 @@ class IncomingVerificationRequestHandler(val context: Context, context.getString(R.string.action_open), Runnable { val intent = SASVerificationActivity.incomingIntent(context, - session.sessionParams.credentials.userId, - tx.otherUserId, - tx.transactionId) + session.sessionParams.credentials.userId, + tx.otherUserId, + tx.transactionId) weakCurrentActivity?.get()?.startActivity(intent) } ) diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationActivity.kt index 4fed4d96..c66a001c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationActivity.kt @@ -84,7 +84,7 @@ class SASVerificationActivity : SimpleFragmentActivity() { override fun initUiAndData() { super.initUiAndData() - viewModel = ViewModelProviders.of(this).get(SasVerificationViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(SasVerificationViewModel::class.java) val transactionID: String? = intent.getStringExtra(EXTRA_TRANSACTION_ID) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt index 35ef1acc..9f893afc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt @@ -53,7 +53,7 @@ class SASVerificationIncomingFragment : VectorBaseFragment() { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(SasVerificationViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(SasVerificationViewModel::class.java) } ?: throw Exception("Invalid Activity") otherUserDisplayNameTextView.text = viewModel.otherUser?.displayName ?: viewModel.otherUserId diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationShortCodeFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationShortCodeFragment.kt index b0363fae..faf40995 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationShortCodeFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationShortCodeFragment.kt @@ -69,7 +69,7 @@ class SASVerificationShortCodeFragment : VectorBaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(SasVerificationViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(SasVerificationViewModel::class.java) } ?: throw Exception("Invalid Activity") diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationStartFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationStartFragment.kt index e41d0c73..ce92888c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationStartFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationStartFragment.kt @@ -58,11 +58,7 @@ class SASVerificationStartFragment : VectorBaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - - viewModel = activity?.run { - ViewModelProviders.of(this).get(SasVerificationViewModel::class.java) - } ?: throw Exception("Invalid Activity") - + viewModel = ViewModelProviders.of(vectorBaseActivity, viewModelFactory).get(SasVerificationViewModel::class.java) viewModel.transactionState.observe(this, Observer { val uxState = (viewModel.transaction as? OutgoingSasVerificationRequest)?.uxState when (uxState) { @@ -75,14 +71,14 @@ class SASVerificationStartFragment : VectorBaseFragment() { this.startButtonLoading.animate() } - OutgoingSasVerificationRequest.UxState.SHOW_SAS -> { + OutgoingSasVerificationRequest.UxState.SHOW_SAS -> { viewModel.shortCodeReady() } OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME, - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> { + OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> { viewModel.navigateCancel() } - else -> { + else -> { TransitionManager.beginDelayedTransition(this.rootLayout) this.loadingText.isVisible = false this.startButton.isVisible = true diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationVerifiedFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationVerifiedFragment.kt index a14dc3ce..47e874be 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationVerifiedFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationVerifiedFragment.kt @@ -35,7 +35,7 @@ class SASVerificationVerifiedFragment : VectorBaseFragment() { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(SasVerificationViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(SasVerificationViewModel::class.java) } ?: throw Exception("Invalid Activity") } diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SasVerificationViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SasVerificationViewModel.kt index 7f06bba8..31fc91a4 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SasVerificationViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SasVerificationViewModel.kt @@ -25,10 +25,11 @@ import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransactio import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState import im.vector.matrix.android.api.session.user.model.User import im.vector.riotredesign.core.utils.LiveEvent +import javax.inject.Inject -class SasVerificationViewModel : ViewModel(), - SasVerificationService.SasVerificationListener { +class SasVerificationViewModel @Inject constructor() : ViewModel(), + SasVerificationService.SasVerificationListener { companion object { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt index c507224d..fb5671d2 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt @@ -43,9 +43,7 @@ import im.vector.riotredesign.features.rageshake.BugReporter import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotredesign.features.workers.signout.SignOutUiWorker import kotlinx.android.synthetic.main.activity_home.* -import org.koin.android.ext.android.inject -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope +import javax.inject.Inject class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { @@ -57,12 +55,13 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { private val homeActivityViewModel: HomeActivityViewModel by viewModel() private lateinit var navigationViewModel: HomeNavigationViewModel - private val homeNavigator by inject() + @Inject lateinit var homeActivityViewModelFactory: HomeActivityViewModel.Factory + @Inject lateinit var homeNavigator: HomeNavigator // TODO Move this elsewhere - private val incomingVerificationRequestHandler by inject() + @Inject lateinit var incomingVerificationRequestHandler: IncomingVerificationRequestHandler // TODO Move this elsewhere - private val keyRequestHandler by inject() + @Inject lateinit var keyRequestHandler: KeyRequestHandler private var progress: ProgressDialog? = null @@ -76,10 +75,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - bindScope(getOrCreateScope(HomeModule.HOME_SCOPE)) homeNavigator.activity = this - - navigationViewModel = ViewModelProviders.of(this).get(HomeNavigationViewModel::class.java) + navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(HomeNavigationViewModel::class.java) drawerLayout.addDrawerListener(drawerListener) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt index c710b477..a2f373fa 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt @@ -19,10 +19,12 @@ package im.vector.riotredesign.features.home import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import arrow.core.Option +import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext -import im.vector.matrix.android.api.Matrix +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.group.model.GroupSummary @@ -34,28 +36,31 @@ import im.vector.riotredesign.features.home.group.ALL_COMMUNITIES_GROUP_ID import im.vector.riotredesign.features.home.group.SelectedGroupStore import io.reactivex.Observable import io.reactivex.functions.BiFunction -import org.koin.android.ext.android.get import java.util.concurrent.TimeUnit data class EmptyState(val isEmpty: Boolean = true) : MvRxState -class HomeActivityViewModel(state: EmptyState, - private val session: Session, - private val selectedGroupStore: SelectedGroupStore, - private val homeRoomListStore: HomeRoomListObservableStore -) : VectorViewModel(state), Session.Listener { +class HomeActivityViewModel @AssistedInject constructor(@Assisted initialState: EmptyState, + private val session: Session, + private val selectedGroupStore: SelectedGroupStore, + private val homeRoomListStore: HomeRoomListObservableStore +) : VectorViewModel(initialState), Session.Listener { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: EmptyState): HomeActivityViewModel + } companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: EmptyState): HomeActivityViewModel? { - val session = Matrix.getInstance().currentSession!! - val selectedGroupStore = viewModelContext.activity.get() - val homeRoomListObservableSource = viewModelContext.activity.get() - return HomeActivityViewModel(state, session, selectedGroupStore, homeRoomListObservableSource) + val homeActivity: HomeActivity = (viewModelContext as ActivityViewModelContext).activity() + return homeActivity.homeActivityViewModelFactory.create(state) } } + private val _isLoading = MutableLiveData() val isLoading: LiveData get() = _isLoading diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt index 273a06d0..bb03f2cd 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt @@ -41,7 +41,7 @@ import im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView import im.vector.riotredesign.features.workers.signout.SignOutViewModel import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_home_detail.* -import org.koin.android.ext.android.inject +import javax.inject.Inject @Parcelize @@ -67,7 +67,8 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate { private val viewModel: HomeDetailViewModel by fragmentViewModel() private lateinit var navigationViewModel: HomeNavigationViewModel - private val session by inject() + @Inject lateinit var session: Session + @Inject lateinit var homeDetailViewModelFactory: HomeDetailViewModel.Factory override fun getLayoutResId(): Int { return R.layout.fragment_home_detail @@ -76,7 +77,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) currentDisplayMode = savedInstanceState?.getSerializable(CURRENT_DISPLAY_MODE) as? RoomListFragment.DisplayMode - ?: RoomListFragment.DisplayMode.HOME + ?: RoomListFragment.DisplayMode.HOME navigationViewModel = ViewModelProviders.of(requireActivity()).get(HomeNavigationViewModel::class.java) @@ -89,7 +90,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate { private fun setupKeysBackupBanner() { // Keys backup banner // Use the SignOutViewModel, it observe the keys backup state and this is what we need here - val model = ViewModelProviders.of(this).get(SignOutViewModel::class.java) + val model = ViewModelProviders.of(this, viewModelFactory).get(SignOutViewModel::class.java) model.init(session) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailViewModel.kt index 7e2ebb7f..59ff9a75 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailViewModel.kt @@ -16,28 +16,34 @@ package im.vector.riotredesign.features.home +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.rx.rx import im.vector.riotredesign.core.platform.VectorViewModel -import org.koin.android.ext.android.get /** * View model used to update the home bottom bar notification counts */ -class HomeDetailViewModel(initialState: HomeDetailViewState, - private val session: Session, - private val homeRoomListStore: HomeRoomListObservableStore) +class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState, + private val session: Session, + private val homeRoomListStore: HomeRoomListObservableStore) : VectorViewModel(initialState) { + @AssistedInject.Factory + interface Factory { + fun create(initialState: HomeDetailViewState): HomeDetailViewModel + } + companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: HomeDetailViewState): HomeDetailViewModel? { - val homeRoomListStore = viewModelContext.activity.get() - val session = viewModelContext.activity.get() - return HomeDetailViewModel(state, session, homeRoomListStore) + val fragment: HomeDetailFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.homeDetailViewModelFactory.create(state) } } @@ -65,21 +71,21 @@ class HomeDetailViewModel(initialState: HomeDetailViewState, .subscribe { list -> list.let { summaries -> val peopleNotifications = summaries - .filter { it.isDirect } - .map { it.notificationCount } - .takeIf { it.isNotEmpty() } - ?.sumBy { i -> i } - ?: 0 + .filter { it.isDirect } + .map { it.notificationCount } + .takeIf { it.isNotEmpty() } + ?.sumBy { i -> i } + ?: 0 val peopleHasHighlight = summaries .filter { it.isDirect } .any { it.highlightCount > 0 } val roomsNotifications = summaries - .filter { !it.isDirect } - .map { it.notificationCount } - .takeIf { it.isNotEmpty() } - ?.sumBy { i -> i } - ?: 0 + .filter { !it.isDirect } + .map { it.notificationCount } + .takeIf { it.isNotEmpty() } + ?.sumBy { i -> i } + ?: 0 val roomsHasHighlight = summaries .filter { !it.isDirect } .any { it.highlightCount > 0 } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt index 66195881..49ee8f67 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt @@ -24,7 +24,7 @@ import im.vector.riotredesign.core.extensions.replaceChildFragment import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.home.group.GroupListFragment import kotlinx.android.synthetic.main.fragment_home_drawer.* -import org.koin.android.ext.android.inject +import javax.inject.Inject class HomeDrawerFragment : VectorBaseFragment() { @@ -35,7 +35,7 @@ class HomeDrawerFragment : VectorBaseFragment() { } } - val session by inject() + @Inject lateinit var session: Session override fun getLayoutResId() = R.layout.fragment_home_drawer diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index 22d52787..eee5b8e8 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -16,89 +16,20 @@ package im.vector.riotredesign.features.home -import androidx.fragment.app.Fragment -import im.vector.riotredesign.core.glide.GlideApp -import im.vector.riotredesign.core.resources.ColorProvider -import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandController -import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter -import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserController -import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter -import im.vector.riotredesign.features.home.group.GroupSummaryController -import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController -import im.vector.riotredesign.features.home.room.detail.timeline.factory.* -import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider -import im.vector.riotredesign.features.home.room.list.RoomSummaryController -import im.vector.riotredesign.features.html.EventHtmlRenderer -import org.koin.core.parameter.parametersOf -import org.koin.dsl.module.module +import android.os.Handler +import dagger.Module +import dagger.Provides +import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventControllerHandler +import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineAsyncHelper -class HomeModule { +@Module +object HomeModule { - companion object { - const val HOME_SCOPE = "HOME_SCOPE" - const val ROOM_DETAIL_SCOPE = "ROOM_DETAIL_SCOPE" + @Provides + @JvmStatic + @TimelineEventControllerHandler + fun providesTimelineBackgroundHandler(): Handler { + return TimelineAsyncHelper.getBackgroundHandler() } - val definition = module { - - // Activity scope - - scope(HOME_SCOPE) { - HomeNavigator() - } - - scope(HOME_SCOPE) { - HomePermalinkHandler(get(), get()) - } - - // Fragment scopes - - factory { - TimelineDateFormatter(get()) - } - - factory { - NoticeEventFormatter(get()) - } - - factory { (fragment: Fragment) -> - val colorProvider = ColorProvider(fragment.requireContext()) - val timelineDateFormatter = get() - val eventHtmlRenderer = EventHtmlRenderer(GlideApp.with(fragment), fragment.requireContext(), get()) - val noticeEventFormatter = get(parameters = { parametersOf(fragment) }) - val timelineMediaSizeProvider = TimelineMediaSizeProvider() - val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider, - timelineDateFormatter, eventHtmlRenderer, get(), get()) - - val timelineItemFactory = TimelineItemFactory( - messageItemFactory = messageItemFactory, - noticeItemFactory = NoticeItemFactory(noticeEventFormatter), - defaultItemFactory = DefaultItemFactory(), - encryptionItemFactory = EncryptionItemFactory(get()), - encryptedItemFactory = EncryptedItemFactory(get()) - ) - TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider) - } - - factory { - RoomSummaryController(get(), get(), get()) - } - - factory { - GroupSummaryController() - } - - scope(ROOM_DETAIL_SCOPE) { (fragment: Fragment) -> - val commandController = AutocompleteCommandController(get()) - AutocompleteCommandPresenter(fragment.requireContext(), commandController) - } - - scope(ROOM_DETAIL_SCOPE) { (fragment: Fragment) -> - val userController = AutocompleteUserController() - AutocompleteUserPresenter(fragment.requireContext(), userController) - } - - } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigationViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigationViewModel.kt index d922f3ae..c678b5f5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigationViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigationViewModel.kt @@ -17,5 +17,6 @@ package im.vector.riotredesign.features.home import im.vector.riotredesign.core.mvrx.NavigationViewModel +import javax.inject.Inject -class HomeNavigationViewModel : NavigationViewModel() \ No newline at end of file +class HomeNavigationViewModel @Inject constructor() : NavigationViewModel() \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt index e46fd7f5..bc3b7bfb 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt @@ -24,11 +24,11 @@ import im.vector.riotredesign.core.extensions.replaceFragment import im.vector.riotredesign.features.navigation.Navigator import kotlinx.android.synthetic.main.activity_home.* import timber.log.Timber +import javax.inject.Inject -class HomeNavigator { +class HomeNavigator @Inject constructor() { var activity: HomeActivity? = null - private var rootRoomId: String? = null fun openSelectedGroup(groupSummary: GroupSummary) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomePermalinkHandler.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomePermalinkHandler.kt index dc387aa5..9041dec1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomePermalinkHandler.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomePermalinkHandler.kt @@ -20,9 +20,10 @@ import android.net.Uri import im.vector.matrix.android.api.permalinks.PermalinkData import im.vector.matrix.android.api.permalinks.PermalinkParser import im.vector.riotredesign.features.navigation.Navigator +import javax.inject.Inject -class HomePermalinkHandler(private val homeNavigator: HomeNavigator, - private val navigator: Navigator) { +class HomePermalinkHandler @Inject constructor(private val homeNavigator: HomeNavigator, + private val navigator: Navigator) { fun launch(deepLink: String?) { val uri = deepLink?.let { Uri.parse(it) } @@ -35,16 +36,16 @@ class HomePermalinkHandler(private val homeNavigator: HomeNavigator, } val permalinkData = PermalinkParser.parse(deepLink) when (permalinkData) { - is PermalinkData.EventLink -> { + is PermalinkData.EventLink -> { homeNavigator.openRoomDetail(permalinkData.roomIdOrAlias, permalinkData.eventId, navigator) } - is PermalinkData.RoomLink -> { + is PermalinkData.RoomLink -> { homeNavigator.openRoomDetail(permalinkData.roomIdOrAlias, null, navigator) } - is PermalinkData.GroupLink -> { + is PermalinkData.GroupLink -> { homeNavigator.openGroupDetail(permalinkData.groupId) } - is PermalinkData.UserLink -> { + is PermalinkData.UserLink -> { homeNavigator.openUserDetail(permalinkData.userId) } is PermalinkData.FallbackLink -> { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt index 9eaa47a7..e455961f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt @@ -21,8 +21,11 @@ import im.vector.riotredesign.core.utils.RxStore import im.vector.riotredesign.features.home.room.list.RoomListDisplayModeFilter import im.vector.riotredesign.features.home.room.list.RoomListFragment import io.reactivex.Observable +import javax.inject.Inject +import javax.inject.Singleton -class HomeRoomListObservableStore : RxStore>() { +@Singleton +class HomeRoomListObservableStore @Inject constructor() : RxStore>() { fun observeFilteredBy(displayMode: RoomListFragment.DisplayMode): Observable> { return observe() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt index ba65cf72..58715088 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt @@ -27,7 +27,7 @@ import im.vector.riotredesign.core.platform.StateView import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.home.HomeNavigator import kotlinx.android.synthetic.main.fragment_group_list.* -import org.koin.android.ext.android.inject +import javax.inject.Inject class GroupListFragment : VectorBaseFragment(), GroupSummaryController.Callback { @@ -38,8 +38,10 @@ class GroupListFragment : VectorBaseFragment(), GroupSummaryController.Callback } private val viewModel: GroupListViewModel by fragmentViewModel() - private val homeNavigator by inject() - private val groupController by inject() + + @Inject lateinit var groupListViewModelFactory: GroupListViewModel.Factory + @Inject lateinit var homeNavigator: HomeNavigator + @Inject lateinit var groupController: GroupSummaryController override fun getLayoutResId() = R.layout.fragment_group_list diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt index c06cbe5e..d6095f03 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt @@ -19,8 +19,11 @@ package im.vector.riotredesign.features.home.group import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import arrow.core.Option +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.rx.rx @@ -28,24 +31,27 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.core.utils.LiveEvent -import org.koin.android.ext.android.get const val ALL_COMMUNITIES_GROUP_ID = "ALL_COMMUNITIES_GROUP_ID" -class GroupListViewModel(initialState: GroupListViewState, - private val selectedGroupHolder: SelectedGroupStore, - private val session: Session, - private val stringProvider: StringProvider +class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState, + private val selectedGroupHolder: SelectedGroupStore, + private val session: Session, + private val stringProvider: StringProvider ) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: GroupListViewState): GroupListViewModel + } + companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: GroupListViewState): GroupListViewModel? { - val currentSession = viewModelContext.activity.get() - val selectedGroupHolder = viewModelContext.activity.get() - val stringProvider = viewModelContext.activity.get() - return GroupListViewModel(state, selectedGroupHolder, currentSession, stringProvider) + val groupListFragment: GroupListFragment = (viewModelContext as FragmentViewModelContext).fragment() + return groupListFragment.groupListViewModelFactory.create(state) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt index fe40b162..e82afb54 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt @@ -18,8 +18,9 @@ package im.vector.riotredesign.features.home.group import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.group.model.GroupSummary +import javax.inject.Inject -class GroupSummaryController : TypedEpoxyController() { +class GroupSummaryController @Inject constructor(): TypedEpoxyController() { var callback: Callback? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupStore.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupStore.kt index 5ee3cc4b..5bd0cc4e 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupStore.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupStore.kt @@ -19,5 +19,8 @@ package im.vector.riotredesign.features.home.group import arrow.core.Option import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.riotredesign.core.utils.RxStore +import javax.inject.Inject +import javax.inject.Singleton -class SelectedGroupStore : RxStore>(Option.empty()) +@Singleton +class SelectedGroupStore @Inject constructor() : RxStore>(Option.empty()) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index 1cabc032..16124ccc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -57,7 +57,13 @@ import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary import im.vector.matrix.android.api.session.room.model.Membership -import im.vector.matrix.android.api.session.room.model.message.* +import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent +import im.vector.matrix.android.api.session.room.model.message.MessageContent +import im.vector.matrix.android.api.session.room.model.message.MessageFileContent +import im.vector.matrix.android.api.session.room.model.message.MessageImageContent +import im.vector.matrix.android.api.session.room.model.message.MessageTextContent +import im.vector.matrix.android.api.session.room.model.message.MessageType +import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.user.model.User import im.vector.riotredesign.R @@ -67,13 +73,19 @@ import im.vector.riotredesign.core.extensions.hideKeyboard import im.vector.riotredesign.core.extensions.observeEvent import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.platform.VectorBaseFragment -import im.vector.riotredesign.core.utils.* +import im.vector.riotredesign.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA +import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA +import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA +import im.vector.riotredesign.core.utils.checkPermissions +import im.vector.riotredesign.core.utils.copyToClipboard +import im.vector.riotredesign.core.utils.openCamera +import im.vector.riotredesign.core.utils.shareMedia import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter import im.vector.riotredesign.features.autocomplete.command.CommandAutocompletePolicy import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter import im.vector.riotredesign.features.command.Command import im.vector.riotredesign.features.home.AvatarRenderer -import im.vector.riotredesign.features.home.HomeModule import im.vector.riotredesign.features.home.HomePermalinkHandler import im.vector.riotredesign.features.home.getColorFromUserId import im.vector.riotredesign.features.home.room.detail.composer.TextComposerActions @@ -99,14 +111,11 @@ import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_room_detail.* import kotlinx.android.synthetic.main.merge_composer_layout.view.* import org.commonmark.parser.Parser -import org.koin.android.ext.android.inject -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope -import org.koin.core.parameter.parametersOf import ru.noties.markwon.Markwon import ru.noties.markwon.html.HtmlPlugin import timber.log.Timber import java.io.File +import javax.inject.Inject @Parcelize @@ -156,19 +165,21 @@ class RoomDetailFragment : } private val roomDetailArgs: RoomDetailArgs by args() - private val session by inject() private val glideRequests by lazy { GlideApp.with(this) } private val roomDetailViewModel: RoomDetailViewModel by fragmentViewModel() private val textComposerViewModel: TextComposerViewModel by fragmentViewModel() - private val timelineEventController: TimelineEventController by inject { parametersOf(this) } - private val commandAutocompletePolicy = CommandAutocompletePolicy() - private val autocompleteCommandPresenter: AutocompleteCommandPresenter by inject { parametersOf(this) } - private val autocompleteUserPresenter: AutocompleteUserPresenter by inject { parametersOf(this) } - private val homePermalinkHandler: HomePermalinkHandler by inject() + @Inject lateinit var session: Session + @Inject lateinit var timelineEventController: TimelineEventController + @Inject lateinit var commandAutocompletePolicy: CommandAutocompletePolicy + @Inject lateinit var autocompleteCommandPresenter: AutocompleteCommandPresenter + @Inject lateinit var autocompleteUserPresenter: AutocompleteUserPresenter + @Inject lateinit var homePermalinkHandler: HomePermalinkHandler + @Inject lateinit var roomDetailViewModelFactory: RoomDetailViewModel.Factory + @Inject lateinit var textComposerViewModelFactory: TextComposerViewModel.Factory private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback override fun getLayoutResId() = R.layout.fragment_room_detail @@ -179,9 +190,9 @@ class RoomDetailFragment : lateinit var composerLayout: TextComposerView override fun onActivityCreated(savedInstanceState: Bundle?) { + injector().inject(this) super.onActivityCreated(savedInstanceState) actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java) - bindScope(getOrCreateScope(HomeModule.ROOM_DETAIL_SCOPE)) setupToolbar(roomToolbar) setupRecyclerView() setupComposer() @@ -229,18 +240,18 @@ class RoomDetailFragment : //TODO this is used at several places, find way to refactor? val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel() - ?: event.root.content.toModel() + ?: event.root.content.toModel() val nonFormattedBody = messageContent?.body ?: "" var formattedBody: CharSequence? = null if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) { val parser = Parser.builder().build() val document = parser.parse(messageContent.formattedBody - ?: messageContent.body) + ?: messageContent.body) formattedBody = Markwon.builder(requireContext()) .usePlugin(HtmlPlugin.create()).build().render(document) } composerLayout.composerRelatedMessageContent.text = formattedBody - ?: nonFormattedBody + ?: nonFormattedBody if (mode == SendMode.EDIT) { @@ -256,7 +267,7 @@ class RoomDetailFragment : } AvatarRenderer.render(event.senderAvatar, event.root.sender - ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar) + ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar) composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length) composerLayout.expand { @@ -279,9 +290,9 @@ class RoomDetailFragment : REQUEST_FILES_REQUEST_CODE, TAKE_IMAGE_REQUEST_CODE -> handleMediaIntent(data) REACTION_SELECT_REQUEST_CODE -> { val eventId = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_EVENT_ID) - ?: return + ?: return val reaction = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_REACTION_RESULT) - ?: return + ?: return //TODO check if already reacted with that? roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction, eventId)) } @@ -363,7 +374,7 @@ class RoomDetailFragment : // Add the span val user = session.getUser(item.userId) - val span = PillImageSpan(glideRequests, context!!, item.userId, user) + val span = PillImageSpan(glideRequests, requireContext(), item.userId, user) span.bind(composerLayout.composerEditText) editable.setSpan(span, startIndex, startIndex + displayName.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) @@ -619,7 +630,7 @@ class RoomDetailFragment : } MessageMenuViewModel.ACTION_VIEW_REACTIONS -> { val messageInformationData = actionData.data as? MessageInformationData - ?: return + ?: return ViewReactionBottomSheet.newInstance(roomDetailArgs.roomId, messageInformationData) .show(requireActivity().supportFragmentManager, "DISPLAY_REACTIONS") } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt index 476ff99b..f78efbff 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt @@ -19,10 +19,13 @@ package im.vector.riotredesign.features.home.room.detail import android.text.TextUtils import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.jakewharton.rxrelay2.BehaviorRelay +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.content.ContentAttachmentData @@ -41,14 +44,13 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.Timeline import io.reactivex.rxkotlin.subscribeBy import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer -import org.koin.android.ext.android.get import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.TimeUnit -class RoomDetailViewModel(initialState: RoomDetailViewState, - private val session: Session +class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: RoomDetailViewState, + private val session: Session ) : VectorViewModel(initialState) { private val room = session.getRoom(initialState.roomId)!! @@ -62,14 +64,19 @@ class RoomDetailViewModel(initialState: RoomDetailViewState, } private val timeline = room.createTimeline(eventId, allowedTypes) + @AssistedInject.Factory + interface Factory { + fun create(initialState: RoomDetailViewState): RoomDetailViewModel + } + companion object : MvRxViewModelFactory { const val PAGINATION_COUNT = 50 @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? { - val currentSession = viewModelContext.activity.get() - return RoomDetailViewModel(state, currentSession) + val fragment: RoomDetailFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.roomDetailViewModelFactory.create(state) } } @@ -201,7 +208,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState, } SendMode.EDIT -> { room.editTextMessage(state.selectedEvent?.root?.eventId - ?: "", action.text, action.autoMarkdown) + ?: "", action.text, action.autoMarkdown) setState { copy( sendMode = SendMode.REGULAR, @@ -213,7 +220,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState, SendMode.QUOTE -> { val messageContent: MessageContent? = state.selectedEvent?.annotations?.editSummary?.aggregatedContent?.toModel() - ?: state.selectedEvent?.root?.content.toModel() + ?: state.selectedEvent?.root?.content.toModel() val textMsg = messageContent?.body val finalText = legacyRiotQuoteText(textMsg, action.text) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/composer/TextComposerViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/composer/TextComposerViewModel.kt index 41c09a19..ef378a29 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/composer/TextComposerViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/composer/TextComposerViewModel.kt @@ -17,35 +17,44 @@ package im.vector.riotredesign.features.home.room.detail.composer import arrow.core.Option +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import com.jakewharton.rxrelay2.BehaviorRelay +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.user.model.User import im.vector.matrix.rx.rx import im.vector.riotredesign.core.platform.VectorViewModel +import im.vector.riotredesign.features.home.room.detail.RoomDetailFragment import io.reactivex.Observable import io.reactivex.functions.BiFunction -import org.koin.android.ext.android.get import java.util.concurrent.TimeUnit typealias AutocompleteUserQuery = CharSequence -class TextComposerViewModel(initialState: TextComposerViewState, - private val session: Session +class TextComposerViewModel @AssistedInject constructor(@Assisted initialState: TextComposerViewState, + private val session: Session ) : VectorViewModel(initialState) { + private val room = session.getRoom(initialState.roomId)!! private val roomId = initialState.roomId private val usersQueryObservable = BehaviorRelay.create>() + @AssistedInject.Factory + interface Factory { + fun create(initialState: TextComposerViewState): TextComposerViewModel + } + companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: TextComposerViewState): TextComposerViewModel? { - val currentSession = viewModelContext.activity.get() - return TextComposerViewModel(state, currentSession) + val fragment : RoomDetailFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.textComposerViewModelFactory.create(state) } } @@ -80,7 +89,7 @@ class TextComposerViewModel(initialState: TextComposerViewState, } else { users.filter { it.displayName?.startsWith(prefix = filter, ignoreCase = true) - ?: false + ?: false } } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index 5b325c4a..d4505b40 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -25,13 +25,25 @@ import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyModel import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary -import im.vector.matrix.android.api.session.room.model.message.* +import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent +import im.vector.matrix.android.api.session.room.model.message.MessageContent +import im.vector.matrix.android.api.session.room.model.message.MessageFileContent +import im.vector.matrix.android.api.session.room.model.message.MessageImageContent +import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.core.epoxy.LoadingItem_ import im.vector.riotredesign.core.extensions.localDateTime import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.helper.* +import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter +import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback +import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener +import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider +import im.vector.riotredesign.features.home.room.detail.timeline.helper.canBeMerged +import im.vector.riotredesign.features.home.room.detail.timeline.helper.nextDisplayableEvent +import im.vector.riotredesign.features.home.room.detail.timeline.helper.prevSameTypeEvents +import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar +import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_ import im.vector.riotredesign.features.home.room.detail.timeline.item.MergedHeaderItem @@ -39,11 +51,12 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInf import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.VideoContentRenderer import org.threeten.bp.LocalDateTime +import javax.inject.Inject -class TimelineEventController(private val dateFormatter: TimelineDateFormatter, - private val timelineItemFactory: TimelineItemFactory, - private val timelineMediaSizeProvider: TimelineMediaSizeProvider, - private val backgroundHandler: Handler = TimelineAsyncHelper.getBackgroundHandler() +class TimelineEventController @Inject constructor(private val dateFormatter: TimelineDateFormatter, + private val timelineItemFactory: TimelineItemFactory, + private val timelineMediaSizeProvider: TimelineMediaSizeProvider, + @TimelineEventControllerHandler private val backgroundHandler: Handler ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener { interface Callback : ReactionPillCallback, AvatarCallback, BaseCallback { @@ -175,8 +188,8 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, // Should be build if not cached or if cached but contains mergedHeader or formattedDay // We then are sure we always have items up to date. if (modelCache[position] == null - || modelCache[position]?.mergedHeaderModel != null - || modelCache[position]?.formattedDayModel != null) { + || modelCache[position]?.mergedHeaderModel != null + || modelCache[position]?.formattedDayModel != null) { modelCache[position] = buildItemModels(position, currentSnapshot) } } @@ -248,7 +261,7 @@ class TimelineEventController(private val dateFormatter: TimelineDateFormatter, // => handle case where paginating from mergeable events and we get more val previousCollapseStateKey = mergedEventIds.intersect(mergeItemCollapseStates.keys).firstOrNull() val initialCollapseState = mergeItemCollapseStates.remove(previousCollapseStateKey) - ?: true + ?: true val isCollapsed = mergeItemCollapseStates.getOrPut(event.localId) { initialCollapseState } if (isCollapsed) { collapsedEventIds.addAll(mergedEventIds) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventControllerHandler.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventControllerHandler.kt new file mode 100644 index 00000000..7ac38d97 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventControllerHandler.kt @@ -0,0 +1,23 @@ +/* + * 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.room.detail.timeline + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class TimelineEventControllerHandler diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ActionsHandler.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ActionsHandler.kt index 84cfc40f..1755fe6b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ActionsHandler.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/ActionsHandler.kt @@ -18,11 +18,12 @@ package im.vector.riotredesign.features.home.room.detail.timeline.action import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import im.vector.riotredesign.core.utils.LiveEvent +import javax.inject.Inject /** * Activity shared view model to handle message actions */ -class ActionsHandler : ViewModel() { +class ActionsHandler @Inject constructor() : ViewModel() { data class ActionData( val actionId: String, diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt index 9c9bbc2d..9a321c24 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt @@ -36,6 +36,7 @@ import im.vector.riotredesign.R import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import kotlinx.android.synthetic.main.bottom_sheet_message_actions.* +import javax.inject.Inject /** * Bottom sheet fragment that shows a message preview with list of contextual actions @@ -43,6 +44,7 @@ import kotlinx.android.synthetic.main.bottom_sheet_message_actions.* */ class MessageActionsBottomSheet : BaseMvRxBottomSheetDialog() { + @Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class) private lateinit var actionHandlerModel: ActionsHandler diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 998ddf81..7cb3164f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -19,6 +19,8 @@ import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel @@ -27,17 +29,16 @@ import im.vector.matrix.android.api.session.room.model.message.MessageTextConten import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter -import org.commonmark.parser.Parser -import org.koin.android.ext.android.get -import org.koin.core.parameter.parametersOf -import ru.noties.markwon.Markwon -import ru.noties.markwon.html.HtmlPlugin -import timber.log.Timber +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData +import im.vector.riotredesign.features.html.EventHtmlRenderer import java.text.SimpleDateFormat import java.util.* data class MessageActionState( + val roomId: String, + val eventId: String, + val informationData: MessageInformationData, val userId: String = "", val senderName: String = "", val messageBody: CharSequence? = null, @@ -45,64 +46,77 @@ data class MessageActionState( val showPreview: Boolean = false, val canReact: Boolean = false, val senderAvatarPath: String? = null) - : MvRxState + : MvRxState { + + constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData) + +} /** * Information related to an event and used to display preview in contextual bottomsheet. */ -class MessageActionsViewModel(initialState: MessageActionState) : VectorViewModel(initialState) { +class MessageActionsViewModel @AssistedInject constructor(@Assisted initialState: MessageActionState, + private val eventHtmlRenderer: EventHtmlRenderer, + private val session: Session, + private val noticeEventFormatter: NoticeEventFormatter +) : VectorViewModel(initialState) { + + private val roomId = initialState.roomId + private val eventId = initialState.eventId + private val informationData = initialState.informationData + + @AssistedInject.Factory + interface Factory { + fun create(initialState: MessageActionState): MessageActionsViewModel + } companion object : MvRxViewModelFactory { - override fun initialState(viewModelContext: ViewModelContext): MessageActionState? { - val currentSession = viewModelContext.activity.get() - val fragment = (viewModelContext as? FragmentViewModelContext)?.fragment - val noticeFormatter = fragment?.get(parameters = { parametersOf(fragment) }) - val parcel = viewModelContext.args as TimelineEventFragmentArgs - - val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault()) - - val event = currentSession.getRoom(parcel.roomId)?.getTimeLineEvent(parcel.eventId) - var body: CharSequence? = null - val originTs = event?.root?.originServerTs - return if (event != null) { - when (event.root.type) { - EventType.MESSAGE -> { - val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel() - ?: event.root.content.toModel() - body = messageContent?.body - if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) { - val parser = Parser.builder().build() - val document = parser.parse(messageContent.formattedBody - ?: messageContent.body) - body = Markwon.builder(viewModelContext.activity) - .usePlugin(HtmlPlugin.create()).build().render(document) - } - } - EventType.STATE_ROOM_NAME, - EventType.STATE_ROOM_TOPIC, - EventType.STATE_ROOM_MEMBER, - EventType.STATE_HISTORY_VISIBILITY, - EventType.CALL_INVITE, - EventType.CALL_HANGUP, - EventType.CALL_ANSWER -> { - body = noticeFormatter?.format(event) - } - } - MessageActionState( - userId = event.root.sender ?: "", - senderName = parcel.informationData.memberName?.toString() ?: "", - messageBody = body, - ts = dateFormat.format(Date(originTs ?: 0)), - showPreview = body != null, - canReact = event.root.type == EventType.MESSAGE && event.sendState.isSent(), - senderAvatarPath = parcel.informationData.avatarUrl - ) - } else { - //can this happen? - Timber.e("Failed to retrieve event") - null - } + override fun create(viewModelContext: ViewModelContext, state: MessageActionState): MessageActionsViewModel? { + val fragment: MessageActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.messageActionViewModelFactory.create(state) } } + + + init { + setState { reduceState(this) } + } + + private fun reduceState(state: MessageActionState): MessageActionState { + val dateFormat = SimpleDateFormat("EEE, d MMM yyyy HH:mm", Locale.getDefault()) + val event = session.getRoom(roomId)?.getTimeLineEvent(eventId) ?: return state + var body: CharSequence? = null + val originTs = event.root.originServerTs + when (event.root.type) { + EventType.MESSAGE -> { + val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel() + ?: event.root.content.toModel() + body = messageContent?.body + if (messageContent is MessageTextContent && messageContent.format == MessageType.FORMAT_MATRIX_HTML) { + body = eventHtmlRenderer.render(messageContent.formattedBody + ?: messageContent.body) + } + } + EventType.STATE_ROOM_NAME, + EventType.STATE_ROOM_TOPIC, + EventType.STATE_ROOM_MEMBER, + EventType.STATE_HISTORY_VISIBILITY, + EventType.CALL_INVITE, + EventType.CALL_HANGUP, + EventType.CALL_ANSWER -> { + body = noticeEventFormatter.format(event) + } + } + return state.copy( + userId = event.root.sender ?: "", + senderName = informationData.memberName?.toString() ?: "", + messageBody = body, + ts = dateFormat.format(Date(originTs ?: 0)), + showPreview = body != null, + canReact = event.root.type == EventType.MESSAGE && event.sendState.isSent(), + senderAvatarPath = informationData.avatarUrl + ) + } + } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuFragment.kt index 2b47eae3..116c792c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuFragment.kt @@ -29,16 +29,16 @@ import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.riotredesign.R import im.vector.riotredesign.features.themes.ThemeUtils +import javax.inject.Inject /** * Fragment showing the list of available contextual action for a given message. */ class MessageMenuFragment : BaseMvRxFragment() { + @Inject lateinit var messageMenuViewModelFactory: MessageMenuViewModel.Factory private val viewModel: MessageMenuViewModel by fragmentViewModel(MessageMenuViewModel::class) - private var addSeparators = false - var interactionListener: InteractionListener? = null override fun invalidate() = withState(viewModel) { state -> diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt index f74a953e..e4554143 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageMenuViewModel.kt @@ -15,9 +15,12 @@ */ package im.vector.riotredesign.features.home.room.detail.timeline.action +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toContent @@ -29,44 +32,76 @@ import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorViewModel +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import org.json.JSONObject -import org.koin.android.ext.android.get data class SimpleAction(val uid: String, val titleRes: Int, val iconResId: Int?, val data: Any? = null) -data class MessageMenuState(val actions: List = emptyList()) : MvRxState +data class MessageMenuState( + val roomId: String, + val eventId: String, + val informationData: MessageInformationData, + val actions: List = emptyList() +) : MvRxState { + + constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData) + +} /** * Manages list actions for a given message (copy / paste / forward...) */ -class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel(initialState) { +class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: MessageMenuState, + private val session: Session) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: MessageMenuState): MessageMenuViewModel + } companion object : MvRxViewModelFactory { - override fun initialState(viewModelContext: ViewModelContext): MessageMenuState? { - // Args are accessible from the context. - val currentSession = viewModelContext.activity.get() - val parcel = viewModelContext.args as TimelineEventFragmentArgs - val event = currentSession.getRoom(parcel.roomId)?.getTimeLineEvent(parcel.eventId) - ?: return null + const val ACTION_ADD_REACTION = "add_reaction" + const val ACTION_COPY = "copy" + const val ACTION_EDIT = "edit" + const val ACTION_QUOTE = "quote" + const val ACTION_REPLY = "reply" + const val ACTION_SHARE = "share" + const val ACTION_RESEND = "resend" + const val ACTION_DELETE = "delete" + const val VIEW_SOURCE = "VIEW_SOURCE" + const val VIEW_DECRYPTED_SOURCE = "VIEW_DECRYPTED_SOURCE" + const val ACTION_COPY_PERMALINK = "ACTION_COPY_PERMALINK" + const val ACTION_FLAG = "ACTION_FLAG" + const val ACTION_QUICK_REACT = "ACTION_QUICK_REACT" + const val ACTION_VIEW_REACTIONS = "ACTION_VIEW_REACTIONS" - val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel() - ?: event.root.content.toModel() - val type = messageContent?.type + override fun create(viewModelContext: ViewModelContext, state: MessageMenuState): MessageMenuViewModel? { + val fragment: MessageMenuFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.messageMenuViewModelFactory.create(state) + } + } - if (!event.sendState.isSent()) { - //Resend and Delete - return MessageMenuState( - //TODO - listOf( + init { + setState { reduceState(this) } + } + + private fun reduceState(state: MessageMenuState): MessageMenuState { + val event = session.getRoom(state.roomId)?.getTimeLineEvent(state.eventId) ?: return state + + val messageContent: MessageContent? = event.annotations?.editSummary?.aggregatedContent?.toModel() + ?: event.root.content.toModel() + val type = messageContent?.type + + val actions = if (!event.sendState.isSent()) { + //Resend and Delete + listOf( // SimpleAction(ACTION_RESEND, R.string.resend, R.drawable.ic_send, event.root.eventId), // //TODO delete icon // SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_delete, event.root.eventId) - ) - ) - } - - val actions = ArrayList().apply { + ) + } else { + ArrayList().apply { if (event.sendState == SendState.SENDING) { //TODO add cancel? @@ -86,28 +121,28 @@ class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel true - else -> false + + private fun canReply(event: TimelineEvent, messageContent: MessageContent?): Boolean { + //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment + if (event.root.getClearType() != EventType.MESSAGE) return false + return when (messageContent?.type) { + MessageType.MSGTYPE_TEXT, + MessageType.MSGTYPE_NOTICE, + MessageType.MSGTYPE_EMOTE, + MessageType.MSGTYPE_IMAGE, + MessageType.MSGTYPE_VIDEO, + MessageType.MSGTYPE_AUDIO, + MessageType.MSGTYPE_FILE -> true + else -> false + } + } + + private fun canReact(event: TimelineEvent, messageContent: MessageContent?): Boolean { + //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment + return event.root.getClearType() == EventType.MESSAGE + } + + private fun canQuote(event: TimelineEvent, messageContent: MessageContent?): Boolean { + //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment + if (event.root.getClearType() != EventType.MESSAGE) return false + return when (messageContent?.type) { + MessageType.MSGTYPE_TEXT, + MessageType.MSGTYPE_NOTICE, + MessageType.MSGTYPE_EMOTE, + MessageType.FORMAT_MATRIX_HTML, + MessageType.MSGTYPE_LOCATION -> { + true } + else -> false } + } - private fun canReact(event: TimelineEvent, messageContent: MessageContent?): Boolean { - //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment - return event.root.getClearType() == EventType.MESSAGE - } + private fun canRedact(event: TimelineEvent, myUserId: String): Boolean { + //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment + if (event.root.getClearType() != EventType.MESSAGE) return false + //TODO if user is admin or moderator + return event.root.sender == myUserId + } - private fun canQuote(event: TimelineEvent, messageContent: MessageContent?): Boolean { - //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment - if (event.root.getClearType() != EventType.MESSAGE) return false - return when (messageContent?.type) { - MessageType.MSGTYPE_TEXT, - MessageType.MSGTYPE_NOTICE, - MessageType.MSGTYPE_EMOTE, - MessageType.FORMAT_MATRIX_HTML, - MessageType.MSGTYPE_LOCATION -> { - true - } - else -> false + private fun canViewReactions(event: TimelineEvent): Boolean { + //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment + if (event.root.getClearType() != EventType.MESSAGE) return false + //TODO if user is admin or moderator + return event.annotations?.reactionsSummary?.isNotEmpty() ?: false + } + + private fun canEdit(event: TimelineEvent, myUserId: String): Boolean { + //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment + if (event.root.getClearType() != EventType.MESSAGE) return false + //TODO if user is admin or moderator + val messageContent = event.root.content.toModel() + return event.root.sender == myUserId && ( + messageContent?.type == MessageType.MSGTYPE_TEXT + || messageContent?.type == MessageType.MSGTYPE_EMOTE + ) + } + + + private fun canCopy(type: String?): Boolean { + return when (type) { + MessageType.MSGTYPE_TEXT, + MessageType.MSGTYPE_NOTICE, + MessageType.MSGTYPE_EMOTE, + MessageType.FORMAT_MATRIX_HTML, + MessageType.MSGTYPE_LOCATION -> { + true } + else -> false } - - private fun canRedact(event: TimelineEvent, myUserId: String): Boolean { - //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment - if (event.root.getClearType() != EventType.MESSAGE) return false - //TODO if user is admin or moderator - return event.root.sender == myUserId - } - - private fun canViewReactions(event: TimelineEvent): Boolean { - //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment - if (event.root.getClearType() != EventType.MESSAGE) return false - //TODO if user is admin or moderator - return event.annotations?.reactionsSummary?.isNotEmpty() ?: false - } - - private fun canEdit(event: TimelineEvent, myUserId: String): Boolean { - //Only event of type Event.EVENT_TYPE_MESSAGE are supported for the moment - if (event.root.getClearType() != EventType.MESSAGE) return false - //TODO if user is admin or moderator - val messageContent = event.root.content.toModel() - return event.root.sender == myUserId && ( - messageContent?.type == MessageType.MSGTYPE_TEXT - || messageContent?.type == MessageType.MSGTYPE_EMOTE - ) - } + } - private fun canCopy(type: String?): Boolean { - return when (type) { - MessageType.MSGTYPE_TEXT, - MessageType.MSGTYPE_NOTICE, - MessageType.MSGTYPE_EMOTE, - MessageType.FORMAT_MATRIX_HTML, - MessageType.MSGTYPE_LOCATION -> { - true - } - else -> false + private fun canShare(type: String?): Boolean { + return when (type) { + MessageType.MSGTYPE_IMAGE, + MessageType.MSGTYPE_AUDIO, + MessageType.MSGTYPE_VIDEO -> { + true } + else -> false } - - - private fun canShare(type: String?): Boolean { - return when (type) { - MessageType.MSGTYPE_IMAGE, - MessageType.MSGTYPE_AUDIO, - MessageType.MSGTYPE_VIDEO -> { - true - } - else -> false - } - } - - const val ACTION_ADD_REACTION = "add_reaction" - const val ACTION_COPY = "copy" - const val ACTION_EDIT = "edit" - const val ACTION_QUOTE = "quote" - const val ACTION_REPLY = "reply" - const val ACTION_SHARE = "share" - const val ACTION_RESEND = "resend" - const val ACTION_DELETE = "delete" - const val VIEW_SOURCE = "VIEW_SOURCE" - const val VIEW_DECRYPTED_SOURCE = "VIEW_DECRYPTED_SOURCE" - const val ACTION_COPY_PERMALINK = "ACTION_COPY_PERMALINK" - const val ACTION_FLAG = "ACTION_FLAG" - const val ACTION_QUICK_REACT = "ACTION_QUICK_REACT" - const val ACTION_VIEW_REACTIONS = "ACTION_VIEW_REACTIONS" - - } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionFragment.kt index b1074480..96d7052c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionFragment.kt @@ -31,7 +31,7 @@ import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.riotredesign.EmojiCompatFontProvider import im.vector.riotredesign.R -import org.koin.android.ext.android.inject +import javax.inject.Inject /** * Quick Reaction Fragment (agree / like reactions) @@ -57,7 +57,8 @@ class QuickReactionFragment : BaseMvRxFragment() { var interactionListener: InteractionListener? = null - val fontProvider by inject() + @Inject lateinit var fontProvider: EmojiCompatFontProvider + @Inject lateinit var quickReactionViewModelFactory: QuickReactionViewModel.Factory override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.adapter_item_action_quick_reaction, container, false) @@ -68,10 +69,10 @@ class QuickReactionFragment : BaseMvRxFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - quickReact1Text.text = QuickReactionViewModel.agreePositive - quickReact2Text.text = QuickReactionViewModel.agreeNegative - quickReact3Text.text = QuickReactionViewModel.likePositive - quickReact4Text.text = QuickReactionViewModel.likeNegative + quickReact1Text.text = QuickReactionViewModel.AGREE_POSITIVE + quickReact2Text.text = QuickReactionViewModel.AGREE_NEGATIVE + quickReact3Text.text = QuickReactionViewModel.LIKE_POSITIVE + quickReact4Text.text = QuickReactionViewModel.LIKE_NEGATIVE listOf(quickReact1Text, quickReact2Text, quickReact3Text, quickReact4Text).forEach { it.typeface = fontProvider.typeface ?: Typeface.DEFAULT @@ -96,7 +97,7 @@ class QuickReactionFragment : BaseMvRxFragment() { override fun invalidate() = withState(viewModel) { TransitionManager.beginDelayedTransition(rootLayout) - when (it.agreeTrigleState) { + when (it.agreeTriggleState) { TriggleState.NONE -> { quickReact1Text.alpha = 1f quickReact2Text.alpha = 1f @@ -130,7 +131,7 @@ class QuickReactionFragment : BaseMvRxFragment() { if (it.selectionResult != null) { val clikedOn = it.selectionResult.first interactionListener?.didQuickReactWith(clikedOn, QuickReactionViewModel.getOpposite(clikedOn) - ?: "", it.selectionResult.second, it.eventId) + ?: "", it.selectionResult.second, it.eventId) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionViewModel.kt index 5252e51b..91abbb05 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/QuickReactionViewModel.kt @@ -15,12 +15,15 @@ */ package im.vector.riotredesign.features.home.room.detail.timeline.action +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.riotredesign.core.platform.VectorViewModel -import org.koin.android.ext.android.get +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData /** * Quick reactions state, it's a toggle with 3rd state @@ -32,33 +35,99 @@ enum class TriggleState { } data class QuickReactionState( - val agreeTrigleState: TriggleState = TriggleState.NONE, + val roomId: String, + val eventId: String, + val informationData: MessageInformationData, + val agreeTriggleState: TriggleState = TriggleState.NONE, val likeTriggleState: TriggleState = TriggleState.NONE, /** Pair of 'clickedOn' and current toggles state*/ - val selectionResult: Pair>? = null, - val eventId: String = "") : MvRxState + val selectionResult: Pair>? = null +) : MvRxState { + + constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData) + +} + /** * Quick reaction view model */ -class QuickReactionViewModel(initialState: QuickReactionState) : VectorViewModel(initialState) { +class QuickReactionViewModel @AssistedInject constructor(@Assisted initialState: QuickReactionState, + private val session: Session) : VectorViewModel(initialState) { + @AssistedInject.Factory + interface Factory { + fun create(initialState: QuickReactionState): QuickReactionViewModel + } + + companion object : MvRxViewModelFactory { + + const val AGREE_POSITIVE = "👍" + const val AGREE_NEGATIVE = "👎" + const val LIKE_POSITIVE = "🙂" + const val LIKE_NEGATIVE = "😔" + + fun getOpposite(reaction: String): String? { + return when (reaction) { + AGREE_POSITIVE -> AGREE_NEGATIVE + AGREE_NEGATIVE -> AGREE_POSITIVE + LIKE_POSITIVE -> LIKE_NEGATIVE + LIKE_NEGATIVE -> LIKE_POSITIVE + else -> null + } + } + + override fun create(viewModelContext: ViewModelContext, state: QuickReactionState): QuickReactionViewModel? { + val fragment: QuickReactionFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.quickReactionViewModelFactory.create(state) + } + } + + init { + setState { reduceState(this) } + } + + private fun reduceState(state: QuickReactionState): QuickReactionState { + val event = session.getRoom(state.roomId)?.getTimeLineEvent(state.eventId) ?: return state + var agreeTriggle: TriggleState = TriggleState.NONE + var likeTriggle: TriggleState = TriggleState.NONE + event.annotations?.reactionsSummary?.forEach { + //it.addedByMe + if (it.addedByMe) { + if (AGREE_POSITIVE == it.key) { + agreeTriggle = TriggleState.FIRST + } else if (AGREE_NEGATIVE == it.key) { + agreeTriggle = TriggleState.SECOND + } + + if (LIKE_POSITIVE == it.key) { + likeTriggle = TriggleState.FIRST + } else if (LIKE_NEGATIVE == it.key) { + likeTriggle = TriggleState.SECOND + } + } + } + return state.copy( + agreeTriggleState = agreeTriggle, + likeTriggleState = likeTriggle + ) + } fun toggleAgree(isFirst: Boolean) = withState { if (isFirst) { setState { - val newTriggle = if (it.agreeTrigleState == TriggleState.FIRST) TriggleState.NONE else TriggleState.FIRST + val newTriggle = if (it.agreeTriggleState == TriggleState.FIRST) TriggleState.NONE else TriggleState.FIRST copy( - agreeTrigleState = newTriggle, - selectionResult = Pair(agreePositive, getReactions(this, newTriggle, null)) + agreeTriggleState = newTriggle, + selectionResult = Pair(AGREE_POSITIVE, getReactions(this, newTriggle, null)) ) } } else { setState { - val newTriggle = if (it.agreeTrigleState == TriggleState.SECOND) TriggleState.NONE else TriggleState.SECOND + val newTriggle = if (it.agreeTriggleState == TriggleState.SECOND) TriggleState.NONE else TriggleState.SECOND copy( - agreeTrigleState = agreeTrigleState, - selectionResult = Pair(agreeNegative, getReactions(this, newTriggle, null)) + agreeTriggleState = agreeTriggleState, + selectionResult = Pair(AGREE_NEGATIVE, getReactions(this, newTriggle, null)) ) } } @@ -70,7 +139,7 @@ class QuickReactionViewModel(initialState: QuickReactionState) : VectorViewModel val newTriggle = if (it.likeTriggleState == TriggleState.FIRST) TriggleState.NONE else TriggleState.FIRST copy( likeTriggleState = newTriggle, - selectionResult = Pair(likePositive, getReactions(this, null, newTriggle)) + selectionResult = Pair(LIKE_POSITIVE, getReactions(this, null, newTriggle)) ) } } else { @@ -78,7 +147,7 @@ class QuickReactionViewModel(initialState: QuickReactionState) : VectorViewModel val newTriggle = if (it.likeTriggleState == TriggleState.SECOND) TriggleState.NONE else TriggleState.SECOND copy( likeTriggleState = newTriggle, - selectionResult = Pair(likeNegative, getReactions(this, null, newTriggle)) + selectionResult = Pair(LIKE_NEGATIVE, getReactions(this, null, newTriggle)) ) } } @@ -87,64 +156,17 @@ class QuickReactionViewModel(initialState: QuickReactionState) : VectorViewModel private fun getReactions(state: QuickReactionState, newState1: TriggleState?, newState2: TriggleState?): List { return ArrayList(4).apply { when (newState2 ?: state.likeTriggleState) { - TriggleState.FIRST -> add(likePositive) - TriggleState.SECOND -> add(likeNegative) + TriggleState.FIRST -> add(LIKE_POSITIVE) + TriggleState.SECOND -> add(LIKE_NEGATIVE) else -> { } } - when (newState1 ?: state.agreeTrigleState) { - TriggleState.FIRST -> add(agreePositive) - TriggleState.SECOND -> add(agreeNegative) + when (newState1 ?: state.agreeTriggleState) { + TriggleState.FIRST -> add(AGREE_POSITIVE) + TriggleState.SECOND -> add(AGREE_NEGATIVE) else -> { } } } } - - - companion object : MvRxViewModelFactory { - - val agreePositive = "👍" - val agreeNegative = "👎" - val likePositive = "🙂" - val likeNegative = "😔" - - fun getOpposite(reaction: String): String? { - return when (reaction) { - agreePositive -> agreeNegative - agreeNegative -> agreePositive - likePositive -> likeNegative - likeNegative -> likePositive - else -> null - } - } - - override fun initialState(viewModelContext: ViewModelContext): QuickReactionState? { - // Args are accessible from the context. - // val foo = vieWModelContext.args.foo - val currentSession = viewModelContext.activity.get() - val parcel = viewModelContext.args as TimelineEventFragmentArgs - val event = currentSession.getRoom(parcel.roomId)?.getTimeLineEvent(parcel.eventId) - ?: return null - var agreeTriggle: TriggleState = TriggleState.NONE - var likeTriggle: TriggleState = TriggleState.NONE - event.annotations?.reactionsSummary?.forEach { - //it.addedByMe - if (it.addedByMe) { - if (agreePositive == it.key) { - agreeTriggle = TriggleState.FIRST - } else if (agreeNegative == it.key) { - agreeTriggle = TriggleState.SECOND - } - - if (likePositive == it.key) { - likeTriggle = TriggleState.FIRST - } else if (likeNegative == it.key) { - likeTriggle = TriggleState.SECOND - } - } - } - return QuickReactionState(agreeTriggle, likeTriggle, null, event.root.eventId ?: "") - } - } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/DefaultItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/DefaultItemFactory.kt index c44af0ea..b64b6adc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/DefaultItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/DefaultItemFactory.kt @@ -19,8 +19,9 @@ package im.vector.riotredesign.features.home.room.detail.timeline.factory import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem_ +import javax.inject.Inject -class DefaultItemFactory { +class DefaultItemFactory @Inject constructor(){ fun create(event: TimelineEvent, exception: Exception? = null): DefaultItem? { val text = if (exception == null) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt index 4e892183..46f5b7eb 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt @@ -30,9 +30,10 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAv import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ +import javax.inject.Inject // This class handles timeline event who haven't been successfully decrypted -class EncryptedItemFactory(private val stringProvider: StringProvider) { +class EncryptedItemFactory @Inject constructor(private val stringProvider: StringProvider) { fun create(timelineEvent: TimelineEvent): VectorEpoxyModel<*>? { return when { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt index d0ca0ffc..cd8f34d5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt @@ -28,8 +28,9 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderNa import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ +import javax.inject.Inject -class EncryptionItemFactory(private val stringProvider: StringProvider) { +class EncryptionItemFactory @Inject constructor(private val stringProvider: StringProvider) { fun create(event: TimelineEvent): NoticeItem? { val text = buildNoticeText(event.root, event.senderName) ?: return null @@ -52,7 +53,7 @@ class EncryptionItemFactory(private val stringProvider: StringProvider) { val content = event.content.toModel() ?: return null stringProvider.getString(R.string.notice_end_to_end, senderName, content.algorithm) } - else -> null + else -> null } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt index a4b31251..9ddd4d34 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -29,7 +29,14 @@ import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.RelationType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary -import im.vector.matrix.android.api.session.room.model.message.* +import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent +import im.vector.matrix.android.api.session.room.model.message.MessageContent +import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent +import im.vector.matrix.android.api.session.room.model.message.MessageFileContent +import im.vector.matrix.android.api.session.room.model.message.MessageImageContent +import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent +import im.vector.matrix.android.api.session.room.model.message.MessageTextContent +import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.EmojiCompatFontProvider @@ -44,18 +51,32 @@ import im.vector.riotredesign.features.home.getColorFromUserId import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider -import im.vector.riotredesign.features.home.room.detail.timeline.item.* +import im.vector.riotredesign.features.home.room.detail.timeline.item.BlankItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem +import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageFileItem +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageFileItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageVideoItem +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageVideoItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem +import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.ReactionInfoData +import im.vector.riotredesign.features.home.room.detail.timeline.item.RedactedMessageItem +import im.vector.riotredesign.features.home.room.detail.timeline.item.RedactedMessageItem_ import im.vector.riotredesign.features.html.EventHtmlRenderer import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.VideoContentRenderer import me.gujun.android.span.span +import javax.inject.Inject -class MessageItemFactory(private val colorProvider: ColorProvider, - private val timelineMediaSizeProvider: TimelineMediaSizeProvider, - private val timelineDateFormatter: TimelineDateFormatter, - private val htmlRenderer: EventHtmlRenderer, - private val stringProvider: StringProvider, - private val emojiCompatFontProvider: EmojiCompatFontProvider) { +class MessageItemFactory @Inject constructor( + private val colorProvider: ColorProvider, + private val timelineMediaSizeProvider: TimelineMediaSizeProvider, + private val timelineDateFormatter: TimelineDateFormatter, + private val htmlRenderer: EventHtmlRenderer, + private val stringProvider: StringProvider, + private val emojiCompatFontProvider: EmojiCompatFontProvider) { fun create(event: TimelineEvent, nextEvent: TimelineEvent?, @@ -68,33 +89,33 @@ class MessageItemFactory(private val colorProvider: ColorProvider, val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60)) - ?: false + ?: false val showInformation = addDaySeparator - || event.senderAvatar != nextEvent?.senderAvatar - || event.senderName != nextEvent?.senderName - || nextEvent?.root?.getClearType() != EventType.MESSAGE - || isNextMessageReceivedMoreThanOneHourAgo + || event.senderAvatar != nextEvent?.senderAvatar + || event.senderName != nextEvent?.senderName + || nextEvent?.root?.getClearType() != EventType.MESSAGE + || isNextMessageReceivedMoreThanOneHourAgo val time = timelineDateFormatter.formatMessageHour(date) val avatarUrl = event.senderAvatar val memberName = event.senderName ?: event.root.sender ?: "" val formattedMemberName = span(memberName) { textColor = colorProvider.getColor(getColorFromUserId(event.root.sender - ?: "")) + ?: "")) } val hasBeenEdited = event.annotations?.editSummary != null val informationData = MessageInformationData(eventId = eventId, - senderId = event.root.sender ?: "", - sendState = event.sendState, - time = time, - avatarUrl = avatarUrl, - memberName = formattedMemberName, - showInformation = showInformation, - orderedReactionList = event.annotations?.reactionsSummary?.map { - ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty()) - }, - hasBeenEdited = hasBeenEdited + senderId = event.root.sender ?: "", + sendState = event.sendState, + time = time, + avatarUrl = avatarUrl, + memberName = formattedMemberName, + showInformation = showInformation, + orderedReactionList = event.annotations?.reactionsSummary?.map { + ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty()) + }, + hasBeenEdited = hasBeenEdited ) if (event.root.unsignedData?.redactedEvent != null) { @@ -104,9 +125,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider, val messageContent: MessageContent = event.annotations?.editSummary?.aggregatedContent?.toModel() - ?: event.root.getClearContent().toModel() - ?: //Malformed content, we should echo something on screen - return DefaultItem_().text(stringProvider.getString(R.string.malformed_message)) + ?: event.root.getClearContent().toModel() + ?: //Malformed content, we should echo something on screen + return DefaultItem_().text(stringProvider.getString(R.string.malformed_message)) if (messageContent.relatesTo?.type == RelationType.REPLACE) { // ignore replace event, the targeted id is already edited @@ -116,16 +137,16 @@ class MessageItemFactory(private val colorProvider: ColorProvider, // val ev = all.toModel() return when (messageContent) { is MessageEmoteContent -> buildEmoteMessageItem(messageContent, - informationData, - hasBeenEdited, - event.annotations?.editSummary, - callback) + informationData, + hasBeenEdited, + event.annotations?.editSummary, + callback) is MessageTextContent -> buildTextMessageItem(event.sendState, - messageContent, - informationData, - hasBeenEdited, - event.annotations?.editSummary, - callback + messageContent, + informationData, + hasBeenEdited, + event.annotations?.editSummary, + callback ) is MessageImageContent -> buildImageMessageItem(messageContent, informationData, callback) is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback) @@ -156,7 +177,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -176,7 +197,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } .clickListener( DebouncedClickListener(View.OnClickListener { _ -> @@ -221,7 +242,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -259,7 +280,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, .clickListener { view -> callback?.onVideoMessageClicked(messageContent, videoData, view) } .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -296,7 +317,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -328,9 +349,9 @@ class MessageItemFactory(private val colorProvider: ColorProvider, //nop } }, - editStart, - editEnd, - Spanned.SPAN_INCLUSIVE_EXCLUSIVE) + editStart, + editEnd, + Spanned.SPAN_INCLUSIVE_EXCLUSIVE) return spannable } @@ -362,7 +383,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -395,7 +416,7 @@ class MessageItemFactory(private val colorProvider: ColorProvider, })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt index dabebd28..00d8070f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt @@ -24,8 +24,9 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderNa import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ +import javax.inject.Inject -class NoticeItemFactory(private val eventFormatter: NoticeEventFormatter) { +class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter) { fun create(event: TimelineEvent, callback: TimelineEventController.Callback?): NoticeItem? { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index c4609f88..6db6a2a2 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -28,12 +28,13 @@ import im.vector.riotredesign.features.home.room.detail.timeline.helper.Timeline import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_ import timber.log.Timber +import javax.inject.Inject -class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, - private val encryptionItemFactory: EncryptionItemFactory, - private val encryptedItemFactory: EncryptedItemFactory, - private val noticeItemFactory: NoticeItemFactory, - private val defaultItemFactory: DefaultItemFactory) { +class TimelineItemFactory @Inject constructor(private val messageItemFactory: MessageItemFactory, + private val encryptionItemFactory: EncryptionItemFactory, + private val encryptedItemFactory: EncryptedItemFactory, + private val noticeItemFactory: NoticeItemFactory, + private val defaultItemFactory: DefaultItemFactory) { fun create(event: TimelineEvent, nextEvent: TimelineEvent?, @@ -64,22 +65,23 @@ class TimelineItemFactory(private val messageItemFactory: MessageItemFactory, //These are just for debug to display hidden event, they should be filtered out in normal mode if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) { val informationData = MessageInformationData(eventId = event.root.eventId - ?: "?", - senderId = event.root.sender ?: "", - sendState = event.sendState, - time = "", - avatarUrl = null, - memberName = "", - showInformation = false + ?: "?", + senderId = event.root.sender + ?: "", + sendState = event.sendState, + time = "", + avatarUrl = null, + memberName = "", + showInformation = false ) val messageContent = event.root.content.toModel() - ?: MessageDefaultContent("", "", null, null) + ?: MessageDefaultContent("", "", null, null) MessageTextItem_() .informationData(informationData) .message("{ \"type\": ${event.root.type} }") .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } else { Timber.w("Ignored event (type: ${event.root.type}") diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt index 70d0f68e..187c98b3 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt @@ -20,15 +20,21 @@ import android.text.TextUtils import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.* +import im.vector.matrix.android.api.session.room.model.Membership +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility +import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibilityContent +import im.vector.matrix.android.api.session.room.model.RoomMember +import im.vector.matrix.android.api.session.room.model.RoomNameContent +import im.vector.matrix.android.api.session.room.model.RoomTopicContent import im.vector.matrix.android.api.session.room.model.call.CallInviteContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.R import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName import timber.log.Timber +import javax.inject.Inject -class NoticeEventFormatter(private val stringProvider: StringProvider) { +class NoticeEventFormatter @Inject constructor(private val stringProvider: StringProvider) { fun format(timelineEvent: TimelineEvent): CharSequence? { return when (val type = timelineEvent.root.getClearType()) { @@ -66,7 +72,7 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) { private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?): CharSequence? { val historyVisibility = event.getClearContent().toModel()?.historyVisibility - ?: return null + ?: return null val formattedVisibility = when (historyVisibility) { RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared) @@ -116,7 +122,7 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) { stringProvider.getString(R.string.notice_display_name_removed, event.sender, prevEventContent?.displayName) else -> stringProvider.getString(R.string.notice_display_name_changed_from, - event.sender, prevEventContent?.displayName, eventContent?.displayName) + event.sender, prevEventContent?.displayName, eventContent?.displayName) } displayText.append(displayNameText) } @@ -143,7 +149,7 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) { when { eventContent.thirdPartyInvite != null -> stringProvider.getString(R.string.notice_room_third_party_registered_invite, - targetDisplayName, eventContent.thirdPartyInvite?.displayName) + targetDisplayName, eventContent.thirdPartyInvite?.displayName) TextUtils.equals(event.stateKey, selfUserId) -> stringProvider.getString(R.string.notice_room_invite_you, senderDisplayName) event.stateKey.isNullOrEmpty() -> diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDateFormatter.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDateFormatter.kt index 0a4ed952..bd2b630f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDateFormatter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDateFormatter.kt @@ -19,8 +19,10 @@ package im.vector.riotredesign.features.home.room.detail.timeline.helper import im.vector.riotredesign.core.resources.LocaleProvider import org.threeten.bp.LocalDateTime import org.threeten.bp.format.DateTimeFormatter +import javax.inject.Inject -class TimelineDateFormatter(private val localeProvider: LocaleProvider) { + +class TimelineDateFormatter @Inject constructor (private val localeProvider: LocaleProvider) { private val messageHourFormatter by lazy { DateTimeFormatter.ofPattern("H:mm", localeProvider.current()) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt index c4e74f3f..4f509798 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineMediaSizeProvider.kt @@ -17,8 +17,9 @@ package im.vector.riotredesign.features.home.room.detail.timeline.helper import androidx.recyclerview.widget.RecyclerView +import javax.inject.Inject -class TimelineMediaSizeProvider { +class TimelineMediaSizeProvider @Inject constructor() { lateinit var recyclerView: RecyclerView private var cachedSize: Pair? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/AlphabeticalRoomComparator.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/AlphabeticalRoomComparator.kt index c1031c45..1c86d908 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/AlphabeticalRoomComparator.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/AlphabeticalRoomComparator.kt @@ -17,9 +17,9 @@ package im.vector.riotredesign.features.home.room.list import im.vector.matrix.android.api.session.room.model.RoomSummary +import javax.inject.Inject -class AlphabeticalRoomComparator - : Comparator { +class AlphabeticalRoomComparator @Inject constructor() : Comparator { override fun compare(leftRoomSummary: RoomSummary?, rightRoomSummary: RoomSummary?): Int { return when { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/ChronologicalRoomComparator.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/ChronologicalRoomComparator.kt index 2ffe559d..ccbe89bf 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/ChronologicalRoomComparator.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/ChronologicalRoomComparator.kt @@ -17,8 +17,9 @@ package im.vector.riotredesign.features.home.room.list import im.vector.matrix.android.api.session.room.model.RoomSummary +import javax.inject.Inject -class ChronologicalRoomComparator : Comparator { +class ChronologicalRoomComparator @Inject constructor() : Comparator { override fun compare(leftRoomSummary: RoomSummary?, rightRoomSummary: RoomSummary?): Int { var rightTimestamp = 0L diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt index e354be2f..06415a05 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt @@ -23,7 +23,11 @@ import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.airbnb.mvrx.* +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Incomplete +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.args +import com.airbnb.mvrx.fragmentViewModel import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomSummary @@ -36,7 +40,7 @@ import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.home.room.list.widget.FabMenuView import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_room_list.* -import org.koin.android.ext.android.inject +import javax.inject.Inject @Parcelize data class RoomListParams( @@ -61,7 +65,8 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O } private val roomListParams: RoomListParams by args() - private val roomController by inject() + @Inject lateinit var roomController: RoomSummaryController + @Inject lateinit var roomListViewModelFactory: RoomListViewModel.Factory private val roomListViewModel: RoomListViewModel by fragmentViewModel() override fun getLayoutResId() = R.layout.fragment_room_list diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt index c9ead506..7c6f7484 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt @@ -19,9 +19,12 @@ package im.vector.riotredesign.features.home.room.list import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import arrow.core.Option +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import com.jakewharton.rxrelay2.BehaviorRelay +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomSummary @@ -29,26 +32,27 @@ import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.core.utils.LiveEvent import im.vector.riotredesign.features.home.HomeRoomListObservableStore -import org.koin.android.ext.android.get typealias RoomListFilterName = CharSequence -class RoomListViewModel(initialState: RoomListViewState, - private val session: Session, - private val homeRoomListObservableSource: HomeRoomListObservableStore, - private val alphabeticalRoomComparator: AlphabeticalRoomComparator, - private val chronologicalRoomComparator: ChronologicalRoomComparator) +class RoomListViewModel @AssistedInject constructor(@Assisted initialState: RoomListViewState, + private val session: Session, + private val homeRoomListObservableSource: HomeRoomListObservableStore, + private val alphabeticalRoomComparator: AlphabeticalRoomComparator, + private val chronologicalRoomComparator: ChronologicalRoomComparator) : VectorViewModel(initialState) { + @AssistedInject.Factory + interface Factory { + fun create(initialState: RoomListViewState): RoomListViewModel + } + companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? { - val currentSession = viewModelContext.activity.get() - val homeRoomListObservableSource = viewModelContext.activity.get() - val chronologicalRoomComparator = viewModelContext.activity.get() - val alphabeticalRoomComparator = viewModelContext.activity.get() - return RoomListViewModel(state, currentSession, homeRoomListObservableSource, alphabeticalRoomComparator, chronologicalRoomComparator) + val fragment: RoomListFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.roomListViewModelFactory.create(state) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt index eafcb7dd..08f7fdb3 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt @@ -27,10 +27,11 @@ import im.vector.riotredesign.core.resources.DateProvider import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter +import javax.inject.Inject -class RoomSummaryController(private val stringProvider: StringProvider, - private val eventFormatter: NoticeEventFormatter, - private val timelineDateFormatter: TimelineDateFormatter +class RoomSummaryController @Inject constructor(private val stringProvider: StringProvider, + private val eventFormatter: NoticeEventFormatter, + private val timelineDateFormatter: TimelineDateFormatter ) : TypedEpoxyController() { var callback: Callback? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt index d8012607..e57de8d1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt @@ -19,11 +19,12 @@ package im.vector.riotredesign.features.html import android.content.Context -import android.text.style.ClickableSpan import android.text.style.URLSpan +import androidx.appcompat.app.AppCompatActivity import im.vector.matrix.android.api.permalinks.PermalinkData import im.vector.matrix.android.api.permalinks.PermalinkParser import im.vector.matrix.android.api.session.Session +import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.glide.GlideRequests import org.commonmark.node.BlockQuote import org.commonmark.node.HtmlBlock @@ -50,13 +51,12 @@ import ru.noties.markwon.html.tag.SubScriptHandler import ru.noties.markwon.html.tag.SuperScriptHandler import ru.noties.markwon.html.tag.UnderlineHandler import java.util.Arrays.asList +import javax.inject.Inject -class EventHtmlRenderer(glideRequests: GlideRequests, - context: Context, - session: Session) { - +class EventHtmlRenderer @Inject constructor(context: AppCompatActivity, + session: Session) { private val markwon = Markwon.builder(context) - .usePlugin(MatrixPlugin.create(glideRequests, context, session)) + .usePlugin(MatrixPlugin.create(GlideApp.with(context), context, session)) .build() fun render(text: String): CharSequence { diff --git a/vector/src/main/java/im/vector/riotredesign/features/lifecycle/VectorActivityLifecycleCallbacks.kt b/vector/src/main/java/im/vector/riotredesign/features/lifecycle/VectorActivityLifecycleCallbacks.kt index 9a2a5e1e..b3ac5726 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/lifecycle/VectorActivityLifecycleCallbacks.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/lifecycle/VectorActivityLifecycleCallbacks.kt @@ -20,8 +20,9 @@ import android.app.Activity import android.app.Application import android.os.Bundle import im.vector.riotredesign.features.popup.PopupAlertManager +import javax.inject.Inject -class VectorActivityLifecycleCallbacks : Application.ActivityLifecycleCallbacks { +class VectorActivityLifecycleCallbacks @Inject constructor() : Application.ActivityLifecycleCallbacks { override fun onActivityPaused(activity: Activity) { } diff --git a/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt index 3dd5c6d9..c13f8b84 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/navigation/DefaultNavigator.kt @@ -27,9 +27,9 @@ import im.vector.riotredesign.features.home.room.detail.RoomDetailArgs import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity import im.vector.riotredesign.features.roomdirectory.roompreview.RoomPreviewActivity import im.vector.riotredesign.features.settings.VectorSettingsActivity +import javax.inject.Inject -class DefaultNavigator : Navigator { - +class DefaultNavigator @Inject constructor() : Navigator { override fun openRoom(roomId: String, context: Context) { val args = RoomDetailArgs(roomId) diff --git a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationBroadcastReceiver.kt b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationBroadcastReceiver.kt index 36692b7d..ae847d1c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationBroadcastReceiver.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationBroadcastReceiver.kt @@ -22,16 +22,15 @@ import android.content.Intent import androidx.core.app.RemoteInput import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.room.Room -import org.koin.standalone.KoinComponent -import org.koin.standalone.inject import timber.log.Timber +import javax.inject.Inject /** * Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.) */ -class NotificationBroadcastReceiver : BroadcastReceiver(), KoinComponent { +class NotificationBroadcastReceiver : BroadcastReceiver() { - private val notificationDrawerManager by inject() + @Inject lateinit var notificationDrawerManager: NotificationDrawerManager override fun onReceive(context: Context?, intent: Intent?) { if (intent == null || context == null) return diff --git a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt index ce207397..7ada17d6 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt @@ -30,13 +30,17 @@ import timber.log.Timber import java.io.File import java.io.FileInputStream import java.io.FileOutputStream +import javax.inject.Inject +import javax.inject.Singleton /** * The NotificationDrawerManager receives notification events as they arrived (from event stream or fcm) and * organise them in order to display them in the notification drawer. * Events can be grouped into the same notification, old (already read) events can be removed to do some cleaning. */ -class NotificationDrawerManager(val context: Context) { + +@Singleton +class NotificationDrawerManager @Inject constructor(val context: Context) { //The first time the notification drawer is refreshed, we force re-render of all notifications private var firstTime = true diff --git a/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserFragment.kt index 6f47538a..13ade472 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserFragment.kt @@ -15,34 +15,27 @@ */ package im.vector.riotredesign.features.reactions -import androidx.lifecycle.ViewModelProviders import android.os.Bundle -import android.util.Log -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.RecyclerView import im.vector.riotredesign.R +import im.vector.riotredesign.core.platform.VectorBaseFragment -class EmojiChooserFragment : Fragment() { +class EmojiChooserFragment : VectorBaseFragment() { companion object { fun newInstance() = EmojiChooserFragment() } - private lateinit var viewModel: EmojiChooserViewModel + override fun getLayoutResId() = R.layout.emoji_chooser_fragment - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.emoji_chooser_fragment, container, false) - } + private lateinit var viewModel: EmojiChooserViewModel override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = activity?.run { - ViewModelProviders.of(this).get(EmojiChooserViewModel::class.java) + ViewModelProviders.of(this, viewModelFactory).get(EmojiChooserViewModel::class.java) } ?: throw Exception("Invalid Activity") viewModel.initWithContect(context!!) (view as? RecyclerView)?.let { @@ -53,9 +46,4 @@ class EmojiChooserFragment : Fragment() { // val ds = EmojiDataSource(this.context!!) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - - } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserViewModel.kt index 7b11adcd..47f2dbf1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiChooserViewModel.kt @@ -19,8 +19,9 @@ import android.content.Context import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import im.vector.riotredesign.core.utils.LiveEvent +import javax.inject.Inject -class EmojiChooserViewModel : ViewModel() { +class EmojiChooserViewModel @Inject constructor() : ViewModel() { var adapter: EmojiRecyclerAdapter? = null val emojiSourceLiveData: MutableLiveData = MutableLiveData() diff --git a/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiReactionPickerActivity.kt index 8e362b61..72d3b19f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/reactions/EmojiReactionPickerActivity.kt @@ -33,7 +33,6 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.observeEvent import im.vector.riotredesign.core.platform.VectorBaseActivity import kotlinx.android.synthetic.main.activity_emoji_reaction_picker.* -import org.koin.android.ext.android.inject /** * @@ -55,7 +54,7 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide override fun getTitleRes(): Int = R.string.title_activity_emoji_reaction_picker - val emojiCompatFontProvider by inject() + lateinit var emojiCompatFontProvider: EmojiCompatFontProvider private var tabLayoutSelectionListener = object : TabLayout.BaseOnTabSelectedListener { override fun onTabReselected(p0: TabLayout.Tab) { @@ -72,7 +71,6 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide override fun initUiAndData() { configureToolbar(emojiPickerToolbar) - emojiCompatFontProvider.let { EmojiDrawView.configureTextPaint(this, it.typeface) it.addListener(this) @@ -80,7 +78,7 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), EmojiCompatFontProvide tabLayout = findViewById(R.id.tabs) - viewModel = ViewModelProviders.of(this).get(EmojiChooserViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(EmojiChooserViewModel::class.java) viewModel.eventId = intent.getStringExtra(EXTRA_EVENT_ID) 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 1f680b9e..7f701af8 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 @@ -34,11 +34,9 @@ import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.themes.ThemeUtils import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_public_rooms.* -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 +import javax.inject.Inject /** @@ -49,8 +47,9 @@ 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() + + @Inject lateinit var publicRoomsController: PublicRoomsController + @Inject lateinit var errorFormatter: ErrorFormatter override fun getLayoutResId() = R.layout.fragment_public_rooms @@ -98,10 +97,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE)) - navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java) - 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 6f1e79e4..64853b8d 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 @@ -25,8 +25,7 @@ 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 +import javax.inject.Inject class RoomDirectoryActivity : VectorBaseActivity() { @@ -39,17 +38,14 @@ class RoomDirectoryActivity : VectorBaseActivity() { } + @Inject lateinit var roomDirectoryViewModelFactory: RoomDirectoryViewModel.Factory private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel override fun getLayoutRes() = R.layout.activity_simple override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE)) - - navigationViewModel = ViewModelProviders.of(this).get(RoomDirectoryNavigationViewModel::class.java) - + navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java) navigationViewModel.navigateTo.observeEvent(this) { navigation -> when (navigation) { is Navigation.Back -> onBackPressed() diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryNavigationViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryNavigationViewModel.kt index 8183b787..e92cd883 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryNavigationViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryNavigationViewModel.kt @@ -17,5 +17,6 @@ package im.vector.riotredesign.features.roomdirectory import im.vector.riotredesign.core.mvrx.NavigationViewModel +import javax.inject.Inject -class RoomDirectoryNavigationViewModel : NavigationViewModel() \ No newline at end of file +class RoomDirectoryNavigationViewModel @Inject constructor(): NavigationViewModel() \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt index fa980b20..f06a2bea 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/RoomDirectoryViewModel.kt @@ -18,7 +18,15 @@ package im.vector.riotredesign.features.roomdirectory import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.airbnb.mvrx.* +import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.ViewModelContext +import com.airbnb.mvrx.appendAt +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.room.model.Membership @@ -31,21 +39,24 @@ import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.rx.rx import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.core.utils.LiveEvent -import org.koin.android.ext.android.get import timber.log.Timber private const val PUBLIC_ROOMS_LIMIT = 20 -class RoomDirectoryViewModel(initialState: PublicRoomsViewState, - private val session: Session) : VectorViewModel(initialState) { +class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: PublicRoomsViewState, + private val session: Session) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: PublicRoomsViewState): RoomDirectoryViewModel + } companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: PublicRoomsViewState): RoomDirectoryViewModel? { - val currentSession = viewModelContext.activity.get() - - return RoomDirectoryViewModel(state, currentSession) + val activity: RoomDirectoryActivity = (viewModelContext as ActivityViewModelContext).activity() + return activity.roomDirectoryViewModelFactory.create(state) } } @@ -84,11 +95,11 @@ class RoomDirectoryViewModel(initialState: PublicRoomsViewState, .liveRoomSummaries() .subscribe { list -> val joinedRoomIds = list - // Keep only joined room - ?.filter { it.membership == Membership.JOIN } - ?.map { it.roomId } - ?.toList() - ?: emptyList() + // Keep only joined room + ?.filter { it.membership == Membership.JOIN } + ?.map { it.roomId } + ?.toList() + ?: emptyList() setState { copy( @@ -155,39 +166,39 @@ class RoomDirectoryViewModel(initialState: PublicRoomsViewState, private fun load() { currentTask = session.getPublicRooms(roomDirectoryData.homeServer, - PublicRoomsParams( - limit = PUBLIC_ROOMS_LIMIT, - filter = PublicRoomsFilter(searchTerm = currentFilter), - includeAllNetworks = roomDirectoryData.includeAllNetworks, - since = since, - thirdPartyInstanceId = roomDirectoryData.thirdPartyInstanceId - ), - object : MatrixCallback { - override fun onSuccess(data: PublicRoomsResponse) { - currentTask = null + PublicRoomsParams( + limit = PUBLIC_ROOMS_LIMIT, + filter = PublicRoomsFilter(searchTerm = currentFilter), + includeAllNetworks = roomDirectoryData.includeAllNetworks, + since = since, + thirdPartyInstanceId = roomDirectoryData.thirdPartyInstanceId + ), + object : MatrixCallback { + override fun onSuccess(data: PublicRoomsResponse) { + currentTask = null - since = data.nextBatch + since = data.nextBatch - setState { - copy( - asyncPublicRoomsRequest = Success(data.chunk!!), - // It's ok to append at the end of the list, so I use publicRooms.size() - publicRooms = publicRooms.appendAt(data.chunk!!, publicRooms.size), - hasMore = since != null - ) - } - } + setState { + copy( + asyncPublicRoomsRequest = Success(data.chunk!!), + // It's ok to append at the end of the list, so I use publicRooms.size() + publicRooms = publicRooms.appendAt(data.chunk!!, publicRooms.size), + hasMore = since != null + ) + } + } - override fun onFailure(failure: Throwable) { - currentTask = null + override fun onFailure(failure: Throwable) { + currentTask = null - setState { - copy( - asyncPublicRoomsRequest = Fail(failure) - ) - } - } - }) + setState { + copy( + asyncPublicRoomsRequest = Fail(failure) + ) + } + } + }) } fun joinRoom(publicRoom: PublicRoom) = withState { state -> 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 index 49fed53e..dadb4fa9 100644 --- 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 @@ -16,14 +16,17 @@ package im.vector.riotredesign.features.roomdirectory.picker -import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.api.session.Session 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 +import javax.inject.Inject -class RoomDirectoryListCreator(private val stringArrayProvider: StringArrayProvider, - private val credentials: Credentials) { +class RoomDirectoryListCreator @Inject constructor(private val stringArrayProvider: StringArrayProvider, + private val session: Session) { + + private val credentials = session.sessionParams.credentials fun computeDirectories(thirdPartyProtocolData: Map): List { val result = ArrayList() 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 e19c7a0b..b80944b9 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 @@ -26,10 +26,11 @@ 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 javax.inject.Inject -class RoomDirectoryPickerController(private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter, - private val roomDirectoryListCreator: RoomDirectoryListCreator +class RoomDirectoryPickerController @Inject constructor(private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter, + private val roomDirectoryListCreator: RoomDirectoryListCreator ) : TypedEpoxyController() { var callback: Callback? = null 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 4d1ca98b..38cf4a3d 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 @@ -28,14 +28,11 @@ import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryD 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 -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope import timber.log.Timber +import javax.inject.Inject // TODO Set title to R.string.select_room_directory // TODO Menu to add custom room directory (not done in RiotWeb so far...) @@ -44,7 +41,9 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon private val viewModel: RoomDirectoryViewModel by activityViewModel() private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel() - private val roomDirectoryPickerController: RoomDirectoryPickerController by inject() + + @Inject lateinit var roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory + @Inject lateinit var roomDirectoryPickerController: RoomDirectoryPickerController override fun getLayoutResId() = R.layout.fragment_room_directory_picker @@ -72,11 +71,9 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon } override fun onActivityCreated(savedInstanceState: Bundle?) { + injector().inject(this) super.onActivityCreated(savedInstanceState) - bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE)) - navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java) - setupRecyclerView() } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt index 30e687e9..6b5d86fb 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt @@ -17,25 +17,32 @@ package im.vector.riotredesign.features.roomdirectory.picker import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol import im.vector.riotredesign.core.platform.VectorViewModel -import org.koin.android.ext.android.get -class RoomDirectoryPickerViewModel(initialState: RoomDirectoryPickerViewState, - private val session: Session) : VectorViewModel(initialState) { +class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initialState: RoomDirectoryPickerViewState, + private val session: Session) : VectorViewModel(initialState) { + + + @AssistedInject.Factory + interface Factory { + fun create(initialState: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel + } companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel? { - val currentSession = viewModelContext.activity.get() - - return RoomDirectoryPickerViewModel(state, currentSession) + val fragment: RoomDirectoryPickerFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.roomDirectoryPickerViewModelFactory.create(state) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewActivity.kt index 0728ad56..46044914 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewActivity.kt @@ -18,7 +18,6 @@ package im.vector.riotredesign.features.roomdirectory.roompreview import android.content.Context import android.content.Intent -import android.os.Bundle import android.os.Parcelable import androidx.appcompat.widget.Toolbar import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom @@ -26,10 +25,7 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.extensions.addFragment import im.vector.riotredesign.core.platform.ToolbarConfigurable import im.vector.riotredesign.core.platform.VectorBaseActivity -import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule import kotlinx.android.parcel.Parcelize -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope @Parcelize data class RoomPreviewData( @@ -65,12 +61,6 @@ class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { configureToolbar(toolbar) } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE)) - } - override fun initUiAndData() { if (isFirstCreation()) { val args = intent.getParcelableExtra(ARG) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt index 3f389a46..d1960614 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt @@ -30,11 +30,8 @@ import im.vector.riotredesign.core.platform.ButtonStateView import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.roomdirectory.JoinState -import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule import kotlinx.android.synthetic.main.fragment_room_preview_no_preview.* -import org.koin.android.ext.android.get -import org.koin.android.scope.ext.android.bindScope -import org.koin.android.scope.ext.android.getOrCreateScope +import javax.inject.Inject /** * Note: this Fragment is also used for world readable room for the moment @@ -47,14 +44,14 @@ class RoomPreviewNoPreviewFragment : VectorBaseFragment() { } } - private val errorFormatter = get() + @Inject lateinit var errorFormatter: ErrorFormatter + @Inject lateinit var roomPreviewViewModelFactory: RoomPreviewViewModel.Factory private val roomPreviewViewModel: RoomPreviewViewModel by fragmentViewModel() - private val roomPreviewData: RoomPreviewData by args() override fun onActivityCreated(savedInstanceState: Bundle?) { + injector().inject(this) super.onActivityCreated(savedInstanceState) - bindScope(getOrCreateScope(RoomDirectoryModule.ROOM_DIRECTORY_SCOPE)) setupToolbar(roomPreviewNoPreviewToolbar) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewViewModel.kt index 131f2719..61102f11 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewViewModel.kt @@ -16,27 +16,33 @@ package im.vector.riotredesign.features.roomdirectory.roompreview +import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext +import com.squareup.inject.assisted.Assisted +import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.rx.rx import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.features.roomdirectory.JoinState -import org.koin.android.ext.android.get import timber.log.Timber -class RoomPreviewViewModel(initialState: RoomPreviewViewState, - private val session: Session) : VectorViewModel(initialState) { +class RoomPreviewViewModel @AssistedInject constructor(@Assisted initialState: RoomPreviewViewState, + private val session: Session) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: RoomPreviewViewState): RoomPreviewViewModel + } companion object : MvRxViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomPreviewViewState): RoomPreviewViewModel? { - val currentSession = viewModelContext.activity.get() - - return RoomPreviewViewModel(state, currentSession) + val fragment: RoomPreviewNoPreviewFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.roomPreviewViewModelFactory.create(state) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt index 2d53f36a..f420a2ac 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt @@ -30,6 +30,7 @@ import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders import androidx.transition.TransitionManager import butterknife.BindView @@ -40,15 +41,19 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.HasInjector +import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.utils.toast import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupActivity -import org.koin.android.ext.android.inject +import javax.inject.Inject class SignOutBottomSheetDialogFragment : BottomSheetDialogFragment() { - val session by inject() + @Inject lateinit var session: Session + @Inject lateinit var viewModelFactory: ViewModelProvider.Factory + @BindView(R.id.bottom_sheet_signout_warning_text) lateinit var sheetTitle: TextView @@ -99,7 +104,7 @@ class SignOutBottomSheetDialogFragment : BottomSheetDialogFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProviders.of(this).get(SignOutViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(SignOutViewModel::class.java) viewModel.init(session) @@ -131,7 +136,7 @@ class SignOutBottomSheetDialogFragment : BottomSheetDialogFragment() { startActivity(KeysBackupManageActivity.intent(context)) } } - KeysBackupState.Disabled -> { + KeysBackupState.Disabled -> { context?.let { context -> startActivityForResult(KeysBackupSetupActivity.intent(context, true), EXPORT_REQ) } @@ -141,7 +146,7 @@ class SignOutBottomSheetDialogFragment : BottomSheetDialogFragment() { //keys are already backing up please wait context?.toast(R.string.keys_backup_is_not_finished_please_wait) } - else -> { + else -> { //nop } } @@ -190,7 +195,7 @@ class SignOutBottomSheetDialogFragment : BottomSheetDialogFragment() { sheetTitle.text = getString(R.string.action_sign_out_confirmation_simple) } KeysBackupState.BackingUp, - KeysBackupState.WillBackUp -> { + KeysBackupState.WillBackUp -> { backingUpStatusGroup.isVisible = true sheetTitle.text = getString(R.string.sign_out_bottom_sheet_warning_backing_up) dontWantClickableView.isVisible = true @@ -202,14 +207,14 @@ class SignOutBottomSheetDialogFragment : BottomSheetDialogFragment() { backupStatusTex.text = getString(R.string.sign_out_bottom_sheet_backing_up_keys) } - KeysBackupState.NotTrusted -> { + KeysBackupState.NotTrusted -> { backingUpStatusGroup.isVisible = false dontWantClickableView.isVisible = true setupClickableView.isVisible = false activateClickableView.isVisible = true sheetTitle.text = getString(R.string.sign_out_bottom_sheet_warning_backup_not_active) } - else -> { + else -> { backingUpStatusGroup.isVisible = false dontWantClickableView.isVisible = true setupClickableView.isVisible = true diff --git a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt index ea3989ee..c923adab 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutViewModel.kt @@ -21,8 +21,9 @@ import androidx.lifecycle.ViewModel import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener +import javax.inject.Inject -class SignOutViewModel : ViewModel(), KeysBackupStateListener { +class SignOutViewModel @Inject constructor() : ViewModel(), KeysBackupStateListener { // Keys exported manually var keysExportedToFile = MutableLiveData() @@ -47,9 +48,9 @@ class SignOutViewModel : ViewModel(), KeysBackupStateListener { */ fun getCurrentBackupVersion(): String { return mxSession - ?.getKeysBackupService() - ?.currentBackupVersion - ?: "" + ?.getKeysBackupService() + ?.currentBackupVersion + ?: "" } /** @@ -57,8 +58,8 @@ class SignOutViewModel : ViewModel(), KeysBackupStateListener { */ fun getNumberOfKeysToBackup(): Int { return mxSession - ?.inboundGroupSessionsCount(false) - ?: 0 + ?.inboundGroupSessionsCount(false) + ?: 0 } /** @@ -87,11 +88,11 @@ class SignOutViewModel : ViewModel(), KeysBackupStateListener { */ fun doYouNeedToBeDisplayed(session: Session?): Boolean { return session - ?.inboundGroupSessionsCount(false) - ?: 0 > 0 - && session - ?.getKeysBackupService() - ?.state != KeysBackupState.ReadyToBackUp + ?.inboundGroupSessionsCount(false) + ?: 0 > 0 + && session + ?.getKeysBackupService() + ?.state != KeysBackupState.ReadyToBackUp } } } \ No newline at end of file