diff --git a/app/src/main/java/fi/kroon/vadret/BaseApplication.kt b/app/src/main/java/fi/kroon/vadret/BaseApplication.kt index e050fa3e..b9e8ab2d 100644 --- a/app/src/main/java/fi/kroon/vadret/BaseApplication.kt +++ b/app/src/main/java/fi/kroon/vadret/BaseApplication.kt @@ -1,33 +1,19 @@ package fi.kroon.vadret import android.app.Application -import android.content.Context import com.jakewharton.threetenabp.AndroidThreeTen -import fi.kroon.vadret.di.component.CoreApplicationComponent -import fi.kroon.vadret.di.component.DaggerCoreApplicationComponent -import fi.kroon.vadret.di.modules.ContextModule -import fi.kroon.vadret.di.modules.DatabaseModule +import fi.kroon.vadret.core.CoreComponent +import fi.kroon.vadret.core.CoreComponentFactory +import fi.kroon.vadret.core.CoreComponentProvider import timber.log.Timber -abstract class BaseApplication : Application() { +abstract class BaseApplication : Application(), CoreComponentProvider { - companion object { - @JvmStatic - fun appComponent(context: Context): CoreApplicationComponent = - (context.applicationContext as BaseApplication).cmp - } - - val cmp: CoreApplicationComponent by lazy(LazyThreadSafetyMode.NONE) { - DaggerCoreApplicationComponent - .builder() - .contextModule(ContextModule(this)) - .databaseModule(DatabaseModule(this)) - .build() - } + override val coreComponent: CoreComponent + get() = CoreComponentFactory.getInstance(applicationContext) override fun onCreate() { super.onCreate() - cmp.inject(this) plantTimber() initThreeTenAbp() cacheDir.delete() diff --git a/app/src/main/java/fi/kroon/vadret/core/CoreComponent.kt b/app/src/main/java/fi/kroon/vadret/core/CoreComponent.kt new file mode 100644 index 00000000..87b9c7cf --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/CoreComponent.kt @@ -0,0 +1,44 @@ +package fi.kroon.vadret.core + +import android.content.Context +import com.afollestad.rxkprefs.RxkPrefs +import com.squareup.moshi.Moshi +import dagger.BindsInstance +import dagger.Component +import fi.kroon.vadret.core.module.ApiServiceModule +import fi.kroon.vadret.core.module.CacheModule +import fi.kroon.vadret.core.module.DatabaseModule +import fi.kroon.vadret.core.module.NetworkModule +import fi.kroon.vadret.core.module.RxkPrefsModule +import fi.kroon.vadret.data.exception.ErrorHandler +import fi.kroon.vadret.data.persistance.AppDatabase +import okhttp3.OkHttpClient +import okhttp3.internal.cache.DiskLruCache + +@CoreScope +@Component( + modules = [ + ApiServiceModule::class, + CacheModule::class, + DatabaseModule::class, + NetworkModule::class, + RxkPrefsModule::class + ] +) +interface CoreComponent { + + fun provideOkHttpClient(): OkHttpClient + fun provideAppDatabase(): AppDatabase + fun provideMoshi(): Moshi + fun provideDiskLruCache(): DiskLruCache + fun provideRxkPrefs(): RxkPrefs + fun provideErrorHandler(): ErrorHandler + + @Component.Factory + interface Factory { + fun create( + @BindsInstance + context: Context + ): CoreComponent + } +} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/core/CoreComponentFactory.kt b/app/src/main/java/fi/kroon/vadret/core/CoreComponentFactory.kt new file mode 100644 index 00000000..8eca6878 --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/CoreComponentFactory.kt @@ -0,0 +1,18 @@ +package fi.kroon.vadret.core + +import android.content.Context + +object CoreComponentFactory { + + @Volatile + private var instance: CoreComponent? = null + + fun getInstance(context: Context): CoreComponent = + instance ?: synchronized(this) { + instance ?: DaggerCoreComponent + .factory() + .create( + context = context + ).also { instance = it } + } +} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/core/CoreComponentProvider.kt b/app/src/main/java/fi/kroon/vadret/core/CoreComponentProvider.kt new file mode 100644 index 00000000..7f81608a --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/CoreComponentProvider.kt @@ -0,0 +1,5 @@ +package fi.kroon.vadret.core + +interface CoreComponentProvider { + val coreComponent: CoreComponent +} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/core/CoreScope.kt b/app/src/main/java/fi/kroon/vadret/core/CoreScope.kt new file mode 100644 index 00000000..52d71fb2 --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/CoreScope.kt @@ -0,0 +1,7 @@ +package fi.kroon.vadret.core + +import javax.inject.Scope + +@Scope +@kotlin.annotation.Retention +annotation class CoreScope \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/core/module/ApiServiceModule.kt b/app/src/main/java/fi/kroon/vadret/core/module/ApiServiceModule.kt new file mode 100644 index 00000000..133004af --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/module/ApiServiceModule.kt @@ -0,0 +1,18 @@ +package fi.kroon.vadret.core.module + +import com.squareup.moshi.Moshi +import dagger.Module +import dagger.Provides +import fi.kroon.vadret.core.CoreScope +import fi.kroon.vadret.data.common.SingleToArrayAdapter + +@Module +object ApiServiceModule { + + @Provides + @CoreScope + fun provideMoshi(): Moshi = Moshi + .Builder() + .add(SingleToArrayAdapter.INSTANCE) + .build() +} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/core/module/CacheModule.kt b/app/src/main/java/fi/kroon/vadret/core/module/CacheModule.kt new file mode 100644 index 00000000..06880db0 --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/module/CacheModule.kt @@ -0,0 +1,24 @@ +package fi.kroon.vadret.core.module + +import android.content.Context +import dagger.Module +import dagger.Provides +import fi.kroon.vadret.core.CoreScope +import fi.kroon.vadret.util.DISK_CACHE_SIZE +import okhttp3.internal.cache.DiskLruCache +import okhttp3.internal.io.FileSystem + +@Module +object CacheModule { + + @Provides + @CoreScope + fun provideDiskLruCache(context: Context): DiskLruCache = + DiskLruCache.create( + FileSystem.SYSTEM, + context.cacheDir, + 1, + 1, + DISK_CACHE_SIZE + ) +} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/core/module/DatabaseModule.kt b/app/src/main/java/fi/kroon/vadret/core/module/DatabaseModule.kt new file mode 100644 index 00000000..e182344e --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/core/module/DatabaseModule.kt @@ -0,0 +1,23 @@ +package fi.kroon.vadret.core.module + +import android.content.Context +import androidx.room.Room +import dagger.Module +import dagger.Provides +import fi.kroon.vadret.core.CoreScope +import fi.kroon.vadret.data.persistance.AppDatabase +import fi.kroon.vadret.util.DATABASE_NAME + +@Module +object DatabaseModule { + + @Provides + @CoreScope + fun provideAppDatabase( + context: Context + ): AppDatabase = Room.databaseBuilder( + context, + AppDatabase::class.java, + DATABASE_NAME + ).build() +} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/NetworkModule.kt b/app/src/main/java/fi/kroon/vadret/core/module/NetworkModule.kt similarity index 87% rename from app/src/main/java/fi/kroon/vadret/di/modules/NetworkModule.kt rename to app/src/main/java/fi/kroon/vadret/core/module/NetworkModule.kt index bb67ad8d..8139c80f 100644 --- a/app/src/main/java/fi/kroon/vadret/di/modules/NetworkModule.kt +++ b/app/src/main/java/fi/kroon/vadret/core/module/NetworkModule.kt @@ -1,10 +1,11 @@ -package fi.kroon.vadret.di.modules +package fi.kroon.vadret.core.module import android.content.Context import dagger.Module import dagger.Provides import fi.kroon.vadret.BuildConfig -import fi.kroon.vadret.di.scope.CoreApplicationScope +import fi.kroon.vadret.core.CoreScope +import fi.kroon.vadret.data.exception.ErrorHandler import okhttp3.Cache import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor @@ -12,11 +13,7 @@ import java.io.File import java.util.concurrent.TimeUnit import javax.inject.Qualifier -@Module( - includes = [ - ContextModule::class - ] -) +@Module object NetworkModule { private const val DEFAULT_CONNECTION_TIMEOUT = 10000L @@ -37,14 +34,18 @@ object NetworkModule { } @Provides - @CoreApplicationScope + @CoreScope + fun provideFailureHandler(): ErrorHandler = ErrorHandler() + + @Provides + @CoreScope fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor() .apply { level = getLogLevel } @Provides @InternalApi - @CoreApplicationScope + @CoreScope fun provideCache( context: Context ): Cache = Cache( @@ -56,7 +57,7 @@ object NetworkModule { ) @Provides - @CoreApplicationScope + @CoreScope fun provideOkHttpClient( httpLoggingInterceptor: HttpLoggingInterceptor, @InternalApi diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/RxkPrefsModule.kt b/app/src/main/java/fi/kroon/vadret/core/module/RxkPrefsModule.kt similarity index 55% rename from app/src/main/java/fi/kroon/vadret/di/modules/RxkPrefsModule.kt rename to app/src/main/java/fi/kroon/vadret/core/module/RxkPrefsModule.kt index c5263791..16713327 100644 --- a/app/src/main/java/fi/kroon/vadret/di/modules/RxkPrefsModule.kt +++ b/app/src/main/java/fi/kroon/vadret/core/module/RxkPrefsModule.kt @@ -1,22 +1,17 @@ -package fi.kroon.vadret.di.modules +package fi.kroon.vadret.core.module import android.content.Context import com.afollestad.rxkprefs.RxkPrefs import com.afollestad.rxkprefs.rxkPrefs import dagger.Module import dagger.Provides -import fi.kroon.vadret.data.exception.ErrorHandler -import fi.kroon.vadret.di.scope.CoreApplicationScope +import fi.kroon.vadret.core.CoreScope import fi.kroon.vadret.util.DEFAULT_SETTINGS @Module object RxkPrefsModule { @Provides - @CoreApplicationScope + @CoreScope fun provideRxkPrefs(context: Context): RxkPrefs = rxkPrefs(context, DEFAULT_SETTINGS) - - @Provides - @CoreApplicationScope - fun provideFailureHandler(): ErrorHandler = ErrorHandler() } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/data/aggregatedfeed/AggregatedFeedRepository.kt b/app/src/main/java/fi/kroon/vadret/data/aggregatedfeed/AggregatedFeedRepository.kt index c0bf76b3..e9257cb6 100644 --- a/app/src/main/java/fi/kroon/vadret/data/aggregatedfeed/AggregatedFeedRepository.kt +++ b/app/src/main/java/fi/kroon/vadret/data/aggregatedfeed/AggregatedFeedRepository.kt @@ -8,7 +8,6 @@ import fi.kroon.vadret.data.exception.ExceptionHandler import fi.kroon.vadret.data.exception.IErrorHandler import fi.kroon.vadret.data.exception.IExceptionHandler import fi.kroon.vadret.data.failure.Failure -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.NetworkHandler import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asRight @@ -17,7 +16,6 @@ import io.reactivex.Single import retrofit2.Response import javax.inject.Inject -@CoreApplicationScope class AggregatedFeedRepository @Inject constructor( private val networkHandler: NetworkHandler, private val netDataSource: Lazy, diff --git a/app/src/main/java/fi/kroon/vadret/data/district/DistrictRepository.kt b/app/src/main/java/fi/kroon/vadret/data/district/DistrictRepository.kt index 514484c7..a0894055 100644 --- a/app/src/main/java/fi/kroon/vadret/data/district/DistrictRepository.kt +++ b/app/src/main/java/fi/kroon/vadret/data/district/DistrictRepository.kt @@ -8,7 +8,6 @@ import fi.kroon.vadret.data.exception.ExceptionHandler import fi.kroon.vadret.data.exception.IErrorHandler import fi.kroon.vadret.data.exception.IExceptionHandler import fi.kroon.vadret.data.failure.Failure -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.NetworkHandler import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asRight @@ -17,7 +16,6 @@ import io.reactivex.Single import retrofit2.Response import javax.inject.Inject -@CoreApplicationScope class DistrictRepository @Inject constructor( private val networkHandler: NetworkHandler, private val networkDataSource: Lazy, diff --git a/app/src/main/java/fi/kroon/vadret/data/exception/ErrorHandler.kt b/app/src/main/java/fi/kroon/vadret/data/exception/ErrorHandler.kt index 5e9d499c..be050c73 100644 --- a/app/src/main/java/fi/kroon/vadret/data/exception/ErrorHandler.kt +++ b/app/src/main/java/fi/kroon/vadret/data/exception/ErrorHandler.kt @@ -1,13 +1,11 @@ package fi.kroon.vadret.data.exception import fi.kroon.vadret.data.failure.Failure -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asSingle import io.github.sphrak.either.Either import io.reactivex.Single -@CoreApplicationScope class ErrorHandler : IErrorHandler { override fun getNetworkError(throwable: Throwable): Single> = diff --git a/app/src/main/java/fi/kroon/vadret/data/exception/ExceptionHandler.kt b/app/src/main/java/fi/kroon/vadret/data/exception/ExceptionHandler.kt index 2e0cb70e..ab8769f1 100644 --- a/app/src/main/java/fi/kroon/vadret/data/exception/ExceptionHandler.kt +++ b/app/src/main/java/fi/kroon/vadret/data/exception/ExceptionHandler.kt @@ -1,13 +1,11 @@ package fi.kroon.vadret.data.exception import fi.kroon.vadret.data.failure.Failure -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.extension.empty import java.net.SocketTimeoutException import java.net.UnknownHostException import javax.inject.Inject -@CoreApplicationScope class ExceptionHandler @Inject constructor() : IExceptionHandler { override fun invoke(throwable: Throwable): Failure = when (throwable) { diff --git a/app/src/main/java/fi/kroon/vadret/data/feedsource/FeedSourceRepository.kt b/app/src/main/java/fi/kroon/vadret/data/feedsource/FeedSourceRepository.kt index 1abf4cfa..94dbea48 100644 --- a/app/src/main/java/fi/kroon/vadret/data/feedsource/FeedSourceRepository.kt +++ b/app/src/main/java/fi/kroon/vadret/data/feedsource/FeedSourceRepository.kt @@ -8,7 +8,6 @@ import fi.kroon.vadret.data.exception.IExceptionHandler import fi.kroon.vadret.data.failure.Failure import fi.kroon.vadret.data.feedsource.model.FeedSource import fi.kroon.vadret.data.feedsource.net.FeedSourceNetDataSource -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.NetworkHandler import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asRight @@ -17,7 +16,6 @@ import io.reactivex.Single import retrofit2.Response import javax.inject.Inject -@CoreApplicationScope class FeedSourceRepository @Inject constructor( private val networkHandler: NetworkHandler, private val feedSourceNetDataSource: Lazy, diff --git a/app/src/main/java/fi/kroon/vadret/data/location/local/LocationLocalDataSource.kt b/app/src/main/java/fi/kroon/vadret/data/location/local/LocationLocalDataSource.kt index 071dd57c..5c659c1a 100644 --- a/app/src/main/java/fi/kroon/vadret/data/location/local/LocationLocalDataSource.kt +++ b/app/src/main/java/fi/kroon/vadret/data/location/local/LocationLocalDataSource.kt @@ -9,6 +9,7 @@ import fi.kroon.vadret.data.failure.Failure import fi.kroon.vadret.data.location.exception.LocationFailure import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asRight +import fi.kroon.vadret.util.extension.lazyAndroid import io.github.sphrak.either.Either import timber.log.Timber import javax.inject.Inject @@ -17,11 +18,11 @@ class LocationLocalDataSource @Inject constructor( private val locationManager: LocationManager ) { - private val isGPSEnabled: Boolean by lazy(LazyThreadSafetyMode.NONE) { + private val isGPSEnabled: Boolean by lazyAndroid { locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) } - private val isNetworkLocationProviderEnabled: Boolean by lazy(LazyThreadSafetyMode.NONE) { + private val isNetworkLocationProviderEnabled: Boolean by lazyAndroid { locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) } diff --git a/app/src/main/java/fi/kroon/vadret/data/nominatim/NominatimRepository.kt b/app/src/main/java/fi/kroon/vadret/data/nominatim/NominatimRepository.kt index 245e9275..784c1d69 100644 --- a/app/src/main/java/fi/kroon/vadret/data/nominatim/NominatimRepository.kt +++ b/app/src/main/java/fi/kroon/vadret/data/nominatim/NominatimRepository.kt @@ -11,7 +11,6 @@ import fi.kroon.vadret.data.nominatim.model.Nominatim import fi.kroon.vadret.data.nominatim.model.NominatimOut import fi.kroon.vadret.data.nominatim.model.NominatimReverseOut import fi.kroon.vadret.data.nominatim.net.NominatimNetDataSource -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.NetworkHandler import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asRight @@ -20,7 +19,6 @@ import io.reactivex.Single import retrofit2.Response import javax.inject.Inject -@CoreApplicationScope class NominatimRepository @Inject constructor( private val nominatimNetDataSource: Lazy, private val networkHandler: NetworkHandler, diff --git a/app/src/main/java/fi/kroon/vadret/data/radar/RadarRepository.kt b/app/src/main/java/fi/kroon/vadret/data/radar/RadarRepository.kt index a219a63c..f9710084 100644 --- a/app/src/main/java/fi/kroon/vadret/data/radar/RadarRepository.kt +++ b/app/src/main/java/fi/kroon/vadret/data/radar/RadarRepository.kt @@ -10,7 +10,6 @@ import fi.kroon.vadret.data.radar.exception.RadarFailure import fi.kroon.vadret.data.radar.model.Radar import fi.kroon.vadret.data.radar.model.RadarRequest import fi.kroon.vadret.data.radar.net.RadarNetDataSource -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.NetworkHandler import fi.kroon.vadret.util.extension.asLeft import fi.kroon.vadret.util.extension.asRight @@ -20,7 +19,6 @@ import retrofit2.Response import timber.log.Timber import javax.inject.Inject -@CoreApplicationScope class RadarRepository @Inject constructor( private val radarNetDataSource: Lazy, private val networkHandler: NetworkHandler, diff --git a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/WeatherForecastRepository.kt b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/WeatherForecastRepository.kt index 92d6a52b..ad746811 100644 --- a/app/src/main/java/fi/kroon/vadret/data/weatherforecast/WeatherForecastRepository.kt +++ b/app/src/main/java/fi/kroon/vadret/data/weatherforecast/WeatherForecastRepository.kt @@ -10,7 +10,6 @@ import fi.kroon.vadret.data.weatherforecast.exception.WeatherForecastFailure import fi.kroon.vadret.data.weatherforecast.model.Weather import fi.kroon.vadret.data.weatherforecast.model.WeatherOut import fi.kroon.vadret.data.weatherforecast.net.WeatherForecastNetDataSource -import fi.kroon.vadret.di.scope.CoreApplicationScope import fi.kroon.vadret.util.HTTP_200_OK import fi.kroon.vadret.util.HTTP_204_NO_CONTENT import fi.kroon.vadret.util.HTTP_400_BAD_REQUEST @@ -27,7 +26,6 @@ import io.reactivex.Single import retrofit2.Response import javax.inject.Inject -@CoreApplicationScope class WeatherForecastRepository @Inject constructor( private val weatherForecastNetDataSource: Lazy, private val networkHandler: NetworkHandler, diff --git a/app/src/main/java/fi/kroon/vadret/di/component/CoreApplicationComponent.kt b/app/src/main/java/fi/kroon/vadret/di/component/CoreApplicationComponent.kt deleted file mode 100644 index e17ca01a..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/component/CoreApplicationComponent.kt +++ /dev/null @@ -1,47 +0,0 @@ -package fi.kroon.vadret.di.component - -import android.app.Application -import com.afollestad.rxkprefs.RxkPrefs -import dagger.Component -import fi.kroon.vadret.di.modules.ApiServiceModule -import fi.kroon.vadret.di.modules.CacheModule -import fi.kroon.vadret.di.modules.DatabaseModule -import fi.kroon.vadret.di.modules.LocationServiceModule -import fi.kroon.vadret.di.modules.NetworkModule -import fi.kroon.vadret.di.modules.RxkPrefsModule -import fi.kroon.vadret.di.modules.SchedulerModule -import fi.kroon.vadret.di.modules.ServiceModule -import fi.kroon.vadret.di.scope.CoreApplicationScope -import fi.kroon.vadret.presentation.main.di.MainActivityComponent -import fi.kroon.vadret.presentation.radar.di.RadarComponent -import fi.kroon.vadret.presentation.warning.display.di.WarningComponent -import fi.kroon.vadret.presentation.warning.filter.di.WarningFilterComponent -import fi.kroon.vadret.presentation.weatherforecast.di.WeatherForecastComponent - -@CoreApplicationScope -@Component( - modules = [ - ApiServiceModule::class, - CacheModule::class, - DatabaseModule::class, - NetworkModule::class, - ServiceModule::class, - RxkPrefsModule::class, - SchedulerModule::class, - LocationServiceModule::class - ] -) -interface CoreApplicationComponent { - - fun inject(application: Application) - - fun rxkPrefs(rxkPrefs: RxkPrefs) - - fun mainActivityComponentBuilder(): MainActivityComponent.Builder - fun radarComponentBuilder(): RadarComponent.Builder - - fun warningComponentBuilder(): WarningComponent.Builder - fun warningFilterComponentBuilder(): WarningFilterComponent.Builder - - fun weatherForecastComponentBuilder(): WeatherForecastComponent.Builder -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/ApiServiceModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/ApiServiceModule.kt deleted file mode 100644 index c873b684..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/ApiServiceModule.kt +++ /dev/null @@ -1,136 +0,0 @@ -package fi.kroon.vadret.di.modules - -import com.squareup.moshi.Moshi -import dagger.Lazy -import dagger.Module -import dagger.Provides -import fi.kroon.vadret.data.aggregatedfeed.net.AggregatedFeedNetDataSource -import fi.kroon.vadret.data.common.SingleToArrayAdapter -import fi.kroon.vadret.data.district.net.DistrictNetDataSource -import fi.kroon.vadret.data.feedsource.net.FeedSourceNetDataSource -import fi.kroon.vadret.data.nominatim.net.NominatimNetDataSource -import fi.kroon.vadret.data.radar.net.RadarNetDataSource -import fi.kroon.vadret.data.weatherforecast.net.WeatherForecastNetDataSource -import fi.kroon.vadret.di.qualifiers.Alert -import fi.kroon.vadret.di.qualifiers.KrisInformation -import fi.kroon.vadret.di.qualifiers.Nominatim -import fi.kroon.vadret.di.qualifiers.Radar -import fi.kroon.vadret.di.qualifiers.Weather -import fi.kroon.vadret.di.scope.CoreApplicationScope -import fi.kroon.vadret.util.KRISINFORMATION_API_URL -import fi.kroon.vadret.util.NOMINATIM_BASE_API_URL -import fi.kroon.vadret.util.SMHI_API_ALERT_URL -import fi.kroon.vadret.util.SMHI_API_FORECAST_URL -import fi.kroon.vadret.util.SMHI_API_RADAR_URL -import fi.kroon.vadret.util.extension.assertNoInitMainThread -import fi.kroon.vadret.util.extension.delegatingCallFactory -import okhttp3.OkHttpClient -import retrofit2.Retrofit -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory -import retrofit2.converter.moshi.MoshiConverterFactory - -@Module -object ApiServiceModule { - - @Provides - @CoreApplicationScope - fun provideWeatherApi(@Weather retrofit: Retrofit): WeatherForecastNetDataSource = - retrofit.create(WeatherForecastNetDataSource::class.java) - - @Provides - @CoreApplicationScope - fun provideRadarApi(@Radar retrofit: Retrofit): RadarNetDataSource = - retrofit.create(RadarNetDataSource::class.java) - - @Provides - @CoreApplicationScope - fun provideNominatimApi(@Nominatim retrofit: Retrofit): NominatimNetDataSource = - retrofit.create(NominatimNetDataSource::class.java) - - @Provides - @CoreApplicationScope - fun provideDistrictViewApi(@Alert retrofit: Retrofit): DistrictNetDataSource = - retrofit.create(DistrictNetDataSource::class.java) - - @Provides - @CoreApplicationScope - fun provideFeedSourceApi(@KrisInformation retrofit: Retrofit): FeedSourceNetDataSource = - retrofit.create(FeedSourceNetDataSource::class.java) - - @Provides - @CoreApplicationScope - fun provideAggregatedFeedApi(@KrisInformation retrofit: Retrofit): AggregatedFeedNetDataSource = - retrofit.create(AggregatedFeedNetDataSource::class.java) - - @Provides - @CoreApplicationScope - fun provideMoshi(): Moshi = Moshi - .Builder() - .add(SingleToArrayAdapter.INSTANCE) - .build() - - @Nominatim - @Provides - @CoreApplicationScope - fun provideRetrofitNominatim(okHttpClient: Lazy, moshi: Moshi): Retrofit { - assertNoInitMainThread() - return Retrofit.Builder() - .baseUrl(NOMINATIM_BASE_API_URL) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .delegatingCallFactory(okHttpClient) - .build() - } - - @Weather - @Provides - @CoreApplicationScope - fun provideRetrofitWeather(okHttpClient: Lazy, moshi: Moshi): Retrofit { - assertNoInitMainThread() - return Retrofit.Builder() - .baseUrl(SMHI_API_FORECAST_URL) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .delegatingCallFactory(okHttpClient) - .build() - } - - @Alert - @Provides - @CoreApplicationScope - fun provideRetrofitAlert(okHttpClient: Lazy, moshi: Moshi): Retrofit { - assertNoInitMainThread() - return Retrofit.Builder() - .baseUrl(SMHI_API_ALERT_URL) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .delegatingCallFactory(okHttpClient) - .build() - } - - @KrisInformation - @Provides - @CoreApplicationScope - fun provideRetrofitKrisInformation(okHttpClient: Lazy, moshi: Moshi): Retrofit { - assertNoInitMainThread() - return Retrofit.Builder() - .baseUrl(KRISINFORMATION_API_URL) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .delegatingCallFactory(okHttpClient) - .build() - } - - @Radar - @Provides - @CoreApplicationScope - fun provideRetrofitRadar(okHttpClient: Lazy, moshi: Moshi): Retrofit { - assertNoInitMainThread() - return Retrofit.Builder() - .baseUrl(SMHI_API_RADAR_URL) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .delegatingCallFactory(okHttpClient) - .build() - } -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/CacheModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/CacheModule.kt deleted file mode 100644 index 226c4ab1..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/CacheModule.kt +++ /dev/null @@ -1,41 +0,0 @@ -package fi.kroon.vadret.di.modules - -import android.content.Context -import androidx.collection.LruCache -import dagger.Module -import dagger.Provides -import fi.kroon.vadret.data.aggregatedfeed.model.AggregatedFeed -import fi.kroon.vadret.data.radar.model.Radar -import fi.kroon.vadret.data.weatherforecast.model.Weather -import fi.kroon.vadret.di.scope.CoreApplicationScope -import fi.kroon.vadret.util.DISK_CACHE_SIZE -import fi.kroon.vadret.util.MEMORY_CACHE_SIZE -import okhttp3.internal.cache.DiskLruCache -import okhttp3.internal.io.FileSystem - -@Module -object CacheModule { - - @Provides - @CoreApplicationScope - fun provideDiskLruCache(context: Context): DiskLruCache = - DiskLruCache.create( - FileSystem.SYSTEM, - context.cacheDir, - 1, - 1, - DISK_CACHE_SIZE - ) - - @Provides - @CoreApplicationScope - fun provideWeatherLruCache(): LruCache = LruCache(MEMORY_CACHE_SIZE) - - @Provides - @CoreApplicationScope - fun provideAggregatedFeedLruCache(): LruCache> = LruCache(MEMORY_CACHE_SIZE) - - @Provides - @CoreApplicationScope - fun provideRadarLruCache(): LruCache = LruCache(MEMORY_CACHE_SIZE) -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/ContextModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/ContextModule.kt deleted file mode 100644 index fa760399..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/ContextModule.kt +++ /dev/null @@ -1,15 +0,0 @@ -package fi.kroon.vadret.di.modules - -import android.app.Application -import android.content.Context -import dagger.Module -import dagger.Provides -import fi.kroon.vadret.di.scope.CoreApplicationScope - -@Module -class ContextModule(private val application: Application) { - - @Provides - @CoreApplicationScope - fun provideContext(): Context = application -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/DatabaseModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/DatabaseModule.kt deleted file mode 100644 index 9e465007..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/DatabaseModule.kt +++ /dev/null @@ -1,49 +0,0 @@ -package fi.kroon.vadret.di.modules - -import android.app.Application -import androidx.room.Room -import dagger.Module -import dagger.Provides -import fi.kroon.vadret.data.district.local.DistrictDao -import fi.kroon.vadret.data.districtpreference.local.DistrictPreferenceDao -import fi.kroon.vadret.data.feedsource.local.FeedSourceDao -import fi.kroon.vadret.data.feedsourcepreference.local.FeedSourcePreferenceDao -import fi.kroon.vadret.data.persistance.AppDatabase -import fi.kroon.vadret.di.scope.CoreApplicationScope -import fi.kroon.vadret.util.DATABASE_NAME - -@Module( - includes = [ - ContextModule::class - ] -) -class DatabaseModule(private val application: Application) { - - @Provides - @CoreApplicationScope - fun provideAppDatabase(): AppDatabase = Room.databaseBuilder( - application, - AppDatabase::class.java, - DATABASE_NAME - ).build() - - @Provides - @CoreApplicationScope - fun provideDistrictDao(appDatabase: AppDatabase): DistrictDao = - appDatabase.districtDao() - - @Provides - @CoreApplicationScope - fun provideDistrictPreferenceDao(appDatabase: AppDatabase): DistrictPreferenceDao = - appDatabase.districtPreferenceDao() - - @Provides - @CoreApplicationScope - fun provideFeedSourceDao(appDatabase: AppDatabase): FeedSourceDao = - appDatabase.feedSourceDao() - - @Provides - @CoreApplicationScope - fun provideFeedSourcePreferenceDao(appDatabase: AppDatabase): FeedSourcePreferenceDao = - appDatabase.feedSourcePreferenceDao() -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/LocationServiceModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/LocationServiceModule.kt deleted file mode 100644 index f65e16d9..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/LocationServiceModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package fi.kroon.vadret.di.modules - -import android.content.Context -import android.location.LocationManager -import dagger.Module -import dagger.Provides -import fi.kroon.vadret.data.location.local.LocationLocalDataSource -import fi.kroon.vadret.di.scope.CoreApplicationScope - -@Module -object LocationServiceModule { - - @Provides - @CoreApplicationScope - fun provideLocationManager(context: Context): LocationManager = - context.getSystemService(Context.LOCATION_SERVICE) as LocationManager - - @Provides - @CoreApplicationScope - fun provideLocationProvider(locationManager: LocationManager): LocationLocalDataSource = - LocationLocalDataSource(locationManager) -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/SchedulerModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/SchedulerModule.kt deleted file mode 100644 index bb8f0048..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/SchedulerModule.kt +++ /dev/null @@ -1,14 +0,0 @@ -package fi.kroon.vadret.di.modules - -import dagger.Module -import dagger.Provides -import fi.kroon.vadret.di.scope.CoreApplicationScope -import fi.kroon.vadret.util.Scheduler - -@Module -object SchedulerModule { - - @Provides - @CoreApplicationScope - fun provideSchedulers(): Scheduler = Scheduler() -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/modules/ServiceModule.kt b/app/src/main/java/fi/kroon/vadret/di/modules/ServiceModule.kt deleted file mode 100644 index f3e33155..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/modules/ServiceModule.kt +++ /dev/null @@ -1,15 +0,0 @@ -package fi.kroon.vadret.di.modules - -import dagger.Binds -import dagger.Module -import fi.kroon.vadret.di.scope.CoreApplicationScope -import fi.kroon.vadret.util.common.DateTimeUtil -import fi.kroon.vadret.util.common.IDateTimeUtil - -@Module -abstract class ServiceModule { - - @Binds - @CoreApplicationScope - abstract fun bindsDateTimeUtil(dateTimeUtil: DateTimeUtil): IDateTimeUtil -} \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/qualifiers/Weather.kt b/app/src/main/java/fi/kroon/vadret/di/qualifiers/WeatherQualifier.kt similarity index 71% rename from app/src/main/java/fi/kroon/vadret/di/qualifiers/Weather.kt rename to app/src/main/java/fi/kroon/vadret/di/qualifiers/WeatherQualifier.kt index 30550a81..e9a3a955 100644 --- a/app/src/main/java/fi/kroon/vadret/di/qualifiers/Weather.kt +++ b/app/src/main/java/fi/kroon/vadret/di/qualifiers/WeatherQualifier.kt @@ -3,4 +3,4 @@ package fi.kroon.vadret.di.qualifiers import javax.inject.Qualifier @Qualifier -annotation class Weather \ No newline at end of file +annotation class WeatherQualifier \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/di/scope/CoreApplicationScope.kt b/app/src/main/java/fi/kroon/vadret/di/scope/CoreApplicationScope.kt deleted file mode 100644 index 2681059b..00000000 --- a/app/src/main/java/fi/kroon/vadret/di/scope/CoreApplicationScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package fi.kroon.vadret.di.scope - -import javax.inject.Scope - -@Scope -@kotlin.annotation.Retention -annotation class CoreApplicationScope \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/AboutAppFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/AboutAppFragment.kt index a1c30be0..f1140485 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/AboutAppFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/AboutAppFragment.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.lifecycleScope import fi.kroon.vadret.R import fi.kroon.vadret.presentation.aboutapp.di.AboutAppComponent import fi.kroon.vadret.presentation.aboutapp.di.DaggerAboutAppComponent +import fi.kroon.vadret.util.extension.lazyAndroid import kotlinx.android.synthetic.main.about_app_fragment.* import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect @@ -17,13 +18,13 @@ class AboutAppFragment : Fragment(R.layout.about_app_fragment) { private lateinit var aboutAppFragmentPagerAdapter: AboutAppFragmentPagerAdapter - private val component: AboutAppComponent by lazy(LazyThreadSafetyMode.NONE) { + private val component: AboutAppComponent by lazyAndroid { DaggerAboutAppComponent .factory() .create(context = requireContext()) } - private val viewModel: AboutAppViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: AboutAppViewModel by lazyAndroid { component.provideViewModel() } diff --git a/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/about/AboutAppAboutFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/about/AboutAppAboutFragment.kt index 51cd4669..8fe898bf 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/about/AboutAppAboutFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/about/AboutAppAboutFragment.kt @@ -10,6 +10,7 @@ import fi.kroon.vadret.R import fi.kroon.vadret.data.aboutinfo.model.AboutInfo import fi.kroon.vadret.presentation.aboutapp.about.di.AboutAppAboutComponent import fi.kroon.vadret.presentation.aboutapp.about.di.DaggerAboutAppAboutComponent +import fi.kroon.vadret.util.extension.lazyAndroid import kotlinx.android.synthetic.main.about_app_about_fragment.* import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect @@ -25,13 +26,13 @@ class AboutAppAboutFragment : Fragment(R.layout.about_app_about_fragment) { private lateinit var aboutAppAboutAdapter: AboutAppAboutAdapter - private val component: AboutAppAboutComponent by lazy(LazyThreadSafetyMode.NONE) { + private val component: AboutAppAboutComponent by lazyAndroid { DaggerAboutAppAboutComponent .factory() .create(context = requireContext()) } - private val viewModel: AboutAppAboutViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: AboutAppAboutViewModel by lazyAndroid { component.provideViewModel() } diff --git a/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/library/AboutAppLibraryFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/library/AboutAppLibraryFragment.kt index 0ccc3351..e5d251ef 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/library/AboutAppLibraryFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/aboutapp/library/AboutAppLibraryFragment.kt @@ -10,6 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import fi.kroon.vadret.R import fi.kroon.vadret.presentation.aboutapp.library.di.AboutAppLibraryComponent import fi.kroon.vadret.presentation.aboutapp.library.di.DaggerAboutAppLibraryComponent +import fi.kroon.vadret.util.extension.lazyAndroid import kotlinx.android.synthetic.main.about_app_library_fragment.* import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect @@ -25,11 +26,11 @@ class AboutAppLibraryFragment : Fragment(R.layout.about_app_library_fragment) { private lateinit var aboutAppLibraryAdapter: AboutAppLibraryAdapter - private val viewModel: AboutAppLibraryViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: AboutAppLibraryViewModel by lazyAndroid { component.provideViewModel() } - private val component: AboutAppLibraryComponent by lazy(LazyThreadSafetyMode.NONE) { + private val component: AboutAppLibraryComponent by lazyAndroid { DaggerAboutAppLibraryComponent .factory() .create(context = requireContext()) diff --git a/app/src/main/java/fi/kroon/vadret/presentation/main/MainActivity.kt b/app/src/main/java/fi/kroon/vadret/presentation/main/MainActivity.kt index 3232b937..7dc6579c 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/main/MainActivity.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/main/MainActivity.kt @@ -8,11 +8,13 @@ import com.google.android.material.bottomnavigation.BottomNavigationView import fi.kroon.vadret.R import fi.kroon.vadret.data.failure.Failure import fi.kroon.vadret.data.theme.model.Theme +import fi.kroon.vadret.presentation.main.di.DaggerMainActivityComponent import fi.kroon.vadret.presentation.main.di.MainActivityComponent import fi.kroon.vadret.presentation.shared.BaseActivity import fi.kroon.vadret.util.DEFAULT_SETTINGS import fi.kroon.vadret.util.Scheduler -import fi.kroon.vadret.util.extension.appComponent +import fi.kroon.vadret.util.extension.coreComponent +import fi.kroon.vadret.util.extension.lazyAndroid import fi.kroon.vadret.util.extension.toObservable import io.reactivex.Observable import io.reactivex.disposables.CompositeDisposable @@ -23,26 +25,26 @@ import timber.log.Timber class MainActivity : BaseActivity() { - private val cmp: MainActivityComponent by lazy(LazyThreadSafetyMode.NONE) { - appComponent() - .mainActivityComponentBuilder() - .build() + private val component: MainActivityComponent by lazyAndroid { + DaggerMainActivityComponent + .factory() + .create(context = this, coreComponent = coreComponent) } - private val subscriptions: CompositeDisposable by lazy(LazyThreadSafetyMode.NONE) { - cmp.provideCompositeDisposable() + private val subscriptions: CompositeDisposable by lazyAndroid { + component.provideCompositeDisposable() } - private val scheduler: Scheduler by lazy(LazyThreadSafetyMode.NONE) { - cmp.provideScheduler() + private val scheduler: Scheduler by lazyAndroid { + component.provideScheduler() } - private val viewModel: MainActivityViewModel by lazy(LazyThreadSafetyMode.NONE) { - cmp.provideMainActivityViewModel() + private val viewModel: MainActivityViewModel by lazyAndroid { + component.provideMainActivityViewModel() } - private val onViewInitialisedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { - cmp.provideOnViewInitialised() + private val onViewInitialisedSubject: PublishSubject by lazyAndroid { + component.provideOnViewInitialised() } /** diff --git a/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityComponent.kt b/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityComponent.kt index 61378326..c50506ad 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityComponent.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityComponent.kt @@ -1,15 +1,21 @@ package fi.kroon.vadret.presentation.main.di -import dagger.Subcomponent +import android.content.Context +import dagger.BindsInstance +import dagger.Component +import fi.kroon.vadret.core.CoreComponent import fi.kroon.vadret.presentation.main.MainActivityView import fi.kroon.vadret.presentation.main.MainActivityViewModel import fi.kroon.vadret.util.Scheduler import io.reactivex.disposables.CompositeDisposable import io.reactivex.subjects.PublishSubject -@Subcomponent( +@Component( modules = [ MainActivityModule::class + ], + dependencies = [ + CoreComponent::class ] ) @MainActivityScope @@ -20,9 +26,12 @@ interface MainActivityComponent { fun provideCompositeDisposable(): CompositeDisposable fun provideScheduler(): Scheduler - @Subcomponent.Builder - interface Builder { - fun mainActivityModule(module: MainActivityModule): Builder - fun build(): MainActivityComponent + @Component.Factory + interface Factory { + fun create( + @BindsInstance + context: Context, + coreComponent: CoreComponent + ): MainActivityComponent } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityModule.kt b/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityModule.kt index 1b938755..b989695e 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityModule.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/main/di/MainActivityModule.kt @@ -3,6 +3,7 @@ package fi.kroon.vadret.presentation.main.di import dagger.Module import dagger.Provides import fi.kroon.vadret.presentation.main.MainActivityView +import fi.kroon.vadret.util.Scheduler import io.reactivex.disposables.CompositeDisposable import io.reactivex.subjects.PublishSubject @@ -10,18 +11,19 @@ import io.reactivex.subjects.PublishSubject object MainActivityModule { @Provides - @JvmStatic @MainActivityScope fun provideViewState(): MainActivityView.State = MainActivityView.State() @Provides - @JvmStatic @MainActivityScope fun provideOnViewInitialisedSubject(): PublishSubject = PublishSubject.create() @Provides - @JvmStatic @MainActivityScope fun provideCompositeDisposable(): CompositeDisposable = CompositeDisposable() + + @Provides + @MainActivityScope + fun provideSchedulers(): Scheduler = Scheduler() } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/radar/RadarFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/radar/RadarFragment.kt index 04491fbe..2a6ae92f 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/radar/RadarFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/radar/RadarFragment.kt @@ -1,6 +1,5 @@ package fi.kroon.vadret.presentation.radar -import android.content.Context import android.graphics.Bitmap import android.graphics.drawable.Drawable import android.os.Bundle @@ -13,6 +12,7 @@ import com.jakewharton.rxbinding3.widget.changes import com.jakewharton.rxbinding3.widget.userChanges import fi.kroon.vadret.BuildConfig import fi.kroon.vadret.R +import fi.kroon.vadret.presentation.radar.di.DaggerRadarComponent import fi.kroon.vadret.presentation.radar.di.RadarComponent import fi.kroon.vadret.presentation.shared.BaseFragment import fi.kroon.vadret.util.DEFAULT_BOUNDINGBOX_CENTER_LATITUDE @@ -27,7 +27,8 @@ import fi.kroon.vadret.util.MAXIMUM_ZOOM_LEVEL import fi.kroon.vadret.util.MINIMUM_ZOOM_LEVEL import fi.kroon.vadret.util.RADAR_DEBOUNCE_MILLIS import fi.kroon.vadret.util.WIKIMEDIA_TILE_SOURCE_URL -import fi.kroon.vadret.util.extension.appComponent +import fi.kroon.vadret.util.extension.coreComponent +import fi.kroon.vadret.util.extension.lazyAndroid import fi.kroon.vadret.util.extension.snack import fi.kroon.vadret.util.extension.toObservable import io.reactivex.Observable @@ -35,7 +36,9 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable import io.reactivex.rxkotlin.addTo import io.reactivex.subjects.PublishSubject -import kotlinx.android.synthetic.main.radar_fragment.* +import kotlinx.android.synthetic.main.radar_fragment.radarMapView +import kotlinx.android.synthetic.main.radar_fragment.radarPlayFab +import kotlinx.android.synthetic.main.radar_fragment.radarSeekBar import org.osmdroid.config.Configuration import org.osmdroid.config.IConfigurationProvider import org.osmdroid.tileprovider.tilesource.XYTileSource @@ -63,61 +66,85 @@ class RadarFragment : BaseFragment() { private var bundle: Bundle? = null private var stateParcel: RadarView.StateParcel? = null - private val component: RadarComponent by lazy(LazyThreadSafetyMode.NONE) { - appComponent() - .radarComponentBuilder() - .build() + private val component: RadarComponent by lazyAndroid { + DaggerRadarComponent + .factory() + .create(context = requireContext(), coreComponent = coreComponent) + } + + private val scheduler by lazyAndroid { + component.provideScheduler() } - private val imageLoader: ImageLoader by lazy(LazyThreadSafetyMode.NONE) { + private val imageLoader: ImageLoader by lazyAndroid { component.provideImageLoader() } - private val viewModel: RadarViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: RadarViewModel by lazyAndroid { component.provideRadarViewModel() } - private val onViewInitialisedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onViewInitialisedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnViewInitialised() } - private val onFailureHandledSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onFailureHandledSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnFailureHandled() } - private val onRadarImageDisplayedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onRadarImageDisplayedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnRadarImageDisplayed() } - private val onSeekBarStoppedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onSeekBarStoppedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnSeekBarStopped() } - private val onStateParcelUpdatedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onStateParcelUpdatedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnStateParcelUpdated() } - private val onPlayButtonStartedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onPlayButtonStartedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnPlayButtonStarted() } - private val onPlayButtonStoppedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onPlayButtonStoppedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnPlayButtonStopped() } - private val onSeekBarResetSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onSeekBarResetSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnSeekBarReset() } - private val onPositionUpdatedSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onPositionUpdatedSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnPositionUpdated() } - private val onSeekBarRestoredSubject: PublishSubject by lazy(LazyThreadSafetyMode.NONE) { + private val onSeekBarRestoredSubject: PublishSubject by lazy( + LazyThreadSafetyMode.NONE + ) { component.provideOnSeekBarRestored() } - private val subscriptions: CompositeDisposable by lazy(LazyThreadSafetyMode.NONE) { + private val subscriptions: CompositeDisposable by lazyAndroid { component.provideCompositeDisposable() } @@ -142,13 +169,6 @@ class RadarFragment : BaseFragment() { ) } - override fun onAttach(context: Context) { - super.onAttach(context) - Timber.d("-----BEGIN-----") - Timber.d("ON ATTACH") - component.inject(this) - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupMapViewConfiguration() @@ -430,8 +450,7 @@ class RadarFragment : BaseFragment() { .link ) .target( - onStart = { - _ -> + onStart = { _ -> Unit }, onSuccess = { result: Drawable -> diff --git a/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarComponent.kt b/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarComponent.kt index 357129aa..d0cb99f2 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarComponent.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarComponent.kt @@ -1,23 +1,27 @@ package fi.kroon.vadret.presentation.radar.di +import android.content.Context import coil.ImageLoader -import dagger.Subcomponent -import fi.kroon.vadret.presentation.radar.RadarFragment +import dagger.BindsInstance +import dagger.Component +import fi.kroon.vadret.core.CoreComponent import fi.kroon.vadret.presentation.radar.RadarView import fi.kroon.vadret.presentation.radar.RadarViewModel +import fi.kroon.vadret.util.Scheduler import io.reactivex.disposables.CompositeDisposable import io.reactivex.subjects.PublishSubject -@Subcomponent( +@Component( modules = [ RadarModule::class + ], + dependencies = [ + CoreComponent::class ] ) @RadarScope interface RadarComponent { - fun inject(radarFragment: RadarFragment) - /** * ViewModel */ @@ -38,10 +42,14 @@ interface RadarComponent { fun provideOnSeekBarRestored(): PublishSubject fun provideCompositeDisposable(): CompositeDisposable fun provideImageLoader(): ImageLoader + fun provideScheduler(): Scheduler - @Subcomponent.Builder - interface Builder { - fun radarModule(module: RadarModule): Builder - fun build(): RadarComponent + @Component.Factory + interface Factory { + fun create( + @BindsInstance + context: Context, + coreComponent: CoreComponent + ): RadarComponent } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarModule.kt b/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarModule.kt index 1c8ae4a8..98fd684a 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarModule.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/radar/di/RadarModule.kt @@ -1,12 +1,28 @@ package fi.kroon.vadret.presentation.radar.di import android.content.Context +import androidx.collection.LruCache import coil.ImageLoader +import com.squareup.moshi.Moshi +import dagger.Lazy import dagger.Module import dagger.Provides +import fi.kroon.vadret.data.radar.net.RadarNetDataSource +import fi.kroon.vadret.di.qualifiers.Radar import fi.kroon.vadret.presentation.radar.RadarView +import fi.kroon.vadret.util.MEMORY_CACHE_SIZE +import fi.kroon.vadret.util.SMHI_API_RADAR_URL +import fi.kroon.vadret.util.Scheduler +import fi.kroon.vadret.util.common.DateTimeUtil +import fi.kroon.vadret.util.common.IDateTimeUtil +import fi.kroon.vadret.util.extension.assertNoInitMainThread +import fi.kroon.vadret.util.extension.delegatingCallFactory import io.reactivex.disposables.CompositeDisposable import io.reactivex.subjects.PublishSubject +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.moshi.MoshiConverterFactory @Module object RadarModule { @@ -77,4 +93,39 @@ object RadarModule { .availableMemoryPercentage(0.25) .crossfade(true) .build() + + @Radar + @Provides + @RadarScope + fun provideRetrofitRadar(okHttpClient: Lazy, moshi: Moshi): Retrofit { + assertNoInitMainThread() + return Retrofit.Builder() + .baseUrl(SMHI_API_RADAR_URL) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .delegatingCallFactory(okHttpClient) + .build() + } + + @Provides + @RadarScope + fun provideRadarApi( + @Radar + retrofit: Retrofit + ): RadarNetDataSource = + retrofit.create(RadarNetDataSource::class.java) + + @Provides + @RadarScope + fun provideSchedulers(): Scheduler = Scheduler() + + @Provides + @RadarScope + fun provideRadarLruCache(): LruCache = LruCache( + MEMORY_CACHE_SIZE + ) + + @Provides + @RadarScope + fun provideDateTimeUtil(dateTimeUtil: DateTimeUtil): IDateTimeUtil = dateTimeUtil } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/shared/BaseFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/shared/BaseFragment.kt index 3c6b7cec..099506db 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/shared/BaseFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/shared/BaseFragment.kt @@ -7,9 +7,7 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import fi.kroon.vadret.data.nominatim.model.Locality import fi.kroon.vadret.presentation.main.MainActivity -import fi.kroon.vadret.util.Scheduler import timber.log.Timber -import javax.inject.Inject abstract class BaseFragment : Fragment() { @@ -17,9 +15,6 @@ abstract class BaseFragment : Fragment() { abstract fun renderError(errorCode: Int) - @Inject - lateinit var scheduler: Scheduler - var isConfigChangeOrProcessDeath = false override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningFragment.kt index 60e59a28..1d487ecf 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningFragment.kt @@ -9,9 +9,11 @@ import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import fi.kroon.vadret.R +import fi.kroon.vadret.presentation.warning.display.di.DaggerWarningComponent import fi.kroon.vadret.presentation.warning.display.di.WarningComponent import fi.kroon.vadret.presentation.warning.display.model.IWarningModel -import fi.kroon.vadret.util.extension.appComponent +import fi.kroon.vadret.util.extension.coreComponent +import fi.kroon.vadret.util.extension.lazyAndroid import fi.kroon.vadret.util.extension.snack import fi.kroon.vadret.util.extension.toGone import fi.kroon.vadret.util.extension.toVisible @@ -35,6 +37,8 @@ class WarningFragment : Fragment(R.layout.warning_display_fragment) { companion object { const val STATE_PARCEL_KEY: String = "STATE_PARCEL_KEY" const val SCROLL_POSITION_KEY: String = "SCROLL_POSITION_KEY" + const val WARNING_FILTER_DIALOG_RESULT = "warning_filter_dialog_result" + const val RESULT_OK = "result_ok" } private var recyclerViewParcelable: Parcelable? = null @@ -42,21 +46,21 @@ class WarningFragment : Fragment(R.layout.warning_display_fragment) { private var bundle: Bundle? = null private var isConfigChangeOrProcessDeath: Boolean = false - private val component: WarningComponent by lazy(LazyThreadSafetyMode.NONE) { - appComponent() - .warningComponentBuilder() - .build() + private val component: WarningComponent by lazyAndroid { + DaggerWarningComponent + .factory() + .create(context = requireContext(), coreComponent = coreComponent) } - private val warningAdapter: WarningAdapter by lazy(LazyThreadSafetyMode.NONE) { + private val warningAdapter: WarningAdapter by lazyAndroid { component.provideWarningAdapter() } - private val viewModel: WarningViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: WarningViewModel by lazyAndroid { component.provideWarningViewModel() } - private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { + private val navController: NavController by lazyAndroid { findNavController() } @@ -86,6 +90,7 @@ class WarningFragment : Fragment(R.layout.warning_display_fragment) { .viewState .collect(::render) } + listenForWarningFilterDialogResult() setup() } @@ -198,7 +203,7 @@ class WarningFragment : Fragment(R.layout.warning_display_fragment) { private fun navigateToFilterView() { navController - .navigate(R.id.action_warningFragment_to_warningFilterDialog) + .navigate(R.id.warningFilterDialog) } private fun displayNoWarningsIssued() { @@ -263,4 +268,16 @@ class WarningFragment : Fragment(R.layout.warning_display_fragment) { warningAdapter.updateList(list) viewModel.send(WarningView.Event.OnWarningListDisplayed) } + + private fun listenForWarningFilterDialogResult() { + navController.currentBackStackEntry + ?.savedStateHandle + ?.getLiveData(WARNING_FILTER_DIALOG_RESULT) + ?.observe( + viewLifecycleOwner, + { + viewModel.send(WarningView.Event.OnWarningFilterResult(it)) + } + ) + } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningView.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningView.kt index a10c28c1..6ee905c6 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningView.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningView.kt @@ -18,6 +18,7 @@ object WarningView { object OnWarningListDisplayed : Event() object OnScrollPositionRestored : Event() object OnStateParcelUpdated : Event() + data class OnWarningFilterResult(val result: String) : Event() } data class State( diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningViewModel.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningViewModel.kt index 46a2f193..718458fe 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningViewModel.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/WarningViewModel.kt @@ -16,6 +16,7 @@ import fi.kroon.vadret.domain.warning.CountFeedSourcePreferenceEntityTask import fi.kroon.vadret.domain.warning.SetDefaultDistrictPreferenceEntityService import fi.kroon.vadret.domain.warning.SetDefaultFeedSourcePreferenceEntityService import fi.kroon.vadret.presentation.shared.IViewModel +import fi.kroon.vadret.presentation.warning.display.WarningFragment.Companion.RESULT_OK import fi.kroon.vadret.presentation.warning.display.model.IWarningModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -44,7 +45,6 @@ class WarningViewModel @Inject constructor( private val setDefaultDistrictPreferenceEntityService: SetDefaultDistrictPreferenceEntityService, private val setDefaultFeedSourcePreferenceEntityService: SetDefaultFeedSourcePreferenceEntityService ) : ViewModel(), IViewModel { - // TODO IViewModel replace it? val viewState: SharedFlow get() = state.asSharedFlow() @@ -54,7 +54,7 @@ class WarningViewModel @Inject constructor( private suspend fun reduce(event: WarningView.Event): Unit = when (event) { - is WarningView.Event.OnViewInitialised -> onViewInitialisedEvent(event) + is WarningView.Event.OnViewInitialised -> onViewInitialisedEvent(event.stateParcel) WarningView.Event.OnFailureHandled -> onFailureHandledEvent() WarningView.Event.OnProgressBarEffectStarted -> onProgressBarEffectStartedEvent() WarningView.Event.OnProgressBarEffectStopped -> onProgressBarEffectStoppedEvent() @@ -64,8 +64,19 @@ class WarningViewModel @Inject constructor( WarningView.Event.OnStateParcelUpdated -> onStateParcelUpdatedEvent() WarningView.Event.OnFilterButtonToggled -> onFilterButtonToggled() WarningView.Event.OnNoWarningsIssuedDisplayed -> onNoWarningsIssuedDisplayed() + is WarningView.Event.OnWarningFilterResult -> onWarningFilterResult(event.result) } + private suspend fun onWarningFilterResult(result: String) { + if (result == RESULT_OK) { + stateModel = stateModel.copy(renderEvent = WarningView.RenderEvent.None) + onViewInitialisedEvent(null) + } else { + stateModel = stateModel.copy(renderEvent = WarningView.RenderEvent.None) + state.emit(stateModel) + } + } + private suspend fun onNoWarningsIssuedDisplayed() = endLoadingWarning() @@ -236,8 +247,8 @@ class WarningViewModel @Inject constructor( state.emit(stateModel) } - private suspend fun onViewInitialisedEvent(event: WarningView.Event.OnViewInitialised) = withContext(Dispatchers.IO) { - restoreStateFromStateParcel(event.stateParcel) + private suspend fun onViewInitialisedEvent(stateParcel: WarningView.StateParcel?) = withContext(Dispatchers.IO) { + restoreStateFromStateParcel(stateParcel) updateStateToLoadingAndRefreshing() preLoadingWarning() } diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningComponent.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningComponent.kt index 9e5ff7f1..893b2122 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningComponent.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningComponent.kt @@ -1,12 +1,20 @@ package fi.kroon.vadret.presentation.warning.display.di -import dagger.Subcomponent +import android.content.Context +import dagger.BindsInstance +import dagger.Component +import fi.kroon.vadret.core.CoreComponent import fi.kroon.vadret.presentation.warning.display.WarningAdapter import fi.kroon.vadret.presentation.warning.display.WarningViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi -@Subcomponent( +@ExperimentalCoroutinesApi +@Component( modules = [ WarningModule::class + ], + dependencies = [ + CoreComponent::class ] ) @WarningScope @@ -15,9 +23,12 @@ interface WarningComponent { fun provideWarningViewModel(): WarningViewModel fun provideWarningAdapter(): WarningAdapter - @Subcomponent.Builder - interface Builder { - fun warningModule(module: WarningModule): Builder - fun build(): WarningComponent + @Component.Factory + interface Factory { + fun create( + @BindsInstance + context: Context, + coreComponent: CoreComponent + ): WarningComponent } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningModule.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningModule.kt index 4059dad0..09078766 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningModule.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/display/di/WarningModule.kt @@ -1,10 +1,33 @@ package fi.kroon.vadret.presentation.warning.display.di +import androidx.collection.LruCache +import com.squareup.moshi.Moshi +import dagger.Lazy import dagger.Module import dagger.Provides +import fi.kroon.vadret.data.aggregatedfeed.model.AggregatedFeed +import fi.kroon.vadret.data.aggregatedfeed.net.AggregatedFeedNetDataSource +import fi.kroon.vadret.data.district.local.DistrictDao +import fi.kroon.vadret.data.district.net.DistrictNetDataSource +import fi.kroon.vadret.data.districtpreference.local.DistrictPreferenceDao +import fi.kroon.vadret.data.feedsource.local.FeedSourceDao +import fi.kroon.vadret.data.feedsource.net.FeedSourceNetDataSource +import fi.kroon.vadret.data.feedsourcepreference.local.FeedSourcePreferenceDao +import fi.kroon.vadret.data.persistance.AppDatabase +import fi.kroon.vadret.di.qualifiers.Alert +import fi.kroon.vadret.di.qualifiers.KrisInformation import fi.kroon.vadret.presentation.warning.display.WarningView +import fi.kroon.vadret.util.KRISINFORMATION_API_URL +import fi.kroon.vadret.util.MEMORY_CACHE_SIZE +import fi.kroon.vadret.util.SMHI_API_ALERT_URL +import fi.kroon.vadret.util.extension.assertNoInitMainThread +import fi.kroon.vadret.util.extension.delegatingCallFactory import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.moshi.MoshiConverterFactory @Module @ExperimentalCoroutinesApi @@ -18,4 +41,71 @@ object WarningModule { @Provides @WarningScope fun provideSharedFlowState(): MutableSharedFlow = MutableSharedFlow() + + @Provides + @WarningScope + fun provideDistrictViewApi(@Alert retrofit: Retrofit): DistrictNetDataSource = + retrofit.create(DistrictNetDataSource::class.java) + + @Provides + @WarningScope + fun provideFeedSourceApi(@KrisInformation retrofit: Retrofit): FeedSourceNetDataSource = + retrofit.create(FeedSourceNetDataSource::class.java) + + @Provides + @WarningScope + fun provideAggregatedFeedApi(@KrisInformation retrofit: Retrofit): AggregatedFeedNetDataSource = + retrofit.create(AggregatedFeedNetDataSource::class.java) + + @Provides + @WarningScope + fun provideAggregatedFeedLruCache(): LruCache> = LruCache( + MEMORY_CACHE_SIZE + ) + + @Provides + @WarningScope + fun provideDistrictDao(appDatabase: AppDatabase): DistrictDao = + appDatabase.districtDao() + + @Provides + @WarningScope + fun provideFeedSourceDao(appDatabase: AppDatabase): FeedSourceDao = + appDatabase.feedSourceDao() + + @Provides + @WarningScope + fun provideDistrictPreferenceDao(appDatabase: AppDatabase): DistrictPreferenceDao = + appDatabase.districtPreferenceDao() + + @Provides + @WarningScope + fun provideFeedSourcePreferenceDao(appDatabase: AppDatabase): FeedSourcePreferenceDao = + appDatabase.feedSourcePreferenceDao() + + @Alert + @Provides + @WarningScope + fun provideRetrofitAlert(okHttpClient: Lazy, moshi: Moshi): Retrofit { + assertNoInitMainThread() + return Retrofit.Builder() + .baseUrl(SMHI_API_ALERT_URL) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .delegatingCallFactory(okHttpClient) + .build() + } + + @KrisInformation + @Provides + @WarningScope + fun provideRetrofitKrisInformation(okHttpClient: Lazy, moshi: Moshi): Retrofit { + assertNoInitMainThread() + return Retrofit.Builder() + .baseUrl(KRISINFORMATION_API_URL) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .delegatingCallFactory(okHttpClient) + .build() + } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/WarningFilterDialogFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/WarningFilterDialogFragment.kt index 63c40c62..2b45cb47 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/WarningFilterDialogFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/WarningFilterDialogFragment.kt @@ -11,13 +11,21 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.bottomsheet.BottomSheetDialogFragment import fi.kroon.vadret.R +import fi.kroon.vadret.presentation.warning.display.WarningFragment.Companion.RESULT_OK +import fi.kroon.vadret.presentation.warning.display.WarningFragment.Companion.WARNING_FILTER_DIALOG_RESULT +import fi.kroon.vadret.presentation.warning.filter.di.DaggerWarningFilterComponent import fi.kroon.vadret.presentation.warning.filter.di.WarningFilterComponent import fi.kroon.vadret.presentation.warning.filter.model.IFilterable -import fi.kroon.vadret.util.extension.appComponent +import fi.kroon.vadret.util.extension.coreComponent +import fi.kroon.vadret.util.extension.lazyAndroid +import kotlinx.android.synthetic.main.warning_filter_dialog_fragment.warningFilterApplyButton import kotlinx.android.synthetic.main.warning_filter_dialog_fragment.warningFilterRecyclerView import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import ru.ldralighieri.corbind.view.clicks import timber.log.Timber @ExperimentalCoroutinesApi @@ -34,17 +42,17 @@ class WarningFilterDialogFragment : BottomSheetDialogFragment() { private lateinit var warningFilterAdapter: WarningFilterAdapter - private val navController: NavController by lazy(LazyThreadSafetyMode.NONE) { + private val navController: NavController by lazyAndroid { findNavController() } - private val component: WarningFilterComponent by lazy(LazyThreadSafetyMode.NONE) { - appComponent() - .warningFilterComponentBuilder() - .build() + private val component: WarningFilterComponent by lazyAndroid { + DaggerWarningFilterComponent + .factory() + .create(context = requireContext(), coreComponent = coreComponent) } - private val viewModel: WarningFilterViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: WarningFilterViewModel by lazyAndroid { component.provideWarningFilterViewModel() } @@ -153,6 +161,17 @@ class WarningFilterDialogFragment : BottomSheetDialogFragment() { } private fun setupEvents() { + + warningFilterApplyButton + .clicks() + .map { + viewModel.send( + WarningFilterView + .Event + .OnFilterOptionsApplyClicked + ) + }.launchIn(lifecycleScope) + viewModel.send( WarningFilterView .Event @@ -192,6 +211,14 @@ class WarningFilterDialogFragment : BottomSheetDialogFragment() { private fun finishDialog() { Timber.d("FINISH DIALOG") + + navController.previousBackStackEntry + ?.savedStateHandle + ?.set( + WARNING_FILTER_DIALOG_RESULT, + RESULT_OK + ) + navController.popBackStack() } diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterComponent.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterComponent.kt index a1964ab2..bb54252f 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterComponent.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterComponent.kt @@ -1,13 +1,19 @@ package fi.kroon.vadret.presentation.warning.filter.di -import dagger.Subcomponent +import android.content.Context +import dagger.BindsInstance +import dagger.Component +import fi.kroon.vadret.core.CoreComponent import fi.kroon.vadret.presentation.warning.filter.WarningFilterViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi @ExperimentalCoroutinesApi -@Subcomponent( +@Component( modules = [ WarningFilterModule::class + ], + dependencies = [ + CoreComponent::class ] ) @WarningFilterScope @@ -15,9 +21,12 @@ interface WarningFilterComponent { fun provideWarningFilterViewModel(): WarningFilterViewModel - @Subcomponent.Builder - interface Builder { - fun warningFilterModule(module: WarningFilterModule): Builder - fun build(): WarningFilterComponent + @Component.Factory + interface Factory { + fun create( + @BindsInstance + context: Context, + coreComponent: CoreComponent + ): WarningFilterComponent } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterModule.kt b/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterModule.kt index 5ab742cb..41e3df26 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterModule.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/warning/filter/di/WarningFilterModule.kt @@ -2,6 +2,9 @@ package fi.kroon.vadret.presentation.warning.filter.di import dagger.Module import dagger.Provides +import fi.kroon.vadret.data.districtpreference.local.DistrictPreferenceDao +import fi.kroon.vadret.data.feedsourcepreference.local.FeedSourcePreferenceDao +import fi.kroon.vadret.data.persistance.AppDatabase import fi.kroon.vadret.presentation.warning.filter.WarningFilterView import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow @@ -18,4 +21,14 @@ object WarningFilterModule { @Provides @WarningFilterScope fun provideSharedFlowState(): MutableSharedFlow = MutableSharedFlow() + + @Provides + @WarningFilterScope + fun provideDistrictPreferenceDao(appDatabase: AppDatabase): DistrictPreferenceDao = + appDatabase.districtPreferenceDao() + + @Provides + @WarningFilterScope + fun provideFeedSourcePreferenceDao(appDatabase: AppDatabase): FeedSourcePreferenceDao = + appDatabase.feedSourcePreferenceDao() } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastFragment.kt b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastFragment.kt index 427aa6f3..c982cd89 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastFragment.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastFragment.kt @@ -5,9 +5,7 @@ import android.content.Context import android.graphics.drawable.Drawable import android.os.Bundle import android.os.Parcelable -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -18,8 +16,10 @@ import fi.kroon.vadret.R import fi.kroon.vadret.data.nominatim.model.Locality import fi.kroon.vadret.presentation.main.MainActivity import fi.kroon.vadret.presentation.weatherforecast.autocomplete.AutoCompleteAdapter +import fi.kroon.vadret.presentation.weatherforecast.di.DaggerWeatherForecastComponent import fi.kroon.vadret.presentation.weatherforecast.di.WeatherForecastComponent -import fi.kroon.vadret.util.extension.appComponent +import fi.kroon.vadret.util.extension.coreComponent +import fi.kroon.vadret.util.extension.lazyAndroid import fi.kroon.vadret.util.extension.toGone import fi.kroon.vadret.util.extension.toInvisible import fi.kroon.vadret.util.extension.toVisible @@ -47,7 +47,7 @@ import timber.log.Timber @ExperimentalCoroutinesApi @FlowPreview @RuntimePermissions -class WeatherForecastFragment : Fragment() { +class WeatherForecastFragment : Fragment(R.layout.weather_forecast_fragment) { private companion object { const val STATE_PARCEL_KEY: String = "STATE_PARCEL_KEY" @@ -59,40 +59,36 @@ class WeatherForecastFragment : Fragment() { private var bundle: Bundle? = null private var recyclerViewParcelable: Parcelable? = null - private val component: WeatherForecastComponent by lazy(LazyThreadSafetyMode.NONE) { - appComponent() - .weatherForecastComponentBuilder() - .build() + private val component: WeatherForecastComponent by lazyAndroid { + DaggerWeatherForecastComponent + .factory() + .create(context = requireContext(), coreComponent = coreComponent) } - private val viewModel: WeatherForecastViewModel by lazy(LazyThreadSafetyMode.NONE) { + private val viewModel: WeatherForecastViewModel by lazyAndroid { component.provideWeatherForecastViewModel() } - private val eventChannel: ConflatedBroadcastChannel by lazy(LazyThreadSafetyMode.NONE) { + private val eventChannel: ConflatedBroadcastChannel by lazyAndroid { component.provideEventChannel() } - private val weatherForecastAdapter: WeatherForecastAdapter by lazy(LazyThreadSafetyMode.NONE) { + private val weatherForecastAdapter: WeatherForecastAdapter by lazyAndroid { component.provideWeatherForecastAdapter() } - private val autoCompleteAdapter: AutoCompleteAdapter by lazy(LazyThreadSafetyMode.NONE) { + private val autoCompleteAdapter: AutoCompleteAdapter by lazyAndroid { component.provideAutoCompleteAdapter() } - private val itemDecoration: DividerItemDecoration by lazy(LazyThreadSafetyMode.NONE) { + private val itemDecoration: DividerItemDecoration by lazyAndroid { DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) } - private val drawable: Drawable? by lazy(LazyThreadSafetyMode.NONE) { + private val drawable: Drawable? by lazyAndroid { ContextCompat.getDrawable(requireContext(), R.drawable.search_item_divider) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.weather_forecast_fragment, container, false) - } - override fun onAttach(context: Context) { Timber.d("ON ATTACH -- WEATHER FORECAST") super.onAttach(context) diff --git a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastViewModel.kt b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastViewModel.kt index 57ae834b..8fbae962 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastViewModel.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/WeatherForecastViewModel.kt @@ -12,7 +12,6 @@ import fi.kroon.vadret.domain.weatherforecast.SetLocationInformationTask import fi.kroon.vadret.domain.weatherforecast.SetLocationModeTask import fi.kroon.vadret.domain.weatherforecast.SetWeatherForecastLastCheckedTask import fi.kroon.vadret.presentation.shared.IViewModel -import fi.kroon.vadret.presentation.weatherforecast.di.WeatherForecastScope import fi.kroon.vadret.util.extension.empty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -28,7 +27,6 @@ import javax.inject.Inject @FlowPreview @ExperimentalCoroutinesApi -@WeatherForecastScope class WeatherForecastViewModel @Inject constructor( private var state: WeatherForecastView.State, private val eventChannel: ConflatedBroadcastChannel, diff --git a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastComponent.kt b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastComponent.kt index 825d946c..4dfb1de4 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastComponent.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastComponent.kt @@ -1,6 +1,9 @@ package fi.kroon.vadret.presentation.weatherforecast.di -import dagger.Subcomponent +import android.content.Context +import dagger.BindsInstance +import dagger.Component +import fi.kroon.vadret.core.CoreComponent import fi.kroon.vadret.presentation.weatherforecast.WeatherForecastAdapter import fi.kroon.vadret.presentation.weatherforecast.WeatherForecastView import fi.kroon.vadret.presentation.weatherforecast.WeatherForecastViewModel @@ -9,31 +12,31 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.ConflatedBroadcastChannel -@ExperimentalCoroutinesApi @FlowPreview -@Subcomponent( +@ExperimentalCoroutinesApi +@WeatherForecastScope +@Component( modules = [ WeatherForecastModule::class + ], + dependencies = [ + CoreComponent::class ] ) -@WeatherForecastScope interface WeatherForecastComponent { - /** - * ViewModel - */ fun provideWeatherForecastViewModel(): WeatherForecastViewModel fun provideEventChannel(): ConflatedBroadcastChannel - /** - * Adapter - */ fun provideWeatherForecastAdapter(): WeatherForecastAdapter fun provideAutoCompleteAdapter(): AutoCompleteAdapter - @Subcomponent.Builder - interface Builder { - fun forecastModule(module: WeatherForecastModule): Builder - fun build(): WeatherForecastComponent + @Component.Factory + interface Factory { + fun create( + @BindsInstance + context: Context, + coreComponent: CoreComponent + ): WeatherForecastComponent } } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt index 38d29d91..96dda4e9 100644 --- a/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt +++ b/app/src/main/java/fi/kroon/vadret/presentation/weatherforecast/di/WeatherForecastModule.kt @@ -1,10 +1,31 @@ package fi.kroon.vadret.presentation.weatherforecast.di +import android.content.Context +import android.location.LocationManager +import androidx.collection.LruCache +import com.squareup.moshi.Moshi +import dagger.Lazy import dagger.Module import dagger.Provides +import fi.kroon.vadret.data.location.local.LocationLocalDataSource +import fi.kroon.vadret.data.nominatim.net.NominatimNetDataSource +import fi.kroon.vadret.data.weatherforecast.model.Weather +import fi.kroon.vadret.data.weatherforecast.net.WeatherForecastNetDataSource +import fi.kroon.vadret.di.qualifiers.Nominatim +import fi.kroon.vadret.di.qualifiers.WeatherQualifier import fi.kroon.vadret.presentation.weatherforecast.WeatherForecastView +import fi.kroon.vadret.util.MEMORY_CACHE_SIZE +import fi.kroon.vadret.util.NOMINATIM_BASE_API_URL +import fi.kroon.vadret.util.SMHI_API_FORECAST_URL +import fi.kroon.vadret.util.Scheduler +import fi.kroon.vadret.util.extension.assertNoInitMainThread +import fi.kroon.vadret.util.extension.delegatingCallFactory import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.ConflatedBroadcastChannel +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.converter.moshi.MoshiConverterFactory @Module @ExperimentalCoroutinesApi @@ -18,4 +39,60 @@ object WeatherForecastModule { @Provides @WeatherForecastScope fun provideViewState(): WeatherForecastView.State = WeatherForecastView.State() + + @Provides + @WeatherForecastScope + fun provideSchedulers(): Scheduler = Scheduler() + + @WeatherQualifier + @Provides + @WeatherForecastScope + fun provideRetrofitWeather(okHttpClient: Lazy, moshi: Moshi): Retrofit { + assertNoInitMainThread() + return Retrofit.Builder() + .baseUrl(SMHI_API_FORECAST_URL) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .delegatingCallFactory(okHttpClient) + .build() + } + + @Nominatim + @Provides + @WeatherForecastScope + fun provideRetrofitNominatim(okHttpClient: Lazy, moshi: Moshi): Retrofit { + assertNoInitMainThread() + return Retrofit.Builder() + .baseUrl(NOMINATIM_BASE_API_URL) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .delegatingCallFactory(okHttpClient) + .build() + } + + @Provides + @WeatherForecastScope + fun provideWeatherApi(@WeatherQualifier retrofit: Retrofit): WeatherForecastNetDataSource = + retrofit.create(WeatherForecastNetDataSource::class.java) + + @Provides + @WeatherForecastScope + fun provideNominatimApi(@Nominatim retrofit: Retrofit): NominatimNetDataSource = + retrofit.create(NominatimNetDataSource::class.java) + + @Provides + @WeatherForecastScope + fun provideLocationManager(context: Context): LocationManager = + context.getSystemService(Context.LOCATION_SERVICE) as LocationManager + + @Provides + @WeatherForecastScope + fun provideLocationProvider(locationManager: LocationManager): LocationLocalDataSource = + LocationLocalDataSource(locationManager) + + @Provides + @WeatherForecastScope + fun provideWeatherLruCache(): LruCache = LruCache( + MEMORY_CACHE_SIZE + ) } \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/util/extension/Activity.kt b/app/src/main/java/fi/kroon/vadret/util/extension/Activity.kt deleted file mode 100644 index 15c433b2..00000000 --- a/app/src/main/java/fi/kroon/vadret/util/extension/Activity.kt +++ /dev/null @@ -1,9 +0,0 @@ -package fi.kroon.vadret.util.extension - -import android.app.Activity -import fi.kroon.vadret.BaseApplication -import fi.kroon.vadret.di.component.CoreApplicationComponent - -fun Activity.appComponent(): CoreApplicationComponent = - BaseApplication - .appComponent(this) \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/util/extension/AppCompatActivity.kt b/app/src/main/java/fi/kroon/vadret/util/extension/AppCompatActivity.kt new file mode 100644 index 00000000..406af60f --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/util/extension/AppCompatActivity.kt @@ -0,0 +1,12 @@ +package fi.kroon.vadret.util.extension + +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import fi.kroon.vadret.core.CoreComponent +import fi.kroon.vadret.core.CoreComponentProvider + +val AppCompatActivity.coreComponent: CoreComponent + get(): CoreComponent = (applicationContext as CoreComponentProvider).coreComponent + +val Fragment.coreComponent: CoreComponent + get(): CoreComponent = (requireContext().applicationContext as CoreComponentProvider).coreComponent \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/util/extension/Fragment.kt b/app/src/main/java/fi/kroon/vadret/util/extension/Fragment.kt index cb2d47c4..aa018172 100644 --- a/app/src/main/java/fi/kroon/vadret/util/extension/Fragment.kt +++ b/app/src/main/java/fi/kroon/vadret/util/extension/Fragment.kt @@ -6,7 +6,6 @@ import android.widget.Toast import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.google.android.material.snackbar.Snackbar -import fi.kroon.vadret.BaseApplication fun Fragment.hideKeyboard() { val imm = requireContext() @@ -17,7 +16,6 @@ fun Fragment.hideKeyboard() { } fun Context.toast(message: String, duration: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, message, duration).show() -fun Fragment.appComponent() = BaseApplication.appComponent(requireContext().applicationContext) inline fun Fragment.snack(@StringRes messageRes: Int, length: Int = Snackbar.LENGTH_LONG, init: Snackbar.() -> Unit = {}) { return view!!.snack(context!!.getString(messageRes), length, init) diff --git a/app/src/main/java/fi/kroon/vadret/util/extension/LazyThreadSafetyMode.kt b/app/src/main/java/fi/kroon/vadret/util/extension/LazyThreadSafetyMode.kt new file mode 100644 index 00000000..acca4693 --- /dev/null +++ b/app/src/main/java/fi/kroon/vadret/util/extension/LazyThreadSafetyMode.kt @@ -0,0 +1,3 @@ +package fi.kroon.vadret.util.extension + +fun lazyAndroid(initializer: () -> T): Lazy = lazy(LazyThreadSafetyMode.NONE, initializer) \ No newline at end of file diff --git a/app/src/main/java/fi/kroon/vadret/util/extension/Service.kt b/app/src/main/java/fi/kroon/vadret/util/extension/Service.kt deleted file mode 100644 index 29a40795..00000000 --- a/app/src/main/java/fi/kroon/vadret/util/extension/Service.kt +++ /dev/null @@ -1,9 +0,0 @@ -package fi.kroon.vadret.util.extension - -import android.app.Service -import fi.kroon.vadret.BaseApplication -import fi.kroon.vadret.di.component.CoreApplicationComponent - -fun Service.appComponent(): CoreApplicationComponent = - BaseApplication - .appComponent(this) \ No newline at end of file