From 1e926449046714ec2324e1e15b1b648d70884e6d Mon Sep 17 00:00:00 2001 From: Aidan Follestad Date: Thu, 6 Dec 2018 17:56:51 -0800 Subject: [PATCH] Switch from Dagger to Koin, resolves #35 --- .idea/modules.xml | 2 +- app/build.gradle | 12 ++- .../com/afollestad/nocknock/NockNockApp.kt | 62 ++++-------- .../afollestad/nocknock/di/AppComponent.java | 77 --------------- .../afollestad/nocknock/di/MainModule.java | 73 -------------- .../nocknock/di/qualifiers/IoDispatcher.kt | 24 ----- .../nocknock/di/qualifiers/MainDispatcher.kt | 24 ----- .../di/viewmodels/ViewModelFactory.kt | 48 --------- .../di/viewmodels/ViewModelModule.java | 33 ------- .../afollestad/nocknock/koin/MainModule.kt | 63 ++++++++++++ .../nocknock/koin/ViewModelModule.kt | 60 +++++++++++ .../{di/viewmodels => ui}/ScopedViewModel.kt | 11 +-- .../nocknock/ui/addsite/AddSiteActivity.kt | 15 +-- .../nocknock/ui/addsite/AddSiteViewModel.kt | 11 +-- .../nocknock/ui/main/MainActivity.kt | 17 +--- .../nocknock/ui/main/MainViewModel.kt | 11 +-- .../nocknock/ui/viewsite/ViewSiteActivity.kt | 15 +-- .../nocknock/ui/viewsite/ViewSiteViewModel.kt | 21 ++-- .../afollestad/nocknock/LiveDataTestUtil.kt | 21 +++- .../StatusUpdateIntentReceiverTest.kt | 17 +++- ...esenterTest.kt => AddSiteViewModelTest.kt} | 2 +- .../nocknock/ui/main/MainViewModelTest.kt | 15 ++- ...senterTest.kt => ViewSiteViewModelTest.kt} | 4 +- {utilities => common}/.gitignore | 0 {utilities => common}/build.gradle | 4 +- .../src/main/AndroidManifest.xml | 0 .../nocknock/utilities/UtilitiesModule.kt | 99 +++++++++---------- .../nocknock/utilities/ext/AnimationExt.kt | 0 .../nocknock/utilities/ext/ContextExt.kt | 0 .../nocknock/utilities/ext/DateExt.kt | 0 .../nocknock/utilities/ext/TimeExt.kt | 0 .../nocknock/utilities/ext/UriExt.kt | 0 .../nocknock/utilities/ext/ViewExt.kt | 0 .../nocknock/utilities/js/JavaScript.kt | 0 .../utilities/providers/BitmapProvider.kt | 9 +- .../utilities/providers/BundleProvider.kt | 3 +- .../utilities/providers/IntentProvider.kt | 14 ++- .../utilities/providers/JobInfoProvider.kt | 9 +- .../providers/NotificationChannelProvider.kt | 3 +- .../providers/NotificationProvider.kt | 9 +- .../utilities/providers/SdkProvider.kt | 3 +- .../utilities/providers/StringProvider.kt | 9 +- .../utilities/ui/DebouncedOnClickListener.kt | 0 .../src/main/res/values/strings.xml | 0 data/build.gradle | 5 +- dependencies.gradle | 4 +- engine/build.gradle | 8 +- .../{EngineModule.java => EngineModule.kt} | 23 +++-- .../engine/validation/BootReceiver.kt | 23 ++--- .../engine/validation/ValidationJob.kt | 16 ++- .../engine/validation/ValidationManager.kt | 3 +- notifications/build.gradle | 6 +- .../notifications/NockNotificationManager.kt | 6 +- .../notifications/NotificationsModule.java | 30 ------ .../notifications/NotificationsModule.kt | 26 ++++- settings.gradle | 2 +- .../nocknock/utilities/ext/InjectorExt.kt | 24 ----- .../utilities/qualifiers/AppIconRes.kt | 24 ----- .../utilities/qualifiers/MainActivityClass.kt | 24 ----- viewcomponents/build.gradle | 5 +- .../viewcomponents/LoadingIndicatorFrame.kt | 16 +-- 61 files changed, 385 insertions(+), 660 deletions(-) delete mode 100644 app/src/main/java/com/afollestad/nocknock/di/AppComponent.java delete mode 100644 app/src/main/java/com/afollestad/nocknock/di/MainModule.java delete mode 100644 app/src/main/java/com/afollestad/nocknock/di/qualifiers/IoDispatcher.kt delete mode 100644 app/src/main/java/com/afollestad/nocknock/di/qualifiers/MainDispatcher.kt delete mode 100644 app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelFactory.kt delete mode 100644 app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelModule.java create mode 100644 app/src/main/java/com/afollestad/nocknock/koin/MainModule.kt create mode 100644 app/src/main/java/com/afollestad/nocknock/koin/ViewModelModule.kt rename app/src/main/java/com/afollestad/nocknock/{di/viewmodels => ui}/ScopedViewModel.kt (79%) rename app/src/test/java/com/afollestad/nocknock/ui/addsite/{AddSitePresenterTest.kt => AddSiteViewModelTest.kt} (99%) rename app/src/test/java/com/afollestad/nocknock/ui/viewsite/{ViewSitePresenterTest.kt => ViewSiteViewModelTest.kt} (88%) rename {utilities => common}/.gitignore (100%) rename {utilities => common}/build.gradle (90%) rename {utilities => common}/src/main/AndroidManifest.xml (100%) rename utilities/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.java => common/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.kt (50%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ext/AnimationExt.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ext/ContextExt.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ext/DateExt.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ext/TimeExt.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ext/UriExt.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ext/ViewExt.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/js/JavaScript.kt (100%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt (85%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt (93%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt (84%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt (90%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt (94%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt (89%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt (91%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt (84%) rename {utilities => common}/src/main/java/com/afollestad/nocknock/utilities/ui/DebouncedOnClickListener.kt (100%) rename {utilities => common}/src/main/res/values/strings.xml (100%) rename engine/src/main/java/com/afollestad/nocknock/engine/{EngineModule.java => EngineModule.kt} (73%) delete mode 100644 notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.java rename utilities/src/main/java/com/afollestad/nocknock/utilities/Injector.kt => notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.kt (53%) delete mode 100644 utilities/src/main/java/com/afollestad/nocknock/utilities/ext/InjectorExt.kt delete mode 100644 utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/AppIconRes.kt delete mode 100644 utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/MainActivityClass.kt diff --git a/.idea/modules.xml b/.idea/modules.xml index d5f1277..23f5d23 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,11 +3,11 @@ + - diff --git a/app/build.gradle b/app/build.gradle index 5c3703e..dbf9c87 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,7 +18,7 @@ android { } dependencies { - implementation project(':utilities') + implementation project(':common') implementation project(':engine') implementation project(':data') implementation project(':notifications') @@ -32,16 +32,22 @@ dependencies { implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin - implementation 'com.google.dagger:dagger:' + versions.dagger - kapt 'com.google.dagger:dagger-compiler:' + versions.dagger + implementation 'org.koin:koin-android:' + versions.koin + implementation 'org.koin:koin-androidx-scope:' + versions.koin + implementation 'org.koin:koin-androidx-viewmodel:' + versions.koin implementation 'com.afollestad.material-dialogs:core:' + versions.materialDialogs implementation 'com.jakewharton.timber:timber:' + versions.timber + testImplementation 'junit:junit:' + versions.junit testImplementation 'org.mockito:mockito-core:' + versions.mockito testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin testImplementation 'com.google.truth:truth:' + versions.truth + testImplementation 'androidx.arch.core:core-testing:' + versions.archTesting + + androidTestImplementation 'androidx.test:runner:' + versions.androidxTestRunner + androidTestImplementation 'androidx.test:rules:' + versions.androidxTestRunner } apply from: '../spotless.gradle' \ No newline at end of file diff --git a/app/src/main/java/com/afollestad/nocknock/NockNockApp.kt b/app/src/main/java/com/afollestad/nocknock/NockNockApp.kt index 777d8a8..6e08bd5 100644 --- a/app/src/main/java/com/afollestad/nocknock/NockNockApp.kt +++ b/app/src/main/java/com/afollestad/nocknock/NockNockApp.kt @@ -16,55 +16,42 @@ package com.afollestad.nocknock import android.app.Application -import com.afollestad.nocknock.di.AppComponent -import com.afollestad.nocknock.di.DaggerAppComponent -import com.afollestad.nocknock.engine.validation.BootReceiver -import com.afollestad.nocknock.engine.validation.ValidationJob +import com.afollestad.nocknock.engine.engineModule +import com.afollestad.nocknock.koin.mainModule +import com.afollestad.nocknock.koin.viewModelModule import com.afollestad.nocknock.notifications.NockNotificationManager -import com.afollestad.nocknock.ui.addsite.AddSiteActivity -import com.afollestad.nocknock.ui.main.MainActivity -import com.afollestad.nocknock.ui.viewsite.ViewSiteActivity -import com.afollestad.nocknock.utilities.Injector -import com.afollestad.nocknock.utilities.ext.systemService -import okhttp3.OkHttpClient +import com.afollestad.nocknock.notifications.notificationsModule +import com.afollestad.nocknock.utilities.utilitiesModule +import org.koin.android.ext.android.inject +import org.koin.android.ext.android.startKoin import timber.log.Timber import timber.log.Timber.DebugTree -import javax.inject.Inject import timber.log.Timber.d as log /** @author Aidan Follestad (@afollestad) */ -class NockNockApp : Application(), Injector { - - private lateinit var appComponent: AppComponent - @Inject lateinit var nockNotificationManager: NockNotificationManager +class NockNockApp : Application() { private var resumedActivities: Int = 0 override fun onCreate() { super.onCreate() - if (BuildConfig.DEBUG) { Timber.plant(DebugTree()) } - val okHttpClient = OkHttpClient.Builder() - .addNetworkInterceptor { chain -> - val request = chain.request() - .newBuilder() - .addHeader("User-Agent", "com.afollestad.nocknock") - .build() - chain.proceed(request) - } - .build() - - appComponent = DaggerAppComponent.builder() - .application(this) - .okHttpClient(okHttpClient) - .jobScheduler(systemService(JOB_SCHEDULER_SERVICE)) - .notificationManager(systemService(NOTIFICATION_SERVICE)) - .build() - appComponent.inject(this) + val modules = listOf( + mainModule, + engineModule, + utilitiesModule, + notificationsModule, + viewModelModule + ) + startKoin( + androidContext = this, + modules = modules + ) + val nockNotificationManager by inject() onActivityLifeChange { activity, resumed -> if (resumed) { resumedActivities++ @@ -77,13 +64,4 @@ class NockNockApp : Application(), Injector { nockNotificationManager.setIsAppOpen(resumedActivities > 0) } } - - override fun injectInto(target: Any) = when (target) { - is MainActivity -> appComponent.inject(target) - is ViewSiteActivity -> appComponent.inject(target) - is AddSiteActivity -> appComponent.inject(target) - is ValidationJob -> appComponent.inject(target) - is BootReceiver -> appComponent.inject(target) - else -> throw IllegalStateException("Can't inject into $target") - } } diff --git a/app/src/main/java/com/afollestad/nocknock/di/AppComponent.java b/app/src/main/java/com/afollestad/nocknock/di/AppComponent.java deleted file mode 100644 index f7a0cdb..0000000 --- a/app/src/main/java/com/afollestad/nocknock/di/AppComponent.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.di; - -import android.app.Application; -import android.app.NotificationManager; -import android.app.job.JobScheduler; -import com.afollestad.nocknock.NockNockApp; -import com.afollestad.nocknock.di.viewmodels.ViewModelModule; -import com.afollestad.nocknock.engine.EngineModule; -import com.afollestad.nocknock.engine.validation.BootReceiver; -import com.afollestad.nocknock.engine.validation.ValidationJob; -import com.afollestad.nocknock.notifications.NotificationsModule; -import com.afollestad.nocknock.ui.addsite.AddSiteActivity; -import com.afollestad.nocknock.ui.main.MainActivity; -import com.afollestad.nocknock.ui.viewsite.ViewSiteActivity; -import com.afollestad.nocknock.utilities.UtilitiesModule; -import dagger.BindsInstance; -import dagger.Component; -import javax.inject.Singleton; -import okhttp3.OkHttpClient; - -/** @author Aidan Follestad (@afollestad) */ -@Singleton -@Component( - modules = { - MainModule.class, - ViewModelModule.class, - EngineModule.class, - NotificationsModule.class, - UtilitiesModule.class - } -) -public interface AppComponent { - - void inject(NockNockApp app); - - void inject(MainActivity activity); - - void inject(ViewSiteActivity activity); - - void inject(AddSiteActivity activity); - - void inject(ValidationJob job); - - void inject(BootReceiver bootReceiver); - - @Component.Builder interface Builder { - - @BindsInstance - Builder application(Application application); - - @BindsInstance - Builder okHttpClient(OkHttpClient okHttpClient); - - @BindsInstance - Builder jobScheduler(JobScheduler jobScheduler); - - @BindsInstance - Builder notificationManager(NotificationManager notificationManager); - - AppComponent build(); - } -} diff --git a/app/src/main/java/com/afollestad/nocknock/di/MainModule.java b/app/src/main/java/com/afollestad/nocknock/di/MainModule.java deleted file mode 100644 index 03dcf7c..0000000 --- a/app/src/main/java/com/afollestad/nocknock/di/MainModule.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.di; - -import android.app.Application; -import com.afollestad.nocknock.R; -import com.afollestad.nocknock.data.AppDatabase; -import com.afollestad.nocknock.ui.main.MainActivity; -import com.afollestad.nocknock.utilities.qualifiers.AppIconRes; -import com.afollestad.nocknock.di.qualifiers.IoDispatcher; -import com.afollestad.nocknock.utilities.qualifiers.MainActivityClass; -import com.afollestad.nocknock.di.qualifiers.MainDispatcher; -import dagger.Module; -import dagger.Provides; -import javax.inject.Singleton; -import kotlinx.coroutines.CoroutineDispatcher; -import kotlinx.coroutines.Dispatchers; - -import static androidx.room.Room.databaseBuilder; - -/** @author Aidan Follestad (@afollestad) */ -@Module -abstract class MainModule { - @SuppressWarnings("FieldCanBeLocal") - private static String DATABASE_NAME = "NockNock.db"; - - @Provides - @Singleton - @AppIconRes - static int provideAppIconRes() { - return R.mipmap.ic_launcher; - } - - @Provides - @Singleton - @MainActivityClass - static Class provideMainActivityClass() { - return MainActivity.class; - } - - @Provides - @Singleton - static AppDatabase provideAppDatabase(Application app) { - return databaseBuilder(app, AppDatabase.class, DATABASE_NAME).build(); - } - - @Provides - @Singleton - @MainDispatcher - static CoroutineDispatcher provideMainDispatcher() { - return Dispatchers.getMain(); - } - - @Provides - @Singleton - @IoDispatcher - static CoroutineDispatcher provideIoDispatcher() { - return Dispatchers.getIO(); - } -} diff --git a/app/src/main/java/com/afollestad/nocknock/di/qualifiers/IoDispatcher.kt b/app/src/main/java/com/afollestad/nocknock/di/qualifiers/IoDispatcher.kt deleted file mode 100644 index 6ecc572..0000000 --- a/app/src/main/java/com/afollestad/nocknock/di/qualifiers/IoDispatcher.kt +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.di.qualifiers - -import javax.inject.Qualifier -import kotlin.annotation.AnnotationRetention.RUNTIME - -/** @author Aidan Follestad (@afollestad) */ -@Qualifier -@Retention(RUNTIME) -annotation class IoDispatcher diff --git a/app/src/main/java/com/afollestad/nocknock/di/qualifiers/MainDispatcher.kt b/app/src/main/java/com/afollestad/nocknock/di/qualifiers/MainDispatcher.kt deleted file mode 100644 index de83ab5..0000000 --- a/app/src/main/java/com/afollestad/nocknock/di/qualifiers/MainDispatcher.kt +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.di.qualifiers - -import javax.inject.Qualifier -import kotlin.annotation.AnnotationRetention.RUNTIME - -/** @author Aidan Follestad (@afollestad) */ -@Qualifier -@Retention(RUNTIME) -annotation class MainDispatcher diff --git a/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelFactory.kt b/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelFactory.kt deleted file mode 100644 index bd95ff9..0000000 --- a/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelFactory.kt +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.di.viewmodels - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import dagger.MapKey -import javax.inject.Inject -import javax.inject.Provider -import javax.inject.Singleton -import kotlin.annotation.AnnotationRetention.RUNTIME -import kotlin.annotation.AnnotationTarget.FUNCTION -import kotlin.annotation.AnnotationTarget.PROPERTY_GETTER -import kotlin.annotation.AnnotationTarget.PROPERTY_SETTER -import kotlin.reflect.KClass - -typealias ViewModelMap = MutableMap, Provider> - -@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER) -@Retention(RUNTIME) -@MapKey -annotation class ViewModelKey(val value: KClass) - -/** - * https://proandroiddev.com/viewmodel-with-dagger2-architecture-components-2e06f06c9455 - */ -@Singleton -class ViewModelFactory @Inject constructor(private val viewModels: ViewModelMap) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - @Suppress("UNCHECKED_CAST") - return viewModels[modelClass]?.get() as T - } -} diff --git a/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelModule.java b/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelModule.java deleted file mode 100644 index d659c78..0000000 --- a/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ViewModelModule.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.afollestad.nocknock.di.viewmodels; - -import androidx.lifecycle.ViewModel; -import androidx.lifecycle.ViewModelProvider; -import com.afollestad.nocknock.ui.addsite.AddSiteViewModel; -import com.afollestad.nocknock.ui.main.MainViewModel; -import com.afollestad.nocknock.ui.viewsite.ViewSiteViewModel; -import dagger.Binds; -import dagger.Module; -import dagger.multibindings.IntoMap; - -/** https://proandroiddev.com/viewmodel-with-dagger2-architecture-components-2e06f06c9455 */ -@Module -public abstract class ViewModelModule { - - @Binds - abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory); - - @Binds - @IntoMap - @ViewModelKey(MainViewModel.class) - abstract ViewModel mainViewModel(MainViewModel viewModel); - - @Binds - @IntoMap - @ViewModelKey(AddSiteViewModel.class) - abstract ViewModel addSiteViewModel(AddSiteViewModel viewModel); - - @Binds - @IntoMap - @ViewModelKey(ViewSiteViewModel.class) - abstract ViewModel viewSiteViewModel(ViewSiteViewModel viewModel); -} diff --git a/app/src/main/java/com/afollestad/nocknock/koin/MainModule.kt b/app/src/main/java/com/afollestad/nocknock/koin/MainModule.kt new file mode 100644 index 0000000..9667287 --- /dev/null +++ b/app/src/main/java/com/afollestad/nocknock/koin/MainModule.kt @@ -0,0 +1,63 @@ +/** + * Designed and developed by Aidan Follestad (@afollestad) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.afollestad.nocknock.koin + +import android.app.Application +import android.app.NotificationManager +import android.app.job.JobScheduler +import android.content.Context.JOB_SCHEDULER_SERVICE +import android.content.Context.NOTIFICATION_SERVICE +import androidx.room.Room.databaseBuilder +import com.afollestad.nocknock.R +import com.afollestad.nocknock.data.AppDatabase +import com.afollestad.nocknock.notifications.Qualifiers.APP_ICON_RES +import com.afollestad.nocknock.ui.main.MainActivity +import com.afollestad.nocknock.utilities.Qualifiers.MAIN_ACTIVITY_CLASS +import com.afollestad.nocknock.utilities.ext.systemService +import okhttp3.OkHttpClient +import org.koin.dsl.module.module + +const val MAIN_MODULE = "main" + +/** @author Aidan Follestad (@afollestad) */ +val mainModule = module(MAIN_MODULE) { + + single(name = APP_ICON_RES) { R.mipmap.ic_launcher } + + single(name = MAIN_ACTIVITY_CLASS) { MainActivity::class.java } + + single { databaseBuilder(get(), AppDatabase::class.java, "NockNock.db").build() } + + single { + OkHttpClient.Builder() + .addNetworkInterceptor { chain -> + val request = chain.request() + .newBuilder() + .addHeader("User-Agent", "com.afollestad.nocknock") + .build() + chain.proceed(request) + } + .build() + } + + single { + get().systemService(JOB_SCHEDULER_SERVICE) + } + + single { + get().systemService(NOTIFICATION_SERVICE) + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/koin/ViewModelModule.kt b/app/src/main/java/com/afollestad/nocknock/koin/ViewModelModule.kt new file mode 100644 index 0000000..55c1f57 --- /dev/null +++ b/app/src/main/java/com/afollestad/nocknock/koin/ViewModelModule.kt @@ -0,0 +1,60 @@ +/** + * Designed and developed by Aidan Follestad (@afollestad) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.afollestad.nocknock.koin + +import com.afollestad.nocknock.ui.addsite.AddSiteViewModel +import com.afollestad.nocknock.ui.main.MainViewModel +import com.afollestad.nocknock.ui.viewsite.ViewSiteViewModel +import com.afollestad.nocknock.utilities.Qualifiers.IO_DISPATCHER +import com.afollestad.nocknock.utilities.Qualifiers.MAIN_DISPATCHER +import org.koin.androidx.viewmodel.ext.koin.viewModel +import org.koin.dsl.module.module + +const val VIEW_MODEL_MODULE = "view_models" + +/** @author Aidan Follestad (@afollestad) */ +val viewModelModule = module(VIEW_MODEL_MODULE) { + + viewModel { + MainViewModel( + get(), + get(), + get(), + get(name = MAIN_DISPATCHER), + get(name = IO_DISPATCHER) + ) + } + + viewModel { + AddSiteViewModel( + get(), + get(), + get(name = MAIN_DISPATCHER), + get(name = IO_DISPATCHER) + ) + } + + viewModel { + ViewSiteViewModel( + get(), + get(), + get(), + get(), + get(name = MAIN_DISPATCHER), + get(name = IO_DISPATCHER) + ) + } +} diff --git a/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ScopedViewModel.kt b/app/src/main/java/com/afollestad/nocknock/ui/ScopedViewModel.kt similarity index 79% rename from app/src/main/java/com/afollestad/nocknock/di/viewmodels/ScopedViewModel.kt rename to app/src/main/java/com/afollestad/nocknock/ui/ScopedViewModel.kt index 19b8fb6..750173a 100644 --- a/app/src/main/java/com/afollestad/nocknock/di/viewmodels/ScopedViewModel.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/ScopedViewModel.kt @@ -13,21 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.afollestad.nocknock.di.viewmodels +package com.afollestad.nocknock.ui import androidx.lifecycle.ViewModel -import com.afollestad.nocknock.di.qualifiers.MainDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import org.jetbrains.annotations.TestOnly -import javax.inject.Inject -abstract class ScopedViewModel : ViewModel() { - - @Inject - @MainDispatcher - lateinit var mainDispatcher: CoroutineDispatcher +/** @author Aidan Follestad (@afollestad) */ +abstract class ScopedViewModel(mainDispatcher: CoroutineDispatcher) : ViewModel() { private val job = Job() protected val scope = CoroutineScope(job + mainDispatcher) diff --git a/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteActivity.kt b/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteActivity.kt index 93cfc32..d0b9376 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteActivity.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteActivity.kt @@ -19,11 +19,8 @@ import android.annotation.SuppressLint import android.os.Bundle import android.widget.ArrayAdapter import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.ViewModelProviders import com.afollestad.nocknock.R import com.afollestad.nocknock.data.model.ValidationMode -import com.afollestad.nocknock.utilities.ext.injector import com.afollestad.nocknock.viewcomponents.ext.attachLiveData import com.afollestad.nocknock.viewcomponents.ext.conceal import com.afollestad.nocknock.viewcomponents.ext.onLayout @@ -43,7 +40,7 @@ import kotlinx.android.synthetic.main.activity_addsite.scriptInputLayout import kotlinx.android.synthetic.main.activity_addsite.textUrlWarning import kotlinx.android.synthetic.main.activity_addsite.toolbar import kotlinx.android.synthetic.main.activity_addsite.validationModeDescription -import javax.inject.Inject +import org.koin.androidx.viewmodel.ext.android.viewModel import kotlin.math.max import kotlin.properties.Delegates.notNull @@ -58,19 +55,13 @@ class AddSiteActivity : AppCompatActivity() { var revealCy by notNull() var revealRadius by notNull() - @Inject lateinit var viewModelFactory: ViewModelProvider.Factory - internal var isClosing = false - private val viewModel by lazy { - return@lazy ViewModelProviders.of(this, viewModelFactory) - .get(AddSiteViewModel::class.java) - } + + private val viewModel by viewModel() @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - injector().injectInto(this) setContentView(R.layout.activity_addsite) setupUi(savedInstanceState) diff --git a/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt b/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt index e959e8c..ebcc4ba 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModel.kt @@ -28,23 +28,22 @@ import com.afollestad.nocknock.data.model.ValidationMode.JAVASCRIPT import com.afollestad.nocknock.data.model.ValidationMode.STATUS_CODE import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH import com.afollestad.nocknock.data.putSite -import com.afollestad.nocknock.di.viewmodels.ScopedViewModel import com.afollestad.nocknock.engine.validation.ValidationManager -import com.afollestad.nocknock.di.qualifiers.IoDispatcher +import com.afollestad.nocknock.ui.ScopedViewModel import com.afollestad.nocknock.viewcomponents.ext.isNullOrLessThan import com.afollestad.nocknock.viewcomponents.ext.map import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.HttpUrl -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ -class AddSiteViewModel @Inject constructor( +class AddSiteViewModel( private val database: AppDatabase, private val validationManager: ValidationManager, - @field:IoDispatcher private val ioDispatcher: CoroutineDispatcher -) : ScopedViewModel(), LifecycleObserver { + mainDispatcher: CoroutineDispatcher, + private val ioDispatcher: CoroutineDispatcher +) : ScopedViewModel(mainDispatcher), LifecycleObserver { // Public properties val name = MutableLiveData() diff --git a/app/src/main/java/com/afollestad/nocknock/ui/main/MainActivity.kt b/app/src/main/java/com/afollestad/nocknock/ui/main/MainActivity.kt index 9be4e52..2fc867a 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/main/MainActivity.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/main/MainActivity.kt @@ -19,8 +19,6 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL import androidx.recyclerview.widget.LinearLayoutManager @@ -28,31 +26,27 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.list.listItems import com.afollestad.nocknock.R import com.afollestad.nocknock.adapter.ServerAdapter +import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver import com.afollestad.nocknock.data.model.Site import com.afollestad.nocknock.dialogs.AboutDialog import com.afollestad.nocknock.notifications.NockNotificationManager -import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver -import com.afollestad.nocknock.utilities.ext.injector import com.afollestad.nocknock.viewcomponents.ext.showOrHide import kotlinx.android.synthetic.main.activity_main.fab import kotlinx.android.synthetic.main.activity_main.list import kotlinx.android.synthetic.main.activity_main.loadingProgress import kotlinx.android.synthetic.main.activity_main.toolbar import kotlinx.android.synthetic.main.include_empty_view.emptyText -import javax.inject.Inject +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.viewModel /** @author Aidan Follestad (@afollestad) */ class MainActivity : AppCompatActivity() { - @Inject lateinit var notificationManager: NockNotificationManager - @Inject lateinit var viewModelFactory: ViewModelProvider.Factory + private val notificationManager by inject() + internal val viewModel by viewModel() private lateinit var adapter: ServerAdapter - internal val viewModel by lazy { - return@lazy ViewModelProviders.of(this, viewModelFactory) - .get(MainViewModel::class.java) - } private val statusUpdateReceiver = StatusUpdateIntentReceiver(application) { viewModel.postSiteUpdate(it) @@ -60,7 +54,6 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - injector().injectInto(this) setContentView(R.layout.activity_main) setupUi() diff --git a/app/src/main/java/com/afollestad/nocknock/ui/main/MainViewModel.kt b/app/src/main/java/com/afollestad/nocknock/ui/main/MainViewModel.kt index 1b287b6..cef3827 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/main/MainViewModel.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/main/MainViewModel.kt @@ -25,22 +25,21 @@ import com.afollestad.nocknock.data.AppDatabase import com.afollestad.nocknock.data.allSites import com.afollestad.nocknock.data.deleteSite import com.afollestad.nocknock.data.model.Site -import com.afollestad.nocknock.di.viewmodels.ScopedViewModel import com.afollestad.nocknock.engine.validation.ValidationManager import com.afollestad.nocknock.notifications.NockNotificationManager -import com.afollestad.nocknock.di.qualifiers.IoDispatcher +import com.afollestad.nocknock.ui.ScopedViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ -class MainViewModel @Inject constructor( +class MainViewModel( private val database: AppDatabase, private val notificationManager: NockNotificationManager, private val validationManager: ValidationManager, - @field:IoDispatcher private val ioDispatcher: CoroutineDispatcher -) : ScopedViewModel(), LifecycleObserver { + mainDispatcher: CoroutineDispatcher, + private val ioDispatcher: CoroutineDispatcher +) : ScopedViewModel(mainDispatcher), LifecycleObserver { private val sites = MutableLiveData>() private val isLoading = MutableLiveData() diff --git a/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteActivity.kt b/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteActivity.kt index 6904345..aace599 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteActivity.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteActivity.kt @@ -21,13 +21,10 @@ import android.os.Bundle import android.widget.ArrayAdapter import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.ViewModelProviders import com.afollestad.nocknock.R +import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver import com.afollestad.nocknock.data.model.Site import com.afollestad.nocknock.data.model.ValidationMode -import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver -import com.afollestad.nocknock.utilities.ext.injector import com.afollestad.nocknock.viewcomponents.ext.attachLiveData import com.afollestad.nocknock.viewcomponents.ext.dimenFloat import com.afollestad.nocknock.viewcomponents.ext.onScroll @@ -51,17 +48,13 @@ import kotlinx.android.synthetic.main.activity_viewsite.textNextCheck import kotlinx.android.synthetic.main.activity_viewsite.textUrlWarning import kotlinx.android.synthetic.main.activity_viewsite.toolbar import kotlinx.android.synthetic.main.activity_viewsite.validationModeDescription -import javax.inject.Inject +import org.koin.androidx.viewmodel.ext.android.viewModel /** @author Aidan Follestad (@afollestad) */ class ViewSiteActivity : AppCompatActivity() { - @Inject lateinit var viewModelFactory: ViewModelProvider.Factory + internal val viewModel by viewModel() - internal val viewModel by lazy { - return@lazy ViewModelProviders.of(this, viewModelFactory) - .get(ViewSiteViewModel::class.java) - } private val statusUpdateReceiver = StatusUpdateIntentReceiver(application) { viewModel.setModel(it) @@ -70,8 +63,6 @@ class ViewSiteActivity : AppCompatActivity() { @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - injector().injectInto(this) setContentView(R.layout.activity_viewsite) setupUi() diff --git a/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModel.kt b/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModel.kt index 4d7b914..76258c5 100644 --- a/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModel.kt +++ b/app/src/main/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModel.kt @@ -15,7 +15,6 @@ */ package com.afollestad.nocknock.ui.viewsite -import android.app.Application import androidx.annotation.CheckResult import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LiveData @@ -33,11 +32,11 @@ import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH import com.afollestad.nocknock.data.model.ValidationResult import com.afollestad.nocknock.data.model.textRes import com.afollestad.nocknock.data.updateSite -import com.afollestad.nocknock.di.viewmodels.ScopedViewModel import com.afollestad.nocknock.engine.validation.ValidationManager import com.afollestad.nocknock.notifications.NockNotificationManager +import com.afollestad.nocknock.ui.ScopedViewModel import com.afollestad.nocknock.utilities.ext.formatDate -import com.afollestad.nocknock.di.qualifiers.IoDispatcher +import com.afollestad.nocknock.utilities.providers.StringProvider import com.afollestad.nocknock.viewcomponents.ext.isNullOrLessThan import com.afollestad.nocknock.viewcomponents.ext.map import com.afollestad.nocknock.viewcomponents.ext.zip @@ -46,16 +45,16 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.HttpUrl import java.lang.System.currentTimeMillis -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ -class ViewSiteViewModel @Inject constructor( - private val app: Application, +class ViewSiteViewModel( + private val stringProvider: StringProvider, private val database: AppDatabase, private val notificationManager: NockNotificationManager, private val validationManager: ValidationManager, - @field:IoDispatcher private val ioDispatcher: CoroutineDispatcher -) : ScopedViewModel(), LifecycleObserver { + mainDispatcher: CoroutineDispatcher, + private val ioDispatcher: CoroutineDispatcher +) : ScopedViewModel(mainDispatcher), LifecycleObserver { lateinit var site: Site @@ -134,13 +133,13 @@ class ViewSiteViewModel @Inject constructor( @CheckResult fun onLastCheckResultText(): LiveData = lastResult.map { if (it == null) { - app.getString(R.string.none) + stringProvider.get(R.string.none) } else { val statusText = it.status.textRes() if (statusText == 0) { it.reason } else { - app.getString(statusText) + stringProvider.get(statusText) } } } @@ -151,7 +150,7 @@ class ViewSiteViewModel @Inject constructor( val disabled = it.first val lastResult = it.second if (disabled) { - app.getString(R.string.auto_checks_disabled) + stringProvider.get(R.string.auto_checks_disabled) } else { val lastCheck = lastResult?.timestampMs ?: currentTimeMillis() (lastCheck + getCheckIntervalMs()).formatDate() diff --git a/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt b/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt index b03df8b..e175d5d 100644 --- a/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt +++ b/app/src/test/java/com/afollestad/nocknock/LiveDataTestUtil.kt @@ -1,8 +1,24 @@ +/** + * Designed and developed by Aidan Follestad (@afollestad) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.afollestad.nocknock import androidx.annotation.CheckResult import androidx.lifecycle.LiveData import androidx.lifecycle.Observer +import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage /** @author Aidan Follestad (@afollestad) */ @@ -22,12 +38,11 @@ class TestLiveData(data: LiveData) { fun assertValues(vararg assertValues: T) { val assertList = assertValues.toList() - assertWithMessage("Expected: $assertList, but got: $receivedValues").that(receivedValues) - .isEqualTo(assertList) + assertThat(receivedValues).isEqualTo(assertList) receivedValues.clear() } @CheckResult fun values(): List = receivedValues } -@CheckResult fun LiveData.test() = TestLiveData(this) \ No newline at end of file +@CheckResult fun LiveData.test() = TestLiveData(this) diff --git a/app/src/test/java/com/afollestad/nocknock/broadcasts/StatusUpdateIntentReceiverTest.kt b/app/src/test/java/com/afollestad/nocknock/broadcasts/StatusUpdateIntentReceiverTest.kt index 54d62c4..0d9b88b 100644 --- a/app/src/test/java/com/afollestad/nocknock/broadcasts/StatusUpdateIntentReceiverTest.kt +++ b/app/src/test/java/com/afollestad/nocknock/broadcasts/StatusUpdateIntentReceiverTest.kt @@ -1,3 +1,18 @@ +/** + * Designed and developed by Aidan Follestad (@afollestad) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.afollestad.nocknock.broadcasts import android.app.Application @@ -52,4 +67,4 @@ class StatusUpdateIntentReceiverTest { receiver.onPause() verify(app).unregisterReceiver(receiver.intentReceiver) } -} \ No newline at end of file +} diff --git a/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSitePresenterTest.kt b/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt similarity index 99% rename from app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSitePresenterTest.kt rename to app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt index 0320fd3..d8cbe81 100644 --- a/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSitePresenterTest.kt +++ b/app/src/test/java/com/afollestad/nocknock/ui/addsite/AddSiteViewModelTest.kt @@ -42,7 +42,7 @@ package com.afollestad.nocknock.ui.addsite //import org.junit.Before //import org.junit.Test // -//class AddSitePresenterTest { +//class AddSiteViewModelTest { // // private val database = mockDatabase() // private val checkStatusManager = mock() diff --git a/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt b/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt index 6414bd5..70e732f 100644 --- a/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt +++ b/app/src/test/java/com/afollestad/nocknock/ui/main/MainViewModelTest.kt @@ -15,6 +15,7 @@ */ package com.afollestad.nocknock.ui.main +import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.afollestad.nocknock.ALL_MOCK_MODELS import com.afollestad.nocknock.MOCK_MODEL_1 import com.afollestad.nocknock.MOCK_MODEL_2 @@ -28,22 +29,25 @@ import com.nhaarman.mockitokotlin2.verify import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import org.junit.After +import org.junit.Rule import org.junit.Test +/** @author Aidan Follestad (@afollestad) */ class MainViewModelTest { private val database = mockDatabase() private val notificationManager = mock() private val validationManager = mock() + @Rule @JvmField val rule = InstantTaskExecutorRule() + private val viewModel = MainViewModel( database, notificationManager, validationManager, - Dispatchers.Default - ).apply { - this.mainDispatcher = Dispatchers.Default - } + Dispatchers.Unconfined, + Dispatchers.Unconfined + ) @After fun tearDown() = viewModel.destroy() @@ -92,7 +96,6 @@ class MainViewModelTest { viewModel.postSiteUpdate(updatedModel2) sites.assertValues(updatedSites) - } @Test fun refreshSite() { @@ -116,6 +119,7 @@ class MainViewModelTest { listOf(), ALL_MOCK_MODELS ) + isLoading.assertValues(true, false) val modifiedModel = MOCK_MODEL_1.copy(id = 11111) viewModel.removeSite(modifiedModel) @@ -140,6 +144,7 @@ class MainViewModelTest { listOf(), ALL_MOCK_MODELS ) + isLoading.assertValues(true, false) val modelsWithout1 = ALL_MOCK_MODELS.toMutableList() .apply { diff --git a/app/src/test/java/com/afollestad/nocknock/ui/viewsite/ViewSitePresenterTest.kt b/app/src/test/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModelTest.kt similarity index 88% rename from app/src/test/java/com/afollestad/nocknock/ui/viewsite/ViewSitePresenterTest.kt rename to app/src/test/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModelTest.kt index 9b4a33b..e06b747 100644 --- a/app/src/test/java/com/afollestad/nocknock/ui/viewsite/ViewSitePresenterTest.kt +++ b/app/src/test/java/com/afollestad/nocknock/ui/viewsite/ViewSiteViewModelTest.kt @@ -15,6 +15,6 @@ */ package com.afollestad.nocknock.ui.viewsite -class ViewSitePresenterTest { +class ViewSiteViewModelTest -} +// TODO this will be mostly identical to the add site test diff --git a/utilities/.gitignore b/common/.gitignore similarity index 100% rename from utilities/.gitignore rename to common/.gitignore diff --git a/utilities/build.gradle b/common/build.gradle similarity index 90% rename from utilities/build.gradle rename to common/build.gradle index 433cdf4..16d9280 100644 --- a/utilities/build.gradle +++ b/common/build.gradle @@ -26,9 +26,7 @@ dependencies { api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines - implementation 'com.google.dagger:dagger:' + versions.dagger - kapt 'com.google.dagger:dagger-compiler:' + versions.dagger - + implementation 'org.koin:koin-android:' + versions.koin implementation 'org.mozilla:rhino:' + versions.rhino testImplementation 'junit:junit:' + versions.junit diff --git a/utilities/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml similarity index 100% rename from utilities/src/main/AndroidManifest.xml rename to common/src/main/AndroidManifest.xml diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.java b/common/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.kt similarity index 50% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.java rename to common/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.kt index 5861004..e48adb3 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.java +++ b/common/src/main/java/com/afollestad/nocknock/utilities/UtilitiesModule.kt @@ -1,11 +1,11 @@ -/* +/** * Designed and developed by Aidan Follestad (@afollestad) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,63 +13,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.afollestad.nocknock.utilities; +package com.afollestad.nocknock.utilities -import com.afollestad.nocknock.utilities.providers.BitmapProvider; -import com.afollestad.nocknock.utilities.providers.BundleProvider; -import com.afollestad.nocknock.utilities.providers.IntentProvider; -import com.afollestad.nocknock.utilities.providers.JobInfoProvider; -import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider; -import com.afollestad.nocknock.utilities.providers.NotificationProvider; -import com.afollestad.nocknock.utilities.providers.RealBitmapProvider; -import com.afollestad.nocknock.utilities.providers.RealBundleProvider; -import com.afollestad.nocknock.utilities.providers.RealIntentProvider; -import com.afollestad.nocknock.utilities.providers.RealJobInfoProvider; -import com.afollestad.nocknock.utilities.providers.RealNotificationChannelProvider; -import com.afollestad.nocknock.utilities.providers.RealNotificationProvider; -import com.afollestad.nocknock.utilities.providers.RealSdkProvider; -import com.afollestad.nocknock.utilities.providers.RealStringProvider; -import com.afollestad.nocknock.utilities.providers.SdkProvider; -import com.afollestad.nocknock.utilities.providers.StringProvider; -import dagger.Binds; -import dagger.Module; -import javax.inject.Singleton; +import com.afollestad.nocknock.utilities.Qualifiers.IO_DISPATCHER +import com.afollestad.nocknock.utilities.Qualifiers.MAIN_ACTIVITY_CLASS +import com.afollestad.nocknock.utilities.Qualifiers.MAIN_DISPATCHER +import com.afollestad.nocknock.utilities.providers.BitmapProvider +import com.afollestad.nocknock.utilities.providers.BundleProvider +import com.afollestad.nocknock.utilities.providers.IntentProvider +import com.afollestad.nocknock.utilities.providers.JobInfoProvider +import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider +import com.afollestad.nocknock.utilities.providers.NotificationProvider +import com.afollestad.nocknock.utilities.providers.RealBitmapProvider +import com.afollestad.nocknock.utilities.providers.RealBundleProvider +import com.afollestad.nocknock.utilities.providers.RealIntentProvider +import com.afollestad.nocknock.utilities.providers.RealJobInfoProvider +import com.afollestad.nocknock.utilities.providers.RealNotificationChannelProvider +import com.afollestad.nocknock.utilities.providers.RealNotificationProvider +import com.afollestad.nocknock.utilities.providers.RealSdkProvider +import com.afollestad.nocknock.utilities.providers.RealStringProvider +import com.afollestad.nocknock.utilities.providers.SdkProvider +import com.afollestad.nocknock.utilities.providers.StringProvider +import kotlinx.coroutines.Dispatchers +import org.koin.dsl.module.module + +const val UTILITIES_MODULE = "utilities" + +object Qualifiers { + const val MAIN_ACTIVITY_CLASS = "main.main_activity_class" + const val MAIN_DISPATCHER = "main.main_dispatcher" + const val IO_DISPATCHER = "main.io_dispatcher" +} /** @author Aidan Follestad (@afollestad) */ -@Module -public abstract class UtilitiesModule { +val utilitiesModule = module(UTILITIES_MODULE) { - @Binds - @Singleton - abstract SdkProvider provideSdkProvider(RealSdkProvider sdkProvider); + factory(name = MAIN_DISPATCHER) { Dispatchers.Main } - @Binds - @Singleton - abstract BitmapProvider provideBitmapProvider(RealBitmapProvider bitmapProvider); + factory(name = IO_DISPATCHER) { Dispatchers.IO } - @Binds - @Singleton - abstract StringProvider provideStringProvider(RealStringProvider stringProvider); + factory { RealSdkProvider() } bind SdkProvider::class - @Binds - @Singleton - abstract IntentProvider provideIntentProvider(RealIntentProvider intentProvider); + factory { RealBitmapProvider(get()) } bind BitmapProvider::class - @Binds - @Singleton - abstract NotificationChannelProvider provideChannelProvider( - RealNotificationChannelProvider channelProvider); + factory { RealStringProvider(get()) } bind StringProvider::class - @Binds - @Singleton - abstract NotificationProvider provideNotificationProvider( - RealNotificationProvider notificationProvider); + factory { + RealIntentProvider(get(), get(name = MAIN_ACTIVITY_CLASS)) + } bind IntentProvider::class - @Binds - @Singleton - abstract BundleProvider provideBundleProvider(RealBundleProvider bundleProvider); + factory { + RealNotificationChannelProvider(get()) + } bind NotificationChannelProvider::class - @Binds - @Singleton - abstract JobInfoProvider provideJobInfoProvider(RealJobInfoProvider jobInfoProvider); + factory { RealNotificationProvider(get()) } bind NotificationProvider::class + + factory { RealBundleProvider() } bind BundleProvider::class + + factory { RealJobInfoProvider(get()) } bind JobInfoProvider::class } diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/AnimationExt.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ext/AnimationExt.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ext/AnimationExt.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ext/AnimationExt.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/ContextExt.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ext/ContextExt.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ext/ContextExt.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ext/ContextExt.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/DateExt.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ext/DateExt.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ext/DateExt.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ext/DateExt.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/TimeExt.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ext/TimeExt.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ext/TimeExt.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ext/TimeExt.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/UriExt.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ext/UriExt.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ext/UriExt.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ext/UriExt.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/ViewExt.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ext/ViewExt.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ext/ViewExt.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ext/ViewExt.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/js/JavaScript.kt b/common/src/main/java/com/afollestad/nocknock/utilities/js/JavaScript.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/js/JavaScript.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/js/JavaScript.kt diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt similarity index 85% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt index 0bbe9c3..7d87780 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/BitmapProvider.kt @@ -15,11 +15,10 @@ */ package com.afollestad.nocknock.utilities.providers -import android.app.Application +import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory.decodeResource import androidx.annotation.DrawableRes -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ interface BitmapProvider { @@ -28,11 +27,11 @@ interface BitmapProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealBitmapProvider @Inject constructor( - private val app: Application +class RealBitmapProvider( + private val context: Context ) : BitmapProvider { override fun get(res: Int): Bitmap { - return decodeResource(app.resources, res) + return decodeResource(context.resources, res) } } diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt similarity index 93% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt index 3d60e81..27894fe 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/BundleProvider.kt @@ -16,7 +16,6 @@ package com.afollestad.nocknock.utilities.providers import android.os.PersistableBundle -import javax.inject.Inject interface IBundle { fun putLong( @@ -34,7 +33,7 @@ interface BundleProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealBundleProvider @Inject constructor() : BundleProvider { +class RealBundleProvider : BundleProvider { override fun createPersistable(bundler: IBundler): PersistableBundle { val realBundle = PersistableBundle() diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt similarity index 84% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt index 56f65a0..3592bbe 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/IntentProvider.kt @@ -15,13 +15,11 @@ */ package com.afollestad.nocknock.utilities.providers -import android.app.Application import android.app.PendingIntent import android.app.PendingIntent.FLAG_CANCEL_CURRENT +import android.content.Context import android.content.Intent -import com.afollestad.nocknock.utilities.qualifiers.MainActivityClass import java.io.Serializable -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ interface CanNotifyModel : Serializable { @@ -42,9 +40,9 @@ interface IntentProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealIntentProvider @Inject constructor( - private val app: Application, - @MainActivityClass private val mainActivity: Class<*> +class RealIntentProvider( + private val context: Context, + private val mainActivityClass: Class<*> ) : IntentProvider { companion object { @@ -55,7 +53,7 @@ class RealIntentProvider @Inject constructor( override fun getPendingIntentForViewSite(model: CanNotifyModel): PendingIntent { val openIntent = getIntentForViewSite(model) return PendingIntent.getActivity( - app, + context, BASE_NOTIFICATION_REQUEST_CODE + model.notiId(), openIntent, FLAG_CANCEL_CURRENT @@ -63,7 +61,7 @@ class RealIntentProvider @Inject constructor( } private fun getIntentForViewSite(model: CanNotifyModel) = - Intent(app, mainActivity).apply { + Intent(context, mainActivityClass).apply { putExtra(KEY_VIEW_NOTIFICATION_MODEL, model) } } diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt similarity index 90% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt index 9852c50..0b59425 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/JobInfoProvider.kt @@ -15,13 +15,12 @@ */ package com.afollestad.nocknock.utilities.providers -import android.app.Application import android.app.job.JobInfo import android.app.job.JobInfo.NETWORK_TYPE_ANY import android.app.job.JobInfo.NETWORK_TYPE_UNMETERED import android.content.ComponentName +import android.content.Context import android.os.PersistableBundle -import javax.inject.Inject interface JobInfoProvider { @@ -34,8 +33,8 @@ interface JobInfoProvider { ): JobInfo } -class RealJobInfoProvider @Inject constructor( - private val app: Application +class RealJobInfoProvider( + private val context: Context ) : JobInfoProvider { // Note: we don't use the periodic feature of JobScheduler because it requires a @@ -48,7 +47,7 @@ class RealJobInfoProvider @Inject constructor( extras: PersistableBundle, target: Class<*> ): JobInfo { - val component = ComponentName(app, target) + val component = ComponentName(context, target) val networkType = if (onlyUnmeteredNetwork) { NETWORK_TYPE_UNMETERED } else { diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt similarity index 94% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt index 0215605..e31ef04 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationChannelProvider.kt @@ -18,7 +18,6 @@ package com.afollestad.nocknock.utilities.providers import android.annotation.TargetApi import android.app.NotificationChannel import android.os.Build.VERSION_CODES -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ interface NotificationChannelProvider { @@ -33,7 +32,7 @@ interface NotificationChannelProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealNotificationChannelProvider @Inject constructor( +class RealNotificationChannelProvider( private val sdkProvider: SdkProvider ) : NotificationChannelProvider { diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt similarity index 89% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt index 6c3547f..e0f45f1 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/NotificationProvider.kt @@ -15,13 +15,12 @@ */ package com.afollestad.nocknock.utilities.providers -import android.app.Application import android.app.Notification import android.app.PendingIntent +import android.content.Context import android.graphics.Bitmap import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ interface NotificationProvider { @@ -37,8 +36,8 @@ interface NotificationProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealNotificationProvider @Inject constructor( - private val app: Application +class RealNotificationProvider( + private val context: Context ) : NotificationProvider { override fun create( @@ -49,7 +48,7 @@ class RealNotificationProvider @Inject constructor( smallIcon: Int, largeIcon: Bitmap ): Notification { - return NotificationCompat.Builder(app, channelId) + return NotificationCompat.Builder(context, channelId) .setContentTitle(title) .setContentText(content) .setContentIntent(intent) diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt similarity index 91% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt index 8701f41..a8ec0a9 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/SdkProvider.kt @@ -17,7 +17,6 @@ package com.afollestad.nocknock.utilities.providers import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION_CODES.O -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ interface SdkProvider { @@ -26,7 +25,7 @@ interface SdkProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealSdkProvider @Inject constructor() : SdkProvider { +class RealSdkProvider : SdkProvider { override fun hasOreo() = SDK_INT >= O } diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt b/common/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt similarity index 84% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt index 1f263b5..1d24030 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt +++ b/common/src/main/java/com/afollestad/nocknock/utilities/providers/StringProvider.kt @@ -15,9 +15,8 @@ */ package com.afollestad.nocknock.utilities.providers -import android.app.Application +import android.content.Context import androidx.annotation.StringRes -import javax.inject.Inject /** @author Aidan Follestad (@afollestad) */ interface StringProvider { @@ -26,11 +25,11 @@ interface StringProvider { } /** @author Aidan Follestad (@afollestad) */ -class RealStringProvider @Inject constructor( - private val app: Application +class RealStringProvider( + private val context: Context ) : StringProvider { override fun get(res: Int): String { - return app.resources.getString(res) + return context.resources.getString(res) } } diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ui/DebouncedOnClickListener.kt b/common/src/main/java/com/afollestad/nocknock/utilities/ui/DebouncedOnClickListener.kt similarity index 100% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/ui/DebouncedOnClickListener.kt rename to common/src/main/java/com/afollestad/nocknock/utilities/ui/DebouncedOnClickListener.kt diff --git a/utilities/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml similarity index 100% rename from utilities/src/main/res/values/strings.xml rename to common/src/main/res/values/strings.xml diff --git a/data/build.gradle b/data/build.gradle index 6a79c06..5512756 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -17,13 +17,10 @@ android { } dependencies { - implementation project(':utilities') + implementation project(':common') implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin - implementation 'com.google.dagger:dagger:' + versions.dagger - annotationProcessor 'com.google.dagger:dagger-compiler:' + versions.dagger - api 'androidx.room:room-runtime:' + versions.room kapt 'androidx.room:room-compiler:' + versions.room diff --git a/dependencies.gradle b/dependencies.gradle index f1d2a5c..e7427e5 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -12,9 +12,9 @@ ext.versions = [ okHttp : '3.12.0', rhino : '1.7.10', - dagger : '2.19', kotlin : '1.3.10', coroutines : '1.0.1', + koin : '1.0.2', androidx : '1.0.0', room : '2.0.0', @@ -30,6 +30,8 @@ ext.versions = [ mockito : '2.23.0', mockitoKotlin : '2.0.0-RC1', truth : '0.42', + androidxTestRunner: '1.1.0', androidxTest : '1.0.0', + archTesting : '2.0.0' ] diff --git a/engine/build.gradle b/engine/build.gradle index c26b99b..1808f4c 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -14,7 +14,7 @@ android { } dependencies { - implementation project(':utilities') + implementation project(':common') implementation project(':data') implementation project(':notifications') @@ -22,12 +22,12 @@ dependencies { api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines + implementation 'org.koin:koin-android:' + versions.koin + api 'com.squareup.okhttp3:okhttp:' + versions.okHttp - implementation 'com.google.dagger:dagger:' + versions.dagger - kapt 'com.google.dagger:dagger-compiler:' + versions.dagger - implementation 'com.jakewharton.timber:timber:' + versions.timber + testImplementation 'junit:junit:' + versions.junit testImplementation 'org.mockito:mockito-core:' + versions.mockito testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin diff --git a/engine/src/main/java/com/afollestad/nocknock/engine/EngineModule.java b/engine/src/main/java/com/afollestad/nocknock/engine/EngineModule.kt similarity index 73% rename from engine/src/main/java/com/afollestad/nocknock/engine/EngineModule.java rename to engine/src/main/java/com/afollestad/nocknock/engine/EngineModule.kt index bc7599e..e766ca3 100644 --- a/engine/src/main/java/com/afollestad/nocknock/engine/EngineModule.java +++ b/engine/src/main/java/com/afollestad/nocknock/engine/EngineModule.kt @@ -1,4 +1,4 @@ -/* +/** * Designed and developed by Aidan Follestad (@afollestad) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,19 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.afollestad.nocknock.engine; +package com.afollestad.nocknock.engine -import com.afollestad.nocknock.engine.validation.RealValidationManager; -import com.afollestad.nocknock.engine.validation.ValidationManager; -import dagger.Binds; -import dagger.Module; -import javax.inject.Singleton; +import com.afollestad.nocknock.engine.validation.RealValidationManager +import com.afollestad.nocknock.engine.validation.ValidationManager +import org.koin.dsl.module.module + +const val ENGINE_MODULE = "engine" /** @author Aidan Follestad (@afollestad) */ -@Module -public abstract class EngineModule { +val engineModule = module(ENGINE_MODULE) { - @Binds - @Singleton - abstract ValidationManager provideValidationManager(RealValidationManager checkStatusManager); + single { + RealValidationManager(get(), get(), get(), get(), get(), get()) + } bind ValidationManager::class } diff --git a/engine/src/main/java/com/afollestad/nocknock/engine/validation/BootReceiver.kt b/engine/src/main/java/com/afollestad/nocknock/engine/validation/BootReceiver.kt index efdef8e..deab303 100644 --- a/engine/src/main/java/com/afollestad/nocknock/engine/validation/BootReceiver.kt +++ b/engine/src/main/java/com/afollestad/nocknock/engine/validation/BootReceiver.kt @@ -19,19 +19,22 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.Intent.ACTION_BOOT_COMPLETED -import com.afollestad.nocknock.utilities.ext.injector -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main +import com.afollestad.nocknock.utilities.Qualifiers.IO_DISPATCHER +import com.afollestad.nocknock.utilities.Qualifiers.MAIN_DISPATCHER +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async import kotlinx.coroutines.launch -import javax.inject.Inject +import kotlinx.coroutines.withContext +import org.koin.standalone.KoinComponent +import org.koin.standalone.inject import timber.log.Timber.d as log /** @author Aidan Follestad (@afollestad) */ -class BootReceiver : BroadcastReceiver() { +class BootReceiver : BroadcastReceiver(), KoinComponent { - @Inject lateinit var checkStatusManager: ValidationManager + private val validationManager by inject() + private val mainDispatcher by inject(name = MAIN_DISPATCHER) + private val ioDispatcher by inject(name = IO_DISPATCHER) override fun onReceive( context: Context, @@ -42,12 +45,10 @@ class BootReceiver : BroadcastReceiver() { } log("Received boot event! Let's go.") - context.injector() - .injectInto(this) val pendingResult = goAsync() - GlobalScope.launch(Main) { - async(IO) { checkStatusManager.ensureScheduledChecks() }.await() + GlobalScope.launch(mainDispatcher) { + withContext(ioDispatcher) { validationManager.ensureScheduledChecks() } pendingResult.resultCode = 0 pendingResult.finish() } diff --git a/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationJob.kt b/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationJob.kt index 69e6c54..8110273 100644 --- a/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationJob.kt +++ b/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationJob.kt @@ -19,6 +19,7 @@ import android.app.job.JobParameters import android.app.job.JobService import android.content.Intent import com.afollestad.nocknock.data.AppDatabase +import com.afollestad.nocknock.data.getSite import com.afollestad.nocknock.data.model.Site import com.afollestad.nocknock.data.model.Status import com.afollestad.nocknock.data.model.Status.CHECKING @@ -29,11 +30,9 @@ import com.afollestad.nocknock.data.model.ValidationMode.JAVASCRIPT import com.afollestad.nocknock.data.model.ValidationMode.STATUS_CODE import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH import com.afollestad.nocknock.data.model.isPending -import com.afollestad.nocknock.data.getSite import com.afollestad.nocknock.data.updateSite import com.afollestad.nocknock.engine.BuildConfig.APPLICATION_ID import com.afollestad.nocknock.notifications.NockNotificationManager -import com.afollestad.nocknock.utilities.ext.injector import com.afollestad.nocknock.utilities.js.JavaScript import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main @@ -41,8 +40,8 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.koin.android.ext.android.inject import java.lang.System.currentTimeMillis -import javax.inject.Inject import timber.log.Timber.d as log /** @@ -59,12 +58,11 @@ class ValidationJob : JobService() { const val KEY_SITE_ID = "site.id" } - @Inject lateinit var database: AppDatabase - @Inject lateinit var checkStatusManager: ValidationManager - @Inject lateinit var notificationManager: NockNotificationManager + private val database by inject() + private val validaitonManager by inject() + private val notificationManager by inject() override fun onStartJob(params: JobParameters): Boolean { - injector().injectInto(this) val siteId = params.extras.getLong(KEY_SITE_ID) GlobalScope.launch(Main) { @@ -84,7 +82,7 @@ class ValidationJob : JobService() { val jobResult = async(IO) { updateStatus(site, CHECKING) - val checkResult = checkStatusManager.performCheck(site) + val checkResult = validaitonManager.performCheck(site) val resultModel = checkResult.model val resultResponse = checkResult.response val result = resultModel.lastResult!! @@ -144,7 +142,7 @@ class ValidationJob : JobService() { notificationManager.postStatusNotification(jobResult) } - checkStatusManager.scheduleCheck( + validaitonManager.scheduleCheck( site = jobResult, fromFinishingJob = true ) diff --git a/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationManager.kt b/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationManager.kt index b7f129f..d24d4d3 100644 --- a/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationManager.kt +++ b/engine/src/main/java/com/afollestad/nocknock/engine/validation/ValidationManager.kt @@ -33,7 +33,6 @@ import okhttp3.Response import org.jetbrains.annotations.TestOnly import java.net.SocketTimeoutException import java.util.concurrent.TimeUnit.MILLISECONDS -import javax.inject.Inject import timber.log.Timber.d as log /** @author Aidan Follestad (@afollestad) */ @@ -61,7 +60,7 @@ interface ValidationManager { suspend fun performCheck(site: Site): CheckResult } -class RealValidationManager @Inject constructor( +class RealValidationManager( private val jobScheduler: JobScheduler, private val okHttpClient: OkHttpClient, private val stringProvider: StringProvider, diff --git a/notifications/build.gradle b/notifications/build.gradle index e843285..24fd449 100644 --- a/notifications/build.gradle +++ b/notifications/build.gradle @@ -14,7 +14,7 @@ android { } dependencies { - implementation project(':utilities') + implementation project(':common') api 'androidx.appcompat:appcompat:' + versions.androidx @@ -22,10 +22,10 @@ dependencies { api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines - implementation 'com.google.dagger:dagger:' + versions.dagger - kapt 'com.google.dagger:dagger-compiler:' + versions.dagger + implementation 'org.koin:koin-android:' + versions.koin implementation 'com.jakewharton.timber:timber:' + versions.timber + testImplementation 'junit:junit:' + versions.junit testImplementation 'org.mockito:mockito-core:' + versions.mockito testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin diff --git a/notifications/src/main/java/com/afollestad/nocknock/notifications/NockNotificationManager.kt b/notifications/src/main/java/com/afollestad/nocknock/notifications/NockNotificationManager.kt index 35acd46..5be2912 100644 --- a/notifications/src/main/java/com/afollestad/nocknock/notifications/NockNotificationManager.kt +++ b/notifications/src/main/java/com/afollestad/nocknock/notifications/NockNotificationManager.kt @@ -26,8 +26,6 @@ import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider import com.afollestad.nocknock.utilities.providers.NotificationProvider import com.afollestad.nocknock.utilities.providers.RealIntentProvider.Companion.BASE_NOTIFICATION_REQUEST_CODE import com.afollestad.nocknock.utilities.providers.StringProvider -import com.afollestad.nocknock.utilities.qualifiers.AppIconRes -import javax.inject.Inject import timber.log.Timber.d as log /** @author Aidan Follestad (@afollestad) */ @@ -45,8 +43,8 @@ interface NockNotificationManager { } /** @author Aidan Follestad (@afollestad) */ -class RealNockNotificationManager @Inject constructor( - @AppIconRes private val appIconRes: Int, +class RealNockNotificationManager( + private val appIconRes: Int, private val stockManager: NotificationManager, private val bitmapProvider: BitmapProvider, private val stringProvider: StringProvider, diff --git a/notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.java b/notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.java deleted file mode 100644 index d43d339..0000000 --- a/notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.notifications; - -import dagger.Binds; -import dagger.Module; -import javax.inject.Singleton; - -/** @author Aidan Follestad (@afollestad) */ -@Module -public abstract class NotificationsModule { - - @Binds - @Singleton - abstract NockNotificationManager provideNockNotificationManager( - RealNockNotificationManager notificationManager); -} diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/Injector.kt b/notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.kt similarity index 53% rename from utilities/src/main/java/com/afollestad/nocknock/utilities/Injector.kt rename to notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.kt index 89972e4..3f2a9a6 100644 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/Injector.kt +++ b/notifications/src/main/java/com/afollestad/nocknock/notifications/NotificationsModule.kt @@ -13,10 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.afollestad.nocknock.utilities +package com.afollestad.nocknock.notifications -/** @author Aidan Follestad (@afollestad)*/ -interface Injector { +import com.afollestad.nocknock.notifications.Qualifiers.APP_ICON_RES +import org.koin.dsl.module.module - fun injectInto(target: Any) +const val NOTIFICATIONS_MODULE = "notifications" + +object Qualifiers { + const val APP_ICON_RES = "main.app_icon_res" +} + +val notificationsModule = module(NOTIFICATIONS_MODULE) { + + single { + RealNockNotificationManager( + get(name = APP_ICON_RES), + get(), + get(), + get(), + get(), + get(), + get() + ) + } bind NockNotificationManager::class } diff --git a/settings.gradle b/settings.gradle index 71dab80..cc839f9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':engine', ':notifications', ':data', ':utilities', ':viewcomponents' +include ':app', ':engine', ':notifications', ':data', ':common', ':viewcomponents' diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/InjectorExt.kt b/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/InjectorExt.kt deleted file mode 100644 index ebf2fb0..0000000 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/ext/InjectorExt.kt +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.utilities.ext - -import android.app.job.JobService -import android.content.Context -import com.afollestad.nocknock.utilities.Injector - -fun Context.injector() = applicationContext as Injector - -fun JobService.injector() = applicationContext as Injector diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/AppIconRes.kt b/utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/AppIconRes.kt deleted file mode 100644 index bae9b30..0000000 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/AppIconRes.kt +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.utilities.qualifiers - -import javax.inject.Qualifier -import kotlin.annotation.AnnotationRetention.RUNTIME - -/** @author Aidan Follestad (@afollestad) */ -@Qualifier -@Retention(RUNTIME) -annotation class AppIconRes diff --git a/utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/MainActivityClass.kt b/utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/MainActivityClass.kt deleted file mode 100644 index db9ee3a..0000000 --- a/utilities/src/main/java/com/afollestad/nocknock/utilities/qualifiers/MainActivityClass.kt +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Designed and developed by Aidan Follestad (@afollestad) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.afollestad.nocknock.utilities.qualifiers - -import javax.inject.Qualifier -import kotlin.annotation.AnnotationRetention.RUNTIME - -/** @author Aidan Follestad (@afollestad) */ -@Qualifier -@Retention(RUNTIME) -annotation class MainActivityClass diff --git a/viewcomponents/build.gradle b/viewcomponents/build.gradle index 51bd417..aaa0ab7 100644 --- a/viewcomponents/build.gradle +++ b/viewcomponents/build.gradle @@ -15,16 +15,13 @@ android { } dependencies { - implementation project(':utilities') + implementation project(':common') implementation project(':data') implementation 'androidx.appcompat:appcompat:' + versions.androidx api 'androidx.lifecycle:lifecycle-extensions:' + versions.lifecycle api 'com.squareup.okhttp3:okhttp:' + versions.okHttp - - implementation 'com.google.dagger:dagger:' + versions.dagger - kapt 'com.google.dagger:dagger-compiler:' + versions.dagger } apply from: '../spotless.gradle' \ No newline at end of file diff --git a/viewcomponents/src/main/java/com/afollestad/nocknock/viewcomponents/LoadingIndicatorFrame.kt b/viewcomponents/src/main/java/com/afollestad/nocknock/viewcomponents/LoadingIndicatorFrame.kt index a91b11c..2745a3f 100644 --- a/viewcomponents/src/main/java/com/afollestad/nocknock/viewcomponents/LoadingIndicatorFrame.kt +++ b/viewcomponents/src/main/java/com/afollestad/nocknock/viewcomponents/LoadingIndicatorFrame.kt @@ -46,7 +46,14 @@ class LoadingIndicatorFrame( isFocusable = true } - fun setIsLoading(isLoading: Boolean) { + fun observe( + owner: LifecycleOwner, + data: LiveData + ) = data.observe(owner, Observer { + setIsLoading(it) + }) + + private fun setIsLoading(isLoading: Boolean) { delayHandler.removeCallbacks(showRunnable) if (isLoading) { delayHandler.postDelayed(showRunnable, SHOW_DELAY_MS) @@ -54,11 +61,4 @@ class LoadingIndicatorFrame( hide() } } - - fun observe( - owner: LifecycleOwner, - data: LiveData - ) = data.observe(owner, Observer { - setIsLoading(it) - }) }