From e01afd2bca06a6a3b80ae7bc493db8caf3cc0c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Czeka=C5=84ski?= Date: Sun, 24 Jun 2018 16:44:06 +0200 Subject: [PATCH] added Dagger2, but architecture isn't perfect --- app/build.gradle | 7 +++ .../java/info/czekanski/bet/MainActivity.kt | 17 ++++--- .../java/info/czekanski/bet/MyApplication.kt | 27 ++++++++++- .../bet/di/component/AppComponent.kt | 31 +++++++++++++ .../czekanski/bet/di/module/ActivityModule.kt | 31 +++++++++++++ .../czekanski/bet/di/module/ContextModule.kt | 23 ++++++++++ .../czekanski/bet/di/module/ServiceModule.kt | 45 +++++++++++++++++++ .../bet/di/module/domain/FragmentModule.kt | 32 +++++++++++++ .../module/view_model/DiViewModelFactory.kt | 30 +++++++++++++ .../bet/di/module/view_model/ViewModelKey.kt | 11 +++++ .../di/module/view_model/ViewModelModule.kt | 36 +++++++++++++++ .../view_model/ViewModelSubComponent.kt | 20 +++++++++ .../czekanski/bet/di/utils/BaseFragment.kt | 20 +++++++++ .../bet/di/utils/CustomDaggerApplication.kt | 15 +++++++ .../bet/di/utils/CustomInjectionModule.kt | 19 ++++++++ .../czekanski/bet/di/utils/CustomInjectors.kt | 38 ++++++++++++++++ .../bet/di/utils/HasViewHolderInjector.kt | 10 +++++ .../czekanski/bet/di/utils/HasViewInjector.kt | 9 ++++ .../bet/domain/base/BaseHomeFragment.kt | 9 ++-- .../czekanski/bet/domain/bets/BetsFragment.kt | 8 ++-- .../bet/domain/bets/BetsViewModel.kt | 11 +++-- .../czekanski/bet/domain/game/GameFragment.kt | 14 +++--- .../bet/domain/game/GameViewModel.kt | 29 ++++++------ .../czekanski/bet/domain/home/HomeFragment.kt | 8 ++-- .../bet/domain/home/HomeViewModel.kt | 15 ++++--- .../bet/domain/home/MatchesAdapter.kt | 18 ++++---- .../domain/home/view_holder/BetViewHolder.kt | 9 +++- .../bet/domain/login/LoginActivity.kt | 3 +- .../bet/domain/login/LoginFragment.kt | 10 ++--- .../bet/domain/matches/MatchesFragment.kt | 10 +++-- .../bet/domain/matches/MatchesViewModel.kt | 7 +-- .../bet/domain/profile/ProfileFragment.kt | 8 ++-- .../czekanski/bet/misc/FragmentExtensions.kt | 1 + .../info/czekanski/bet/network/BetService.kt | 22 --------- .../czekanski/bet/receiver/UpdateReceiver.kt | 14 +++--- .../czekanski/bet/repository/BetRepository.kt | 10 ++--- .../bet/repository/ConfigProvider.kt | 9 ++-- .../bet/repository/FriendsRepository.kt | 11 ++--- .../bet/repository/MatchRepository.kt | 11 ++--- .../bet/repository/PreferencesProvider.kt | 15 ++----- .../FirebaseTokenRegistrationService.kt | 11 ++++- .../info/czekanski/bet/user/UserProvider.kt | 24 +++++----- .../czekanski/bet/views/OctagonalImageView.kt | 9 +++- build.gradle | 2 +- 44 files changed, 558 insertions(+), 161 deletions(-) create mode 100644 app/src/main/java/info/czekanski/bet/di/component/AppComponent.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/ActivityModule.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/ContextModule.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/ServiceModule.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/domain/FragmentModule.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/view_model/DiViewModelFactory.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelKey.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelModule.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelSubComponent.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/utils/BaseFragment.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/utils/CustomDaggerApplication.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/utils/CustomInjectionModule.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/utils/CustomInjectors.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/utils/HasViewHolderInjector.kt create mode 100644 app/src/main/java/info/czekanski/bet/di/utils/HasViewInjector.kt delete mode 100644 app/src/main/java/info/czekanski/bet/network/BetService.kt diff --git a/app/build.gradle b/app/build.gradle index ceda431..aae83e9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -61,6 +61,13 @@ dependencies { implementation 'com.squareup.moshi:moshi:1.6.0' implementation 'com.github.florent37:viewtooltip:1.1.5' + implementation 'com.google.dagger:dagger:2.16' + implementation 'com.google.dagger:dagger-android:2.16' + implementation 'com.google.dagger:dagger-android-support:2.16' + kapt 'com.google.dagger:dagger-compiler:2.16' + kapt 'com.google.dagger:dagger-android-processor:2.16' + compileOnly 'org.glassfish:javax.annotation:10.0-b28' + testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/app/src/main/java/info/czekanski/bet/MainActivity.kt b/app/src/main/java/info/czekanski/bet/MainActivity.kt index 127b81d..17fdcf4 100644 --- a/app/src/main/java/info/czekanski/bet/MainActivity.kt +++ b/app/src/main/java/info/czekanski/bet/MainActivity.kt @@ -4,11 +4,13 @@ import android.content.Intent import android.os.Bundle import android.support.v4.app.* import android.support.v7.app.AppCompatActivity -import android.util.Log +import dagger.android.AndroidInjection +import dagger.android.support.DaggerAppCompatActivity +import info.czekanski.bet.R.id.* import info.czekanski.bet.domain.bets.BetsFragment -import info.czekanski.bet.domain.home.HomeFragment -import info.czekanski.bet.domain.login.* import info.czekanski.bet.domain.game.GameFragment +import info.czekanski.bet.domain.home.HomeFragment +import info.czekanski.bet.domain.login.LoginActivity import info.czekanski.bet.domain.matches.MatchesFragment import info.czekanski.bet.domain.profile.ProfileFragment import info.czekanski.bet.misc.* @@ -17,12 +19,13 @@ import info.czekanski.bet.user.UserProvider import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.activity_main.* import timber.log.Timber +import javax.inject.Inject -class MainActivity : AppCompatActivity() { - private val config by lazy { ConfigProvider.instance } - private val userProvider by lazy { UserProvider.instance } - private val preferencesProvider by lazy { PreferencesProvider.getInstance(applicationContext) } +class MainActivity : DaggerAppCompatActivity() { + @Inject lateinit var config: ConfigProvider + @Inject lateinit var userProvider: UserProvider + @Inject lateinit var preferencesProvider: PreferencesProvider override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/info/czekanski/bet/MyApplication.kt b/app/src/main/java/info/czekanski/bet/MyApplication.kt index 1bd3d20..6773679 100644 --- a/app/src/main/java/info/czekanski/bet/MyApplication.kt +++ b/app/src/main/java/info/czekanski/bet/MyApplication.kt @@ -1,12 +1,19 @@ package info.czekanski.bet -import android.app.Application +import dagger.android.AndroidInjector +import dagger.android.support.DaggerApplication +import info.czekanski.bet.di.* +import info.czekanski.bet.di.component.* +import info.czekanski.bet.di.utils.CustomDaggerApplication import info.czekanski.bet.service.NotificationService import timber.log.Timber -class MyApplication : Application() { +class MyApplication : CustomDaggerApplication() { + lateinit var component: AppComponent + override fun onCreate() { super.onCreate() + instance = this NotificationService.createNotificationChannels(this) @@ -14,4 +21,20 @@ class MyApplication : Application() { Timber.plant(Timber.DebugTree()) } } + + override fun applicationInjector(): AndroidInjector { + val c = DaggerAppComponent + .builder() + .application(this) + .build() + this.component = c + + return c + } + + companion object { + private var instance: MyApplication? = null + + fun get(): MyApplication = instance!! + } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/component/AppComponent.kt b/app/src/main/java/info/czekanski/bet/di/component/AppComponent.kt new file mode 100644 index 0000000..0b61611 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/component/AppComponent.kt @@ -0,0 +1,31 @@ +package info.czekanski.bet.di.component + +import dagger.* +import dagger.android.AndroidInjector +import info.czekanski.bet.MyApplication +import info.czekanski.bet.di.module.* +import info.czekanski.bet.di.module.domain.* +import info.czekanski.bet.di.utils.CustomInjectionModule +import info.czekanski.bet.di.module.view_model.ViewModelModule +import info.czekanski.bet.views.OctagonalImageView +import javax.inject.Singleton + +@Component(modules = [ + CustomInjectionModule::class, + ContextModule::class, + ServiceModule::class, + ViewModelModule::class, + ActivityModule::class, + FragmentModule::class +]) +@Singleton +interface AppComponent : AndroidInjector { + @Component.Builder + interface Builder { + @BindsInstance + fun application(app: MyApplication): Builder + fun build(): AppComponent + } + + fun inject(octagonalImageView: OctagonalImageView) +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/ActivityModule.kt b/app/src/main/java/info/czekanski/bet/di/module/ActivityModule.kt new file mode 100644 index 0000000..9054dca --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/ActivityModule.kt @@ -0,0 +1,31 @@ +package info.czekanski.bet.di.module + +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.firestore.FirebaseFirestore +import dagger.* +import dagger.android.ContributesAndroidInjector +import info.czekanski.bet.MainActivity +import info.czekanski.bet.domain.login.LoginActivity +import info.czekanski.bet.network.BetApi +import info.czekanski.bet.receiver.UpdateReceiver +import info.czekanski.bet.service.FirebaseTokenRegistrationService +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.moshi.MoshiConverterFactory +import javax.inject.Singleton + +@Module +abstract class ActivityModule { + + @ContributesAndroidInjector + abstract fun contributeMainActivity(): MainActivity + + @ContributesAndroidInjector + abstract fun contributeLoginActivity(): LoginActivity + + @ContributesAndroidInjector + abstract fun contributeUpdateReceiver(): UpdateReceiver + + @ContributesAndroidInjector + abstract fun contributeFirebaseTokenRegistrationService(): FirebaseTokenRegistrationService +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/ContextModule.kt b/app/src/main/java/info/czekanski/bet/di/module/ContextModule.kt new file mode 100644 index 0000000..71922e3 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/ContextModule.kt @@ -0,0 +1,23 @@ +package info.czekanski.bet.di.module + +import android.app.Application +import android.content.* +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import dagger.* +import info.czekanski.bet.MyApplication +import info.czekanski.bet.network.BetApi +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.moshi.MoshiConverterFactory +import javax.inject.Singleton + +@Module +abstract class ContextModule { + + @Binds + @Singleton + abstract fun context(app: MyApplication): Context + +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/ServiceModule.kt b/app/src/main/java/info/czekanski/bet/di/module/ServiceModule.kt new file mode 100644 index 0000000..1f19dea --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/ServiceModule.kt @@ -0,0 +1,45 @@ +package info.czekanski.bet.di.module + +import android.content.* +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import dagger.* +import info.czekanski.bet.network.BetApi +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.moshi.MoshiConverterFactory +import javax.inject.Singleton + +@Module +class ServiceModule { + @Provides + @Singleton + fun retrofit(): Retrofit = Retrofit.Builder() + .baseUrl("https://bet.czekanski.info/") + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(MoshiConverterFactory.create()) + .build() + + @Provides + @Singleton + fun betApi(retrofit: Retrofit): BetApi = + retrofit.create(BetApi::class.java) + + + @Provides + @Singleton + fun firestore(): FirebaseFirestore = FirebaseFirestore.getInstance() + + @Provides + @Singleton + fun firebaseAuth(): FirebaseAuth = FirebaseAuth.getInstance() + + @Provides + @Singleton + fun remoteConfig(): FirebaseRemoteConfig = FirebaseRemoteConfig.getInstance() + + @Provides + @Singleton + fun preferences(context: Context): SharedPreferences = context.getSharedPreferences("preferences", Context.MODE_PRIVATE) +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/domain/FragmentModule.kt b/app/src/main/java/info/czekanski/bet/di/module/domain/FragmentModule.kt new file mode 100644 index 0000000..d7ba0a8 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/domain/FragmentModule.kt @@ -0,0 +1,32 @@ +package info.czekanski.bet.di.module.domain + +import dagger.Module +import dagger.android.ContributesAndroidInjector +import info.czekanski.bet.domain.bets.BetsFragment +import info.czekanski.bet.domain.game.GameFragment +import info.czekanski.bet.domain.home.HomeFragment +import info.czekanski.bet.domain.login.LoginFragment +import info.czekanski.bet.domain.matches.MatchesFragment +import info.czekanski.bet.domain.profile.ProfileFragment + +@Module +abstract class FragmentModule { + + @ContributesAndroidInjector + abstract fun contributeLoginFragment(): LoginFragment + + @ContributesAndroidInjector + abstract fun contributeHomeFragment(): HomeFragment + + @ContributesAndroidInjector + abstract fun contributeMatchesFragment(): MatchesFragment + + @ContributesAndroidInjector + abstract fun contributeBetsFragment(): BetsFragment + + @ContributesAndroidInjector + abstract fun contributeGameFragment(): GameFragment + + @ContributesAndroidInjector + abstract fun contributeProfileFragment(): ProfileFragment +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/view_model/DiViewModelFactory.kt b/app/src/main/java/info/czekanski/bet/di/module/view_model/DiViewModelFactory.kt new file mode 100644 index 0000000..ef415a9 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/view_model/DiViewModelFactory.kt @@ -0,0 +1,30 @@ +package info.czekanski.bet.di.module.view_model + +import android.arch.lifecycle.* +import javax.inject.* + +@Singleton +class DiViewModelFactory @Inject constructor( + private val creators: Map, @JvmSuppressWildcards Provider?> +) : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + var creator: Provider? = creators[modelClass] + if (creator == null) { + for (entry in creators.entries) { + if (modelClass.isAssignableFrom(entry.key)) { + creator = entry.value + break + } + } + } + if (creator == null) { + throw IllegalArgumentException("unknown model class $modelClass") + } + try { + return creator.get() as T + } catch (e: Exception) { + throw RuntimeException(e) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelKey.kt b/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelKey.kt new file mode 100644 index 0000000..75ae509 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelKey.kt @@ -0,0 +1,11 @@ +package info.czekanski.bet.di.module.view_model + +import android.arch.lifecycle.ViewModel +import dagger.MapKey +import kotlin.reflect.KClass + +@MustBeDocumented +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +@Retention(AnnotationRetention.RUNTIME) +@MapKey +annotation class ViewModelKey(val value: KClass) diff --git a/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelModule.kt b/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelModule.kt new file mode 100644 index 0000000..eac254d --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelModule.kt @@ -0,0 +1,36 @@ +package info.czekanski.bet.di.module.view_model + +import android.arch.lifecycle.* +import dagger.* +import dagger.multibindings.IntoMap +import info.czekanski.bet.domain.bets.BetsViewModel +import info.czekanski.bet.domain.game.GameViewModel +import info.czekanski.bet.domain.home.HomeViewModel +import info.czekanski.bet.domain.matches.MatchesViewModel + + +@Module +abstract class ViewModelModule { + @Binds + @IntoMap + @ViewModelKey(HomeViewModel::class) + abstract fun bindHomeViewModel(homeViewModel: HomeViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(MatchesViewModel::class) + abstract fun bindMathesViewModel(matchesViewModel: MatchesViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(GameViewModel::class) + abstract fun bindGameViewModel(gameViewModel: GameViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(BetsViewModel::class) + abstract fun bindBetsViewModel(betsViewModel: BetsViewModel): ViewModel + + @Binds + abstract fun bindViewModelFactory(factory: DiViewModelFactory): ViewModelProvider.Factory +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelSubComponent.kt b/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelSubComponent.kt new file mode 100644 index 0000000..248a4f5 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/module/view_model/ViewModelSubComponent.kt @@ -0,0 +1,20 @@ +package info.czekanski.bet.di.module.view_model + +import dagger.Subcomponent +import info.czekanski.bet.domain.bets.BetsViewModel +import info.czekanski.bet.domain.game.GameViewModel +import info.czekanski.bet.domain.home.HomeViewModel +import info.czekanski.bet.domain.matches.MatchesViewModel + +@Subcomponent +interface ViewModelSubComponent { + @Subcomponent.Builder + interface Builder { + fun build(): ViewModelSubComponent + } + + fun homeViewModel(): HomeViewModel + fun matchesViewModel(): MatchesViewModel + fun betsViewModel(): BetsViewModel + fun gameViewModel(): GameViewModel +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/utils/BaseFragment.kt b/app/src/main/java/info/czekanski/bet/di/utils/BaseFragment.kt new file mode 100644 index 0000000..a2953fb --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/utils/BaseFragment.kt @@ -0,0 +1,20 @@ +package info.czekanski.bet.di.utils + +import android.arch.lifecycle.* +import android.content.Context +import android.support.v4.app.Fragment +import dagger.android.support.AndroidSupportInjection +import info.czekanski.bet.di.module.view_model.DiViewModelFactory +import javax.inject.Inject + +open class BaseFragment : Fragment() { + @Inject lateinit var viewModelFactory: DiViewModelFactory + + override fun onAttach(context: Context?) { + AndroidSupportInjection.inject(this) + super.onAttach(context) + } + + inline fun viewModel(): T = ViewModelProviders.of(this, viewModelFactory).get(T::class.java) +} + diff --git a/app/src/main/java/info/czekanski/bet/di/utils/CustomDaggerApplication.kt b/app/src/main/java/info/czekanski/bet/di/utils/CustomDaggerApplication.kt new file mode 100644 index 0000000..0f445e6 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/utils/CustomDaggerApplication.kt @@ -0,0 +1,15 @@ +package info.czekanski.bet.di.utils + +import android.support.v7.widget.RecyclerView +import android.view.View +import dagger.android.* +import dagger.android.support.DaggerApplication +import javax.inject.Inject + +abstract class CustomDaggerApplication: DaggerApplication(), HasViewInjector, HasViewHolderInjector { + @Inject lateinit var viewInjector: DispatchingAndroidInjector + @Inject lateinit var viewHolderInjector: DispatchingAndroidInjector + + override fun viewInjector(): AndroidInjector = viewInjector + override fun viewHolderInjector(): AndroidInjector = viewHolderInjector +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/utils/CustomInjectionModule.kt b/app/src/main/java/info/czekanski/bet/di/utils/CustomInjectionModule.kt new file mode 100644 index 0000000..78f253b --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/utils/CustomInjectionModule.kt @@ -0,0 +1,19 @@ +package info.czekanski.bet.di.utils + +import android.support.v7.widget.RecyclerView +import android.view.View +import dagger.Module +import dagger.android.AndroidInjector +import dagger.android.support.AndroidSupportInjectionModule +import dagger.internal.Beta +import dagger.multibindings.Multibinds + +@Beta +@Module(includes = [(AndroidSupportInjectionModule::class)]) +abstract class CustomInjectionModule private constructor() { + @Multibinds + abstract fun viewInjectorFactories(): Map, AndroidInjector.Factory> + + @Multibinds + abstract fun viewHolderInjectorFactories(): Map, AndroidInjector.Factory> +} diff --git a/app/src/main/java/info/czekanski/bet/di/utils/CustomInjectors.kt b/app/src/main/java/info/czekanski/bet/di/utils/CustomInjectors.kt new file mode 100644 index 0000000..0b34793 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/utils/CustomInjectors.kt @@ -0,0 +1,38 @@ +package info.czekanski.bet.di.utils + +import android.support.v7.widget.RecyclerView +import android.view.View + +object CustomInjectors { + @JvmStatic + fun inject(view: View) { + val application = view.context.applicationContext + if (application !is HasViewInjector) { + throw RuntimeException(String.format( + "%s does not implement %s", + application.javaClass.canonicalName, + HasViewInjector::class.java.canonicalName)) + } + + val viewInjection = (application as HasViewInjector).viewInjector() + checkNotNull(viewInjection, { "%s.viewInjector() returned null".format(application.javaClass) }) + + viewInjection.inject(view) + } + + @JvmStatic + fun inject(viewHolder: RecyclerView.ViewHolder) { +// val application = viewHolder.itemView.context.applicationContext +// if (application !is HasViewHolderInjector) { +// throw RuntimeException(String.format( +// "%s does not implement %s", +// application.javaClass.canonicalName, +// HasViewHolderInjector::class.java.canonicalName)) +// } +// +// val viewHolderInjector = (application as HasViewHolderInjector).viewHolderInjector() +// checkNotNull(viewHolderInjector, { "%s.viewHolderInjector() returned null".format(application.javaClass) }) +// +// viewHolderInjector.inject(viewHolder) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/utils/HasViewHolderInjector.kt b/app/src/main/java/info/czekanski/bet/di/utils/HasViewHolderInjector.kt new file mode 100644 index 0000000..f0369f6 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/utils/HasViewHolderInjector.kt @@ -0,0 +1,10 @@ +package info.czekanski.bet.di.utils + +import android.app.Fragment +import android.support.v7.widget.RecyclerView +import android.view.View +import dagger.android.AndroidInjector + +interface HasViewHolderInjector { + fun viewHolderInjector(): AndroidInjector +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/di/utils/HasViewInjector.kt b/app/src/main/java/info/czekanski/bet/di/utils/HasViewInjector.kt new file mode 100644 index 0000000..9cd4003 --- /dev/null +++ b/app/src/main/java/info/czekanski/bet/di/utils/HasViewInjector.kt @@ -0,0 +1,9 @@ +package info.czekanski.bet.di.utils + +import android.app.Fragment +import android.view.View +import dagger.android.AndroidInjector + +interface HasViewInjector { + fun viewInjector(): AndroidInjector +} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/domain/base/BaseHomeFragment.kt b/app/src/main/java/info/czekanski/bet/domain/base/BaseHomeFragment.kt index 79f3aef..194c075 100644 --- a/app/src/main/java/info/czekanski/bet/domain/base/BaseHomeFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/base/BaseHomeFragment.kt @@ -2,19 +2,20 @@ package info.czekanski.bet.domain.base import android.os.Bundle -import android.support.v4.app.Fragment import android.support.v7.widget.SimpleItemAnimator import android.view.* import info.czekanski.bet.R +import info.czekanski.bet.di.utils.BaseFragment import info.czekanski.bet.domain.game.GameFragment import info.czekanski.bet.domain.home.MatchesAdapter import info.czekanski.bet.domain.home.cells.* import info.czekanski.bet.domain.home.utils.ListDecorator import info.czekanski.bet.misc.* import kotlinx.android.synthetic.main.fragment_home.* +import javax.inject.Inject -abstract class BaseHomeFragment : Fragment() { - protected var matchesAdapter = MatchesAdapter(callback = this::onCellClicked) +abstract class BaseHomeFragment : BaseFragment() { + @Inject lateinit var matchesAdapter: MatchesAdapter override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_home, container, false) @@ -30,6 +31,8 @@ abstract class BaseHomeFragment : Fragment() { protected abstract fun initializeViewModel() private fun initRecyclerView() { + matchesAdapter.callback = this::onCellClicked + recyclerView.adapter = matchesAdapter recyclerView.addItemDecoration(ListDecorator()) recyclerView.setHasFixedSize(true) diff --git a/app/src/main/java/info/czekanski/bet/domain/bets/BetsFragment.kt b/app/src/main/java/info/czekanski/bet/domain/bets/BetsFragment.kt index 50790f2..a59e67c 100644 --- a/app/src/main/java/info/czekanski/bet/domain/bets/BetsFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/bets/BetsFragment.kt @@ -1,13 +1,15 @@ package info.czekanski.bet.domain.bets -import android.arch.lifecycle.ViewModelProviders import info.czekanski.bet.domain.base.BaseHomeFragment import info.czekanski.bet.misc.safeObserve class BetsFragment : BaseHomeFragment() { override fun initializeViewModel() { - val viewModel = ViewModelProviders.of(this).get(BetsViewModel::class.java) - viewModel.getCells().safeObserve(this, { matchesAdapter.setCells(it) }) + viewModel() + .getCells() + .safeObserve(this, { + matchesAdapter.setCells(it) + }) } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/domain/bets/BetsViewModel.kt b/app/src/main/java/info/czekanski/bet/domain/bets/BetsViewModel.kt index b2fc3e7..a95cefc 100644 --- a/app/src/main/java/info/czekanski/bet/domain/bets/BetsViewModel.kt +++ b/app/src/main/java/info/czekanski/bet/domain/bets/BetsViewModel.kt @@ -1,19 +1,18 @@ package info.czekanski.bet.domain.bets -import android.util.Log import info.czekanski.bet.domain.base.BaseHomeViewModel import info.czekanski.bet.domain.home.HomeViewModel -import info.czekanski.bet.domain.home.HomeViewModel.Companion.mergeMatchesIntoBets import info.czekanski.bet.domain.home.cells.* import info.czekanski.bet.misc.Cell import info.czekanski.bet.repository.* import io.reactivex.rxkotlin.* import timber.log.Timber +import javax.inject.Inject -class BetsViewModel : BaseHomeViewModel() { - private val betsRepository by lazy { BetRepository.instance } - private val matchesRepository by lazy { MatchRepository.instance } - +class BetsViewModel @Inject constructor( + private val betsRepository: BetRepository, + private val matchesRepository: MatchRepository +) : BaseHomeViewModel() { override fun loadData() { val betsFlowable = betsRepository.getBets() val matchesFlowable = matchesRepository.getMatches() diff --git a/app/src/main/java/info/czekanski/bet/domain/game/GameFragment.kt b/app/src/main/java/info/czekanski/bet/domain/game/GameFragment.kt index 5c8cada..850e6a3 100644 --- a/app/src/main/java/info/czekanski/bet/domain/game/GameFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/game/GameFragment.kt @@ -1,17 +1,16 @@ package info.czekanski.bet.domain.game import android.annotation.SuppressLint -import android.arch.lifecycle.ViewModelProviders import android.content.Intent import android.net.Uri import android.os.* -import android.support.v4.app.Fragment import android.support.v7.app.AlertDialog -import android.support.v7.widget.* +import android.support.v7.widget.StaggeredGridLayoutManager import android.view.* import android.widget.Toast import info.czekanski.bet.R -import info.czekanski.bet.domain.game.GameViewModel.* +import info.czekanski.bet.di.utils.BaseFragment +import info.czekanski.bet.domain.game.GameViewModel.Action import info.czekanski.bet.domain.game.GameViewState.Step.* import info.czekanski.bet.domain.game.friends.FriendsAdapter import info.czekanski.bet.domain.game.summary.SummaryAdapter @@ -26,9 +25,10 @@ import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_game.* import kotlinx.android.synthetic.main.layout_match_bid.* import kotlinx.android.synthetic.main.layout_match_score.* +import javax.inject.Inject -class GameFragment : Fragment(), OnBackPressedInterface { - private val userProvider by lazy { UserProvider.instance } +class GameFragment : BaseFragment(), OnBackPressedInterface { + @Inject lateinit var userProvider: UserProvider private val arg by lazy { getArgument() } private val summaryAdapter = SummaryAdapter(this::listCallback) @@ -40,7 +40,7 @@ class GameFragment : Fragment(), OnBackPressedInterface { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java) + viewModel = viewModel() initToolbar() initViews() diff --git a/app/src/main/java/info/czekanski/bet/domain/game/GameViewModel.kt b/app/src/main/java/info/czekanski/bet/domain/game/GameViewModel.kt index e94f6ca..6bdf62f 100644 --- a/app/src/main/java/info/czekanski/bet/domain/game/GameViewModel.kt +++ b/app/src/main/java/info/czekanski/bet/domain/game/GameViewModel.kt @@ -2,29 +2,30 @@ package info.czekanski.bet.domain.game import android.arch.lifecycle.* import android.net.Uri -import android.util.Log import com.google.firebase.dynamiclinks.* import durdinapps.rxfirebase2.RxHandler import info.czekanski.bet.domain.game.GameViewState.Step import info.czekanski.bet.misc.* +import info.czekanski.bet.misc.plusAssign import info.czekanski.bet.network.* import info.czekanski.bet.network.firebase.model.FirebaseBet import info.czekanski.bet.network.model.Bet import info.czekanski.bet.repository.* import info.czekanski.bet.user.UserProvider -import info.czekanski.bet.misc.plusAssign import io.reactivex.* -import io.reactivex.disposables.* +import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.* import timber.log.Timber - -class GameViewModel : ViewModel() { +import javax.inject.Inject + +class GameViewModel @Inject constructor( + private val betService: BetApi, + private val userProvider: UserProvider, + private val betRepository: BetRepository, + private val matchRepository: MatchRepository, + private val friendsRepository: FriendsRepository +) : ViewModel() { private val subs = CompositeDisposable() - private val betService: BetService by lazy { BetService.instance } - private val betRepository by lazy { BetRepository.instance } - private val matchRepository by lazy { MatchRepository.instance } - private val friendsRepository by lazy { FriendsRepository.instance } - private val userProvider by lazy { UserProvider.instance } private val state = MutableLiveData() private val toast = MutableLiveData() @@ -138,7 +139,7 @@ class GameViewModel : ViewModel() { private fun deleteBet() { val s = state.v if (s.bet != null) { - subs += betService.api.deleteBet(s.bet.id, userProvider.userId!!) + subs += betService.deleteBet(s.bet.id, userProvider.userId!!) .applySchedulers() .doOnSubscribe { state.value = this.state.v.copy(showLoader = true) } .doFinally { state.value = this.state.v.copy(showLoader = false) } @@ -155,7 +156,7 @@ class GameViewModel : ViewModel() { val s = state.v if (s.match == null) return if (s.bet == null) { - subs += betService.api.createBet(s.match.id, Bet(state.v.bid, state.v.scoreAsString()), userProvider.userId!!) + subs += betService.createBet(s.match.id, Bet(state.v.bid, state.v.scoreAsString()), userProvider.userId!!) .applySchedulers() .doOnSubscribe { state.value = this.state.v.copy(showLoader = true) } .doFinally { state.value = this.state.v.copy(step = Step.LIST, showLoader = false) } @@ -167,7 +168,7 @@ class GameViewModel : ViewModel() { Timber.w(it) }) } else { - subs += betService.api.updateBet(s.bet.id, Bet(state.v.bid, state.v.scoreAsString()), userProvider.userId!!) + subs += betService.updateBet(s.bet.id, Bet(state.v.bid, state.v.scoreAsString()), userProvider.userId!!) .applySchedulers() .doOnSubscribe { state.value = this.state.v.copy(showLoader = true) } .doFinally { state.value = this.state.v.copy(step = Step.LIST, showLoader = false) } @@ -245,7 +246,7 @@ class GameViewModel : ViewModel() { fun shareLinkTo(userId: String) { val betId = state.v.bet?.id ?: return - betService.api.inviteUser(betId, userId, userProvider.userId!!) + betService.inviteUser(betId, userId, userProvider.userId!!) .applySchedulers() .doOnSubscribe { state.value = this.state.v.copy(showLoader = true) } .doFinally { state.value = this.state.v.copy(showLoader = false) } diff --git a/app/src/main/java/info/czekanski/bet/domain/home/HomeFragment.kt b/app/src/main/java/info/czekanski/bet/domain/home/HomeFragment.kt index fc65127..f0a3a5b 100644 --- a/app/src/main/java/info/czekanski/bet/domain/home/HomeFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/home/HomeFragment.kt @@ -1,13 +1,15 @@ package info.czekanski.bet.domain.home -import android.arch.lifecycle.ViewModelProviders import info.czekanski.bet.domain.base.BaseHomeFragment import info.czekanski.bet.misc.safeObserve class HomeFragment : BaseHomeFragment() { override fun initializeViewModel() { - val viewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java) - viewModel.getCells().safeObserve(this, { matchesAdapter.setCells(it) }) + viewModel() + .getCells() + .safeObserve(this, { + matchesAdapter.setCells(it) + }) } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/domain/home/HomeViewModel.kt b/app/src/main/java/info/czekanski/bet/domain/home/HomeViewModel.kt index 4a6b034..e80d02a 100644 --- a/app/src/main/java/info/czekanski/bet/domain/home/HomeViewModel.kt +++ b/app/src/main/java/info/czekanski/bet/domain/home/HomeViewModel.kt @@ -10,13 +10,14 @@ import info.czekanski.bet.repository.* import info.czekanski.bet.user.UserProvider import io.reactivex.rxkotlin.* import timber.log.Timber - -class HomeViewModel : BaseHomeViewModel() { - private val betRepository by lazy { BetRepository.instance } - private val matchesRepository by lazy { MatchRepository.instance } - private val userProvider by lazy { UserProvider.instance } - private val preferencesProvider by lazy { PreferencesProvider._instance!! } // TODO: Kill it with fire!!!!! - +import javax.inject.Inject + +class HomeViewModel @Inject constructor( + private val userProvider: UserProvider, + private val betRepository: BetRepository, + private val matchesRepository: MatchRepository, + private val preferencesProvider: PreferencesProvider +) : BaseHomeViewModel() { override fun loadData() { val betsFlowable = betRepository.getBets().retry() val matchesFlowable = matchesRepository.getMatches().retry() diff --git a/app/src/main/java/info/czekanski/bet/domain/home/MatchesAdapter.kt b/app/src/main/java/info/czekanski/bet/domain/home/MatchesAdapter.kt index 25bbedb..b24f9a8 100644 --- a/app/src/main/java/info/czekanski/bet/domain/home/MatchesAdapter.kt +++ b/app/src/main/java/info/czekanski/bet/domain/home/MatchesAdapter.kt @@ -5,14 +5,16 @@ import android.support.v7.util.DiffUtil import android.support.v7.widget.RecyclerView import android.view.* import info.czekanski.bet.R -import info.czekanski.bet.domain.game.summary.cells.SummaryCell import info.czekanski.bet.domain.home.cells.* import info.czekanski.bet.domain.home.view_holder.* import info.czekanski.bet.misc.Cell +import info.czekanski.bet.user.UserProvider +import javax.inject.Inject -class MatchesAdapter( - private val callback: Callback +class MatchesAdapter @Inject constructor( + val userProvider: UserProvider ) : RecyclerView.Adapter() { + var callback: Callback = {} private var cells: List = listOf() init { @@ -23,7 +25,7 @@ class MatchesAdapter( TYPE_WELCOME -> WelcomeViewHolder(parent.inflate(R.layout.holder_home_welcome)) TYPE_HEADER -> HeaderViewHolder(parent.inflate(R.layout.holder_home_header)) TYPE_MATCH -> MatchViewHolder(parent.inflate(R.layout.holder_home_match), callback) - TYPE_BET -> BetViewHolder(parent.inflate(R.layout.holder_home_bet), callback) + TYPE_BET -> BetViewHolder(parent.inflate(R.layout.holder_home_bet), callback, userProvider) TYPE_LOADER -> StaticViewHolder(parent.inflate(R.layout.holder_home_loader)) TYPE_RESULTS -> ResultsViewHolder(parent.inflate(R.layout.holder_home_results)) TYPE_EMPTY -> EmptyViewHolder(parent.inflate(R.layout.holder_home_empty)) @@ -44,9 +46,9 @@ class MatchesAdapter( } } - override fun getItemId(position: Int): Long{ + override fun getItemId(position: Int): Long { val cell = cells[position] - return when(cell) { + return when (cell) { is WelcomeCell -> -1000 is HeaderCell -> cell.name.hashCode().toLong() is LoaderCell -> -1002 @@ -58,7 +60,7 @@ class MatchesAdapter( } } - override fun getItemViewType(position: Int) = when(cells[position]) { + override fun getItemViewType(position: Int) = when (cells[position]) { is WelcomeCell -> TYPE_WELCOME is HeaderCell -> TYPE_HEADER is MatchCell -> TYPE_MATCH @@ -70,7 +72,7 @@ class MatchesAdapter( } fun setCells(new: List) { - DiffUtil.calculateDiff(object : DiffUtil.Callback(){ + DiffUtil.calculateDiff(object : DiffUtil.Callback() { override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return cells[oldItemPosition].hashCode() == new[newItemPosition].hashCode() } diff --git a/app/src/main/java/info/czekanski/bet/domain/home/view_holder/BetViewHolder.kt b/app/src/main/java/info/czekanski/bet/domain/home/view_holder/BetViewHolder.kt index 879698d..2b887ad 100644 --- a/app/src/main/java/info/czekanski/bet/domain/home/view_holder/BetViewHolder.kt +++ b/app/src/main/java/info/czekanski/bet/domain/home/view_holder/BetViewHolder.kt @@ -2,6 +2,7 @@ package info.czekanski.bet.domain.home.view_holder import android.support.v7.widget.RecyclerView import android.view.View +import info.czekanski.bet.MyApplication import info.czekanski.bet.domain.home.Callback import info.czekanski.bet.domain.home.cells.BetCell import info.czekanski.bet.misc.* @@ -10,10 +11,14 @@ import info.czekanski.bet.network.firebase.model.FirebaseBetEntry import info.czekanski.bet.user.UserProvider import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.holder_home_bet.* +import javax.inject.Inject -class BetViewHolder(override val containerView: View, val callback: Callback) : RecyclerView.ViewHolder(containerView), LayoutContainer { - private val userProvider by lazy { UserProvider.instance } +class BetViewHolder( + override val containerView: View, + val callback: Callback, + val userProvider: UserProvider +) : RecyclerView.ViewHolder(containerView), LayoutContainer { fun bind(cell: BetCell) { val userBet = cell.bet.bets[userProvider.userId] diff --git a/app/src/main/java/info/czekanski/bet/domain/login/LoginActivity.kt b/app/src/main/java/info/czekanski/bet/domain/login/LoginActivity.kt index e688ce2..c298aa6 100644 --- a/app/src/main/java/info/czekanski/bet/domain/login/LoginActivity.kt +++ b/app/src/main/java/info/czekanski/bet/domain/login/LoginActivity.kt @@ -2,11 +2,12 @@ package info.czekanski.bet.domain.login import android.os.Bundle import android.support.v7.app.AppCompatActivity +import dagger.android.support.DaggerAppCompatActivity import info.czekanski.bet.R import info.czekanski.bet.misc.navigateWithTransition -class LoginActivity : AppCompatActivity() { +class LoginActivity : DaggerAppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/info/czekanski/bet/domain/login/LoginFragment.kt b/app/src/main/java/info/czekanski/bet/domain/login/LoginFragment.kt index d24a835..789c48d 100644 --- a/app/src/main/java/info/czekanski/bet/domain/login/LoginFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/login/LoginFragment.kt @@ -4,24 +4,24 @@ package info.czekanski.bet.domain.login import android.arch.lifecycle.* import android.content.Intent import android.os.Bundle -import android.support.v4.app.Fragment import android.text.* -import android.util.Log import android.view.* import android.widget.EditText import com.google.firebase.iid.FirebaseInstanceId import info.czekanski.bet.* import info.czekanski.bet.R +import info.czekanski.bet.di.utils.BaseFragment import info.czekanski.bet.misc.* import info.czekanski.bet.user.UserProvider import io.reactivex.Completable import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_login.* import timber.log.Timber +import javax.inject.Inject -class LoginFragment : Fragment() { +class LoginFragment : BaseFragment() { private val loading = MutableLiveData() - private val userProvider by lazy { UserProvider.instance } + @Inject lateinit var userProvider: UserProvider override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_login, container, false) @@ -47,7 +47,7 @@ class LoginFragment : Fragment() { .subscribeBy(onComplete = { goToHome() }, onError = { - Timber.d("login", it) + Timber.d(it, "login") goToHome() }) } diff --git a/app/src/main/java/info/czekanski/bet/domain/matches/MatchesFragment.kt b/app/src/main/java/info/czekanski/bet/domain/matches/MatchesFragment.kt index c8353e7..b203212 100644 --- a/app/src/main/java/info/czekanski/bet/domain/matches/MatchesFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/matches/MatchesFragment.kt @@ -1,13 +1,15 @@ package info.czekanski.bet.domain.matches -import android.arch.lifecycle.ViewModelProviders import info.czekanski.bet.domain.base.BaseHomeFragment -import info.czekanski.bet.misc.* +import info.czekanski.bet.misc.safeObserve class MatchesFragment : BaseHomeFragment() { override fun initializeViewModel() { - val viewModel = ViewModelProviders.of(this).get(MatchesViewModel::class.java) - viewModel.getCells().safeObserve(this, { matchesAdapter.setCells(it) }) + viewModel() + .getCells() + .safeObserve(this, { + matchesAdapter.setCells(it) + }) } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/domain/matches/MatchesViewModel.kt b/app/src/main/java/info/czekanski/bet/domain/matches/MatchesViewModel.kt index c767730..18836ab 100644 --- a/app/src/main/java/info/czekanski/bet/domain/matches/MatchesViewModel.kt +++ b/app/src/main/java/info/czekanski/bet/domain/matches/MatchesViewModel.kt @@ -6,10 +6,11 @@ import info.czekanski.bet.misc.Cell import info.czekanski.bet.repository.MatchRepository import io.reactivex.rxkotlin.subscribeBy import timber.log.Timber +import javax.inject.Inject -class MatchesViewModel : BaseHomeViewModel() { - private val matchesRepository by lazy { MatchRepository.instance } - +class MatchesViewModel @Inject constructor( + private val matchesRepository: MatchRepository +) : BaseHomeViewModel() { override fun loadData() { subscription = matchesRepository.getMatches() .doOnSubscribe { liveCells.value = listOf(LoaderCell()) } diff --git a/app/src/main/java/info/czekanski/bet/domain/profile/ProfileFragment.kt b/app/src/main/java/info/czekanski/bet/domain/profile/ProfileFragment.kt index a4c2798..2d95908 100644 --- a/app/src/main/java/info/czekanski/bet/domain/profile/ProfileFragment.kt +++ b/app/src/main/java/info/czekanski/bet/domain/profile/ProfileFragment.kt @@ -4,12 +4,11 @@ package info.czekanski.bet.domain.profile import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle -import android.support.v4.app.Fragment import android.support.v7.app.AlertDialog -import android.util.Log import android.view.* import android.widget.Toast import info.czekanski.bet.R +import info.czekanski.bet.di.utils.BaseFragment import info.czekanski.bet.domain.login.LoginActivity import info.czekanski.bet.misc.* import info.czekanski.bet.user.UserProvider @@ -17,9 +16,10 @@ import io.reactivex.Completable import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_profile.* import timber.log.Timber +import javax.inject.Inject -class ProfileFragment : Fragment() { - private val userProvider by lazy { UserProvider.instance } +class ProfileFragment : BaseFragment() { + @Inject lateinit var userProvider: UserProvider override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_profile, container, false) diff --git a/app/src/main/java/info/czekanski/bet/misc/FragmentExtensions.kt b/app/src/main/java/info/czekanski/bet/misc/FragmentExtensions.kt index 9c7565c..c6076ca 100644 --- a/app/src/main/java/info/czekanski/bet/misc/FragmentExtensions.kt +++ b/app/src/main/java/info/czekanski/bet/misc/FragmentExtensions.kt @@ -14,3 +14,4 @@ fun T.withArgument(arg: Parcelable): T { fun Fragment.getArgument(): T = arguments?.getParcelable("ARG")!! + diff --git a/app/src/main/java/info/czekanski/bet/network/BetService.kt b/app/src/main/java/info/czekanski/bet/network/BetService.kt deleted file mode 100644 index e15ab45..0000000 --- a/app/src/main/java/info/czekanski/bet/network/BetService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package info.czekanski.bet.network - -import retrofit2.Retrofit -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory -import retrofit2.converter.moshi.MoshiConverterFactory - -class BetService(val api: BetApi) { - - companion object { - val instance by lazy { - val retrofit = Retrofit.Builder() - .baseUrl("https://bet.czekanski.info/") - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(MoshiConverterFactory.create()) - .build() - - val api = retrofit.create(BetApi::class.java) - - return@lazy BetService(api) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/receiver/UpdateReceiver.kt b/app/src/main/java/info/czekanski/bet/receiver/UpdateReceiver.kt index 843e0b2..61fe67f 100644 --- a/app/src/main/java/info/czekanski/bet/receiver/UpdateReceiver.kt +++ b/app/src/main/java/info/czekanski/bet/receiver/UpdateReceiver.kt @@ -1,18 +1,20 @@ package info.czekanski.bet.receiver import android.content.* -import android.util.Log import com.google.firebase.iid.FirebaseInstanceId +import dagger.android.* import info.czekanski.bet.repository.PreferencesProvider import info.czekanski.bet.user.UserProvider import io.reactivex.rxkotlin.subscribeBy import timber.log.Timber +import javax.inject.Inject -class UpdateReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent?) { +class UpdateReceiver : DaggerBroadcastReceiver() { + @Inject lateinit var userProvider: UserProvider + @Inject lateinit var preferences: PreferencesProvider - val preferences = PreferencesProvider.getInstance(context) - val userProvider = UserProvider.instance + override fun onReceive(context: Context, intent: Intent?) { + super.onReceive(context, intent) if (!preferences.deviceRegistered) { val token = FirebaseInstanceId.getInstance().token @@ -24,7 +26,7 @@ class UpdateReceiver : BroadcastReceiver() { userProvider.setFcmToken(token) .subscribeBy( onComplete = { Timber.d("Success") }, - onError = { Timber.e(it,"Failure") } + onError = { Timber.e(it, "Failure") } ) } } diff --git a/app/src/main/java/info/czekanski/bet/repository/BetRepository.kt b/app/src/main/java/info/czekanski/bet/repository/BetRepository.kt index 1e0e344..793f76b 100644 --- a/app/src/main/java/info/czekanski/bet/repository/BetRepository.kt +++ b/app/src/main/java/info/czekanski/bet/repository/BetRepository.kt @@ -6,8 +6,10 @@ import info.czekanski.bet.misc.applySchedulers import info.czekanski.bet.network.firebase.model.FirebaseBet import info.czekanski.bet.user.UserProvider import io.reactivex.Flowable +import javax.inject.* -class BetRepository( +@Singleton +class BetRepository @Inject constructor( private val firestore: FirebaseFirestore, private val userProvider: UserProvider ) { @@ -28,10 +30,4 @@ class BetRepository( .map { it.toObject(FirebaseBet::class.java)!!.copy(id = it.id) } .applySchedulers() } - - companion object { - val instance by lazy { - BetRepository(FirebaseFirestore.getInstance(), UserProvider.instance) - } - } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/repository/ConfigProvider.kt b/app/src/main/java/info/czekanski/bet/repository/ConfigProvider.kt index d3a982b..9f0cbcb 100644 --- a/app/src/main/java/info/czekanski/bet/repository/ConfigProvider.kt +++ b/app/src/main/java/info/czekanski/bet/repository/ConfigProvider.kt @@ -7,9 +7,12 @@ import info.czekanski.bet.user.RxHandlerCompletable import io.reactivex.Completable import timber.log.Timber import java.util.concurrent.TimeUnit +import javax.inject.Inject -class ConfigProvider(private val remoteConfig: FirebaseRemoteConfig) { +class ConfigProvider @Inject constructor( + private val remoteConfig: FirebaseRemoteConfig +) { init { remoteConfig.setConfigSettings(FirebaseRemoteConfigSettings.Builder() .setDeveloperModeEnabled(BuildConfig.DEBUG) @@ -49,9 +52,5 @@ class ConfigProvider(private val remoteConfig: FirebaseRemoteConfig) { companion object { private const val ROUND_FLAGS = "round_flags" - - val instance by lazy { - ConfigProvider(FirebaseRemoteConfig.getInstance()) - } } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/repository/FriendsRepository.kt b/app/src/main/java/info/czekanski/bet/repository/FriendsRepository.kt index d790d85..4b340e3 100644 --- a/app/src/main/java/info/czekanski/bet/repository/FriendsRepository.kt +++ b/app/src/main/java/info/czekanski/bet/repository/FriendsRepository.kt @@ -5,8 +5,11 @@ import durdinapps.rxfirebase2.RxFirestore import info.czekanski.bet.misc.applySchedulers import info.czekanski.bet.network.firebase.model.FirebaseBet import io.reactivex.* +import javax.inject.Inject -class FriendsRepository(private val firestore: FirebaseFirestore) { +class FriendsRepository @Inject constructor( + private val firestore: FirebaseFirestore +) { private val cache = mutableMapOf() fun getFriends(userId: String): Single> { @@ -37,12 +40,6 @@ class FriendsRepository(private val firestore: FirebaseFirestore) { .doOnSuccess { nick -> cache[userId] = nick } .applySchedulers() } - - companion object { - val instance by lazy { - FriendsRepository(FirebaseFirestore.getInstance()) - } - } } data class Friend( diff --git a/app/src/main/java/info/czekanski/bet/repository/MatchRepository.kt b/app/src/main/java/info/czekanski/bet/repository/MatchRepository.kt index 89a7aee..72bb215 100644 --- a/app/src/main/java/info/czekanski/bet/repository/MatchRepository.kt +++ b/app/src/main/java/info/czekanski/bet/repository/MatchRepository.kt @@ -5,8 +5,11 @@ import durdinapps.rxfirebase2.RxFirestore import info.czekanski.bet.misc.applySchedulers import info.czekanski.bet.model.Match import io.reactivex.Flowable +import javax.inject.Inject -class MatchRepository(private val firestore: FirebaseFirestore) { +class MatchRepository @Inject constructor( + private val firestore: FirebaseFirestore +) { fun getMatches(): Flowable> { return RxFirestore.observeQueryRef(firestore.collection("matches").orderBy("date")) @@ -24,10 +27,4 @@ class MatchRepository(private val firestore: FirebaseFirestore) { .map { it.toObject(Match::class.java)!!.copy(id = it.id) } .applySchedulers() } - - companion object { - val instance by lazy { - MatchRepository(FirebaseFirestore.getInstance()) - } - } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/repository/PreferencesProvider.kt b/app/src/main/java/info/czekanski/bet/repository/PreferencesProvider.kt index 0c4f47b..9982902 100644 --- a/app/src/main/java/info/czekanski/bet/repository/PreferencesProvider.kt +++ b/app/src/main/java/info/czekanski/bet/repository/PreferencesProvider.kt @@ -1,8 +1,11 @@ package info.czekanski.bet.repository import android.content.* +import javax.inject.Inject -class PreferencesProvider(val sharedPreferences: SharedPreferences) { +class PreferencesProvider @Inject constructor( + val sharedPreferences: SharedPreferences +) { var runCount: Int get() = sharedPreferences.getInt(RUN_COUNT, 0) @@ -15,15 +18,5 @@ class PreferencesProvider(val sharedPreferences: SharedPreferences) { companion object { private const val RUN_COUNT = "runCount" private const val DEVICE_REGISTERED = "deviceRegistered" - var _instance: PreferencesProvider? = null - - fun getInstance(context: Context): PreferencesProvider { - if (_instance == null) { - _instance = PreferencesProvider(context.getSharedPreferences("preferences", Context.MODE_PRIVATE)) - } - - return _instance!! - } - } } diff --git a/app/src/main/java/info/czekanski/bet/service/FirebaseTokenRegistrationService.kt b/app/src/main/java/info/czekanski/bet/service/FirebaseTokenRegistrationService.kt index cee80f9..5dc9a29 100644 --- a/app/src/main/java/info/czekanski/bet/service/FirebaseTokenRegistrationService.kt +++ b/app/src/main/java/info/czekanski/bet/service/FirebaseTokenRegistrationService.kt @@ -1,16 +1,25 @@ package info.czekanski.bet.service import com.google.firebase.iid.* +import dagger.android.AndroidInjection +import info.czekanski.bet.MyApplication import info.czekanski.bet.user.UserProvider import io.reactivex.rxkotlin.subscribeBy import timber.log.Timber +import javax.inject.Inject class FirebaseTokenRegistrationService : FirebaseInstanceIdService() { + @Inject lateinit var userProvider: UserProvider + + override fun onCreate() { + AndroidInjection.inject(this) + super.onCreate() + } + override fun onTokenRefresh() { val token = FirebaseInstanceId.getInstance().token Timber.d("onTokenRefresh: $token") - val userProvider = UserProvider.instance if (userProvider.loggedIn && token != null) { userProvider.setFcmToken(token) .subscribeBy(onComplete = { diff --git a/app/src/main/java/info/czekanski/bet/user/UserProvider.kt b/app/src/main/java/info/czekanski/bet/user/UserProvider.kt index 66b9d5e..ad8c5d5 100644 --- a/app/src/main/java/info/czekanski/bet/user/UserProvider.kt +++ b/app/src/main/java/info/czekanski/bet/user/UserProvider.kt @@ -1,17 +1,22 @@ package info.czekanski.bet.user -import android.util.Log import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.FirebaseFirestore import durdinapps.rxfirebase2.* import info.czekanski.bet.misc.applySchedulers import info.czekanski.bet.model.TokenRequest -import info.czekanski.bet.network.BetService +import info.czekanski.bet.network.BetApi import io.reactivex.* import io.reactivex.rxkotlin.subscribeBy import timber.log.Timber - -class UserProvider private constructor(private val firestore: FirebaseFirestore, private val auth: FirebaseAuth) { +import javax.inject.* + +@Singleton +class UserProvider @Inject constructor( + private val firestore: FirebaseFirestore, + private val auth: FirebaseAuth, + private val betApi: BetApi +) { var nick: String? = null private set @@ -73,20 +78,13 @@ class UserProvider private constructor(private val firestore: FirebaseFirestore, } fun setFcmToken(fcmToken: String): Completable { - return BetService.instance.api.registerDevice(TokenRequest(fcmToken), userId!!) + return betApi.registerDevice(TokenRequest(fcmToken), userId!!) .applySchedulers() } fun removeFcmToken(): Completable { - return BetService.instance.api.unregisterDevice(userId!!) + return betApi.unregisterDevice(userId!!) .applySchedulers() } - - - companion object { - val instance by lazy { - UserProvider(FirebaseFirestore.getInstance(), FirebaseAuth.getInstance()) - } - } } \ No newline at end of file diff --git a/app/src/main/java/info/czekanski/bet/views/OctagonalImageView.kt b/app/src/main/java/info/czekanski/bet/views/OctagonalImageView.kt index 936ec2f..265e8d5 100644 --- a/app/src/main/java/info/czekanski/bet/views/OctagonalImageView.kt +++ b/app/src/main/java/info/czekanski/bet/views/OctagonalImageView.kt @@ -1,21 +1,26 @@ package info.czekanski.bet.views -import android.content.* +import android.content.Context import android.graphics.* import android.support.v7.widget.AppCompatImageView import android.util.AttributeSet +import dagger.android.AndroidInjection +import info.czekanski.bet.MyApplication +import info.czekanski.bet.di.* import info.czekanski.bet.repository.ConfigProvider +import javax.inject.Inject class OctagonalImageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppCompatImageView(context, attrs, defStyleAttr) { - private val config by lazy { ConfigProvider.instance } + @Inject lateinit var config: ConfigProvider private val sides = 8 private val octagon = Path() private val temporal = Path() init { + MyApplication.get().component.inject(this) octagon.fillType = Path.FillType.EVEN_ODD } diff --git a/build.gradle b/build.gradle index b5acf44..e656c53 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0-alpha18' + classpath 'com.android.tools.build:gradle:3.2.0-beta01' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong