mirror of
https://github.com/afollestad/nock-nock.git
synced 2025-08-06 16:08:39 +00:00
Switch from Dagger to Koin, resolves #35
This commit is contained in:
parent
c9750f5f66
commit
1e92644904
61 changed files with 385 additions and 660 deletions
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
|
@ -3,11 +3,11 @@
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/common/common.iml" filepath="$PROJECT_DIR$/common/common.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/data/data.iml" filepath="$PROJECT_DIR$/data/data.iml" />
|
<module fileurl="file://$PROJECT_DIR$/data/data.iml" filepath="$PROJECT_DIR$/data/data.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/engine/engine.iml" filepath="$PROJECT_DIR$/engine/engine.iml" />
|
<module fileurl="file://$PROJECT_DIR$/engine/engine.iml" filepath="$PROJECT_DIR$/engine/engine.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/nock-nock.iml" filepath="$PROJECT_DIR$/nock-nock.iml" />
|
<module fileurl="file://$PROJECT_DIR$/nock-nock.iml" filepath="$PROJECT_DIR$/nock-nock.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/notifications/notifications.iml" filepath="$PROJECT_DIR$/notifications/notifications.iml" />
|
<module fileurl="file://$PROJECT_DIR$/notifications/notifications.iml" filepath="$PROJECT_DIR$/notifications/notifications.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/utilities/utilities.iml" filepath="$PROJECT_DIR$/utilities/utilities.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/viewcomponents/viewcomponents.iml" filepath="$PROJECT_DIR$/viewcomponents/viewcomponents.iml" />
|
<module fileurl="file://$PROJECT_DIR$/viewcomponents/viewcomponents.iml" filepath="$PROJECT_DIR$/viewcomponents/viewcomponents.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -18,7 +18,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':utilities')
|
implementation project(':common')
|
||||||
implementation project(':engine')
|
implementation project(':engine')
|
||||||
implementation project(':data')
|
implementation project(':data')
|
||||||
implementation project(':notifications')
|
implementation project(':notifications')
|
||||||
|
@ -32,16 +32,22 @@ dependencies {
|
||||||
|
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin
|
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin
|
||||||
|
|
||||||
implementation 'com.google.dagger:dagger:' + versions.dagger
|
implementation 'org.koin:koin-android:' + versions.koin
|
||||||
kapt 'com.google.dagger:dagger-compiler:' + versions.dagger
|
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.afollestad.material-dialogs:core:' + versions.materialDialogs
|
||||||
|
|
||||||
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
||||||
|
|
||||||
testImplementation 'junit:junit:' + versions.junit
|
testImplementation 'junit:junit:' + versions.junit
|
||||||
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
||||||
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
||||||
testImplementation 'com.google.truth:truth:' + versions.truth
|
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'
|
apply from: '../spotless.gradle'
|
|
@ -16,55 +16,42 @@
|
||||||
package com.afollestad.nocknock
|
package com.afollestad.nocknock
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.afollestad.nocknock.di.AppComponent
|
import com.afollestad.nocknock.engine.engineModule
|
||||||
import com.afollestad.nocknock.di.DaggerAppComponent
|
import com.afollestad.nocknock.koin.mainModule
|
||||||
import com.afollestad.nocknock.engine.validation.BootReceiver
|
import com.afollestad.nocknock.koin.viewModelModule
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationJob
|
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||||
import com.afollestad.nocknock.ui.addsite.AddSiteActivity
|
import com.afollestad.nocknock.notifications.notificationsModule
|
||||||
import com.afollestad.nocknock.ui.main.MainActivity
|
import com.afollestad.nocknock.utilities.utilitiesModule
|
||||||
import com.afollestad.nocknock.ui.viewsite.ViewSiteActivity
|
import org.koin.android.ext.android.inject
|
||||||
import com.afollestad.nocknock.utilities.Injector
|
import org.koin.android.ext.android.startKoin
|
||||||
import com.afollestad.nocknock.utilities.ext.systemService
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import timber.log.Timber.DebugTree
|
import timber.log.Timber.DebugTree
|
||||||
import javax.inject.Inject
|
|
||||||
import timber.log.Timber.d as log
|
import timber.log.Timber.d as log
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class NockNockApp : Application(), Injector {
|
class NockNockApp : Application() {
|
||||||
|
|
||||||
private lateinit var appComponent: AppComponent
|
|
||||||
@Inject lateinit var nockNotificationManager: NockNotificationManager
|
|
||||||
|
|
||||||
private var resumedActivities: Int = 0
|
private var resumedActivities: Int = 0
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Timber.plant(DebugTree())
|
Timber.plant(DebugTree())
|
||||||
}
|
}
|
||||||
|
|
||||||
val okHttpClient = OkHttpClient.Builder()
|
val modules = listOf(
|
||||||
.addNetworkInterceptor { chain ->
|
mainModule,
|
||||||
val request = chain.request()
|
engineModule,
|
||||||
.newBuilder()
|
utilitiesModule,
|
||||||
.addHeader("User-Agent", "com.afollestad.nocknock")
|
notificationsModule,
|
||||||
.build()
|
viewModelModule
|
||||||
chain.proceed(request)
|
)
|
||||||
}
|
startKoin(
|
||||||
.build()
|
androidContext = this,
|
||||||
|
modules = modules
|
||||||
appComponent = DaggerAppComponent.builder()
|
)
|
||||||
.application(this)
|
|
||||||
.okHttpClient(okHttpClient)
|
|
||||||
.jobScheduler(systemService(JOB_SCHEDULER_SERVICE))
|
|
||||||
.notificationManager(systemService(NOTIFICATION_SERVICE))
|
|
||||||
.build()
|
|
||||||
appComponent.inject(this)
|
|
||||||
|
|
||||||
|
val nockNotificationManager by inject<NockNotificationManager>()
|
||||||
onActivityLifeChange { activity, resumed ->
|
onActivityLifeChange { activity, resumed ->
|
||||||
if (resumed) {
|
if (resumed) {
|
||||||
resumedActivities++
|
resumedActivities++
|
||||||
|
@ -77,13 +64,4 @@ class NockNockApp : Application(), Injector {
|
||||||
nockNotificationManager.setIsAppOpen(resumedActivities > 0)
|
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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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<Class<out ViewModel>, Provider<ViewModel>>
|
|
||||||
|
|
||||||
@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
|
|
||||||
@Retention(RUNTIME)
|
|
||||||
@MapKey
|
|
||||||
annotation class ViewModelKey(val value: KClass<out ViewModel>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://proandroiddev.com/viewmodel-with-dagger2-architecture-components-2e06f06c9455
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
class ViewModelFactory @Inject constructor(private val viewModels: ViewModelMap) :
|
|
||||||
ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return viewModels[modelClass]?.get() as T
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
63
app/src/main/java/com/afollestad/nocknock/koin/MainModule.kt
Normal file
63
app/src/main/java/com/afollestad/nocknock/koin/MainModule.kt
Normal file
|
@ -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<JobScheduler> {
|
||||||
|
get<Application>().systemService(JOB_SCHEDULER_SERVICE)
|
||||||
|
}
|
||||||
|
|
||||||
|
single<NotificationManager> {
|
||||||
|
get<Application>().systemService(NOTIFICATION_SERVICE)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,21 +13,16 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.di.viewmodels
|
package com.afollestad.nocknock.ui
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.afollestad.nocknock.di.qualifiers.MainDispatcher
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
abstract class ScopedViewModel : ViewModel() {
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
|
abstract class ScopedViewModel(mainDispatcher: CoroutineDispatcher) : ViewModel() {
|
||||||
@Inject
|
|
||||||
@MainDispatcher
|
|
||||||
lateinit var mainDispatcher: CoroutineDispatcher
|
|
||||||
|
|
||||||
private val job = Job()
|
private val job = Job()
|
||||||
protected val scope = CoroutineScope(job + mainDispatcher)
|
protected val scope = CoroutineScope(job + mainDispatcher)
|
|
@ -19,11 +19,8 @@ import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.ViewModelProviders
|
|
||||||
import com.afollestad.nocknock.R
|
import com.afollestad.nocknock.R
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode
|
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.attachLiveData
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.conceal
|
import com.afollestad.nocknock.viewcomponents.ext.conceal
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.onLayout
|
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.textUrlWarning
|
||||||
import kotlinx.android.synthetic.main.activity_addsite.toolbar
|
import kotlinx.android.synthetic.main.activity_addsite.toolbar
|
||||||
import kotlinx.android.synthetic.main.activity_addsite.validationModeDescription
|
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.math.max
|
||||||
import kotlin.properties.Delegates.notNull
|
import kotlin.properties.Delegates.notNull
|
||||||
|
|
||||||
|
@ -58,19 +55,13 @@ class AddSiteActivity : AppCompatActivity() {
|
||||||
var revealCy by notNull<Int>()
|
var revealCy by notNull<Int>()
|
||||||
var revealRadius by notNull<Float>()
|
var revealRadius by notNull<Float>()
|
||||||
|
|
||||||
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
|
|
||||||
|
|
||||||
internal var isClosing = false
|
internal var isClosing = false
|
||||||
private val viewModel by lazy {
|
|
||||||
return@lazy ViewModelProviders.of(this, viewModelFactory)
|
private val viewModel by viewModel<AddSiteViewModel>()
|
||||||
.get(AddSiteViewModel::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
injector().injectInto(this)
|
|
||||||
setContentView(R.layout.activity_addsite)
|
setContentView(R.layout.activity_addsite)
|
||||||
setupUi(savedInstanceState)
|
setupUi(savedInstanceState)
|
||||||
|
|
||||||
|
|
|
@ -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.STATUS_CODE
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH
|
import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH
|
||||||
import com.afollestad.nocknock.data.putSite
|
import com.afollestad.nocknock.data.putSite
|
||||||
import com.afollestad.nocknock.di.viewmodels.ScopedViewModel
|
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationManager
|
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.isNullOrLessThan
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.map
|
import com.afollestad.nocknock.viewcomponents.ext.map
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class AddSiteViewModel @Inject constructor(
|
class AddSiteViewModel(
|
||||||
private val database: AppDatabase,
|
private val database: AppDatabase,
|
||||||
private val validationManager: ValidationManager,
|
private val validationManager: ValidationManager,
|
||||||
@field:IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
mainDispatcher: CoroutineDispatcher,
|
||||||
) : ScopedViewModel(), LifecycleObserver {
|
private val ioDispatcher: CoroutineDispatcher
|
||||||
|
) : ScopedViewModel(mainDispatcher), LifecycleObserver {
|
||||||
|
|
||||||
// Public properties
|
// Public properties
|
||||||
val name = MutableLiveData<String>()
|
val name = MutableLiveData<String>()
|
||||||
|
|
|
@ -19,8 +19,6 @@ import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.ViewModelProviders
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
@ -28,31 +26,27 @@ import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.list.listItems
|
import com.afollestad.materialdialogs.list.listItems
|
||||||
import com.afollestad.nocknock.R
|
import com.afollestad.nocknock.R
|
||||||
import com.afollestad.nocknock.adapter.ServerAdapter
|
import com.afollestad.nocknock.adapter.ServerAdapter
|
||||||
|
import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver
|
||||||
import com.afollestad.nocknock.data.model.Site
|
import com.afollestad.nocknock.data.model.Site
|
||||||
import com.afollestad.nocknock.dialogs.AboutDialog
|
import com.afollestad.nocknock.dialogs.AboutDialog
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
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 com.afollestad.nocknock.viewcomponents.ext.showOrHide
|
||||||
import kotlinx.android.synthetic.main.activity_main.fab
|
import kotlinx.android.synthetic.main.activity_main.fab
|
||||||
import kotlinx.android.synthetic.main.activity_main.list
|
import kotlinx.android.synthetic.main.activity_main.list
|
||||||
import kotlinx.android.synthetic.main.activity_main.loadingProgress
|
import kotlinx.android.synthetic.main.activity_main.loadingProgress
|
||||||
import kotlinx.android.synthetic.main.activity_main.toolbar
|
import kotlinx.android.synthetic.main.activity_main.toolbar
|
||||||
import kotlinx.android.synthetic.main.include_empty_view.emptyText
|
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) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@Inject lateinit var notificationManager: NockNotificationManager
|
private val notificationManager by inject<NockNotificationManager>()
|
||||||
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
|
internal val viewModel by viewModel<MainViewModel>()
|
||||||
|
|
||||||
private lateinit var adapter: ServerAdapter
|
private lateinit var adapter: ServerAdapter
|
||||||
|
|
||||||
internal val viewModel by lazy {
|
|
||||||
return@lazy ViewModelProviders.of(this, viewModelFactory)
|
|
||||||
.get(MainViewModel::class.java)
|
|
||||||
}
|
|
||||||
private val statusUpdateReceiver =
|
private val statusUpdateReceiver =
|
||||||
StatusUpdateIntentReceiver(application) {
|
StatusUpdateIntentReceiver(application) {
|
||||||
viewModel.postSiteUpdate(it)
|
viewModel.postSiteUpdate(it)
|
||||||
|
@ -60,7 +54,6 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
injector().injectInto(this)
|
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
setupUi()
|
setupUi()
|
||||||
|
|
||||||
|
|
|
@ -25,22 +25,21 @@ import com.afollestad.nocknock.data.AppDatabase
|
||||||
import com.afollestad.nocknock.data.allSites
|
import com.afollestad.nocknock.data.allSites
|
||||||
import com.afollestad.nocknock.data.deleteSite
|
import com.afollestad.nocknock.data.deleteSite
|
||||||
import com.afollestad.nocknock.data.model.Site
|
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.engine.validation.ValidationManager
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
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.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class MainViewModel @Inject constructor(
|
class MainViewModel(
|
||||||
private val database: AppDatabase,
|
private val database: AppDatabase,
|
||||||
private val notificationManager: NockNotificationManager,
|
private val notificationManager: NockNotificationManager,
|
||||||
private val validationManager: ValidationManager,
|
private val validationManager: ValidationManager,
|
||||||
@field:IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
mainDispatcher: CoroutineDispatcher,
|
||||||
) : ScopedViewModel(), LifecycleObserver {
|
private val ioDispatcher: CoroutineDispatcher
|
||||||
|
) : ScopedViewModel(mainDispatcher), LifecycleObserver {
|
||||||
|
|
||||||
private val sites = MutableLiveData<List<Site>>()
|
private val sites = MutableLiveData<List<Site>>()
|
||||||
private val isLoading = MutableLiveData<Boolean>()
|
private val isLoading = MutableLiveData<Boolean>()
|
||||||
|
|
|
@ -21,13 +21,10 @@ import android.os.Bundle
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.ViewModelProviders
|
|
||||||
import com.afollestad.nocknock.R
|
import com.afollestad.nocknock.R
|
||||||
|
import com.afollestad.nocknock.broadcasts.StatusUpdateIntentReceiver
|
||||||
import com.afollestad.nocknock.data.model.Site
|
import com.afollestad.nocknock.data.model.Site
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode
|
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.attachLiveData
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
|
import com.afollestad.nocknock.viewcomponents.ext.dimenFloat
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.onScroll
|
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.textUrlWarning
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.toolbar
|
import kotlinx.android.synthetic.main.activity_viewsite.toolbar
|
||||||
import kotlinx.android.synthetic.main.activity_viewsite.validationModeDescription
|
import kotlinx.android.synthetic.main.activity_viewsite.validationModeDescription
|
||||||
import javax.inject.Inject
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class ViewSiteActivity : AppCompatActivity() {
|
class ViewSiteActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
|
internal val viewModel by viewModel<ViewSiteViewModel>()
|
||||||
|
|
||||||
internal val viewModel by lazy {
|
|
||||||
return@lazy ViewModelProviders.of(this, viewModelFactory)
|
|
||||||
.get(ViewSiteViewModel::class.java)
|
|
||||||
}
|
|
||||||
private val statusUpdateReceiver =
|
private val statusUpdateReceiver =
|
||||||
StatusUpdateIntentReceiver(application) {
|
StatusUpdateIntentReceiver(application) {
|
||||||
viewModel.setModel(it)
|
viewModel.setModel(it)
|
||||||
|
@ -70,8 +63,6 @@ class ViewSiteActivity : AppCompatActivity() {
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
injector().injectInto(this)
|
|
||||||
setContentView(R.layout.activity_viewsite)
|
setContentView(R.layout.activity_viewsite)
|
||||||
setupUi()
|
setupUi()
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.ui.viewsite
|
package com.afollestad.nocknock.ui.viewsite
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import androidx.annotation.CheckResult
|
import androidx.annotation.CheckResult
|
||||||
import androidx.lifecycle.LifecycleObserver
|
import androidx.lifecycle.LifecycleObserver
|
||||||
import androidx.lifecycle.LiveData
|
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.ValidationResult
|
||||||
import com.afollestad.nocknock.data.model.textRes
|
import com.afollestad.nocknock.data.model.textRes
|
||||||
import com.afollestad.nocknock.data.updateSite
|
import com.afollestad.nocknock.data.updateSite
|
||||||
import com.afollestad.nocknock.di.viewmodels.ScopedViewModel
|
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationManager
|
import com.afollestad.nocknock.engine.validation.ValidationManager
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||||
|
import com.afollestad.nocknock.ui.ScopedViewModel
|
||||||
import com.afollestad.nocknock.utilities.ext.formatDate
|
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.isNullOrLessThan
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.map
|
import com.afollestad.nocknock.viewcomponents.ext.map
|
||||||
import com.afollestad.nocknock.viewcomponents.ext.zip
|
import com.afollestad.nocknock.viewcomponents.ext.zip
|
||||||
|
@ -46,16 +45,16 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class ViewSiteViewModel @Inject constructor(
|
class ViewSiteViewModel(
|
||||||
private val app: Application,
|
private val stringProvider: StringProvider,
|
||||||
private val database: AppDatabase,
|
private val database: AppDatabase,
|
||||||
private val notificationManager: NockNotificationManager,
|
private val notificationManager: NockNotificationManager,
|
||||||
private val validationManager: ValidationManager,
|
private val validationManager: ValidationManager,
|
||||||
@field:IoDispatcher private val ioDispatcher: CoroutineDispatcher
|
mainDispatcher: CoroutineDispatcher,
|
||||||
) : ScopedViewModel(), LifecycleObserver {
|
private val ioDispatcher: CoroutineDispatcher
|
||||||
|
) : ScopedViewModel(mainDispatcher), LifecycleObserver {
|
||||||
|
|
||||||
lateinit var site: Site
|
lateinit var site: Site
|
||||||
|
|
||||||
|
@ -134,13 +133,13 @@ class ViewSiteViewModel @Inject constructor(
|
||||||
|
|
||||||
@CheckResult fun onLastCheckResultText(): LiveData<String> = lastResult.map {
|
@CheckResult fun onLastCheckResultText(): LiveData<String> = lastResult.map {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
app.getString(R.string.none)
|
stringProvider.get(R.string.none)
|
||||||
} else {
|
} else {
|
||||||
val statusText = it.status.textRes()
|
val statusText = it.status.textRes()
|
||||||
if (statusText == 0) {
|
if (statusText == 0) {
|
||||||
it.reason
|
it.reason
|
||||||
} else {
|
} else {
|
||||||
app.getString(statusText)
|
stringProvider.get(statusText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +150,7 @@ class ViewSiteViewModel @Inject constructor(
|
||||||
val disabled = it.first
|
val disabled = it.first
|
||||||
val lastResult = it.second
|
val lastResult = it.second
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
app.getString(R.string.auto_checks_disabled)
|
stringProvider.get(R.string.auto_checks_disabled)
|
||||||
} else {
|
} else {
|
||||||
val lastCheck = lastResult?.timestampMs ?: currentTimeMillis()
|
val lastCheck = lastResult?.timestampMs ?: currentTimeMillis()
|
||||||
(lastCheck + getCheckIntervalMs()).formatDate()
|
(lastCheck + getCheckIntervalMs()).formatDate()
|
||||||
|
|
|
@ -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
|
package com.afollestad.nocknock
|
||||||
|
|
||||||
import androidx.annotation.CheckResult
|
import androidx.annotation.CheckResult
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
import com.google.common.truth.Truth.assertWithMessage
|
import com.google.common.truth.Truth.assertWithMessage
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
|
@ -22,12 +38,11 @@ class TestLiveData<T>(data: LiveData<T>) {
|
||||||
|
|
||||||
fun assertValues(vararg assertValues: T) {
|
fun assertValues(vararg assertValues: T) {
|
||||||
val assertList = assertValues.toList()
|
val assertList = assertValues.toList()
|
||||||
assertWithMessage("Expected: $assertList, but got: $receivedValues").that(receivedValues)
|
assertThat(receivedValues).isEqualTo(assertList)
|
||||||
.isEqualTo(assertList)
|
|
||||||
receivedValues.clear()
|
receivedValues.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckResult fun values(): List<T> = receivedValues
|
@CheckResult fun values(): List<T> = receivedValues
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckResult fun <T> LiveData<T>.test() = TestLiveData(this)
|
@CheckResult fun <T> LiveData<T>.test() = TestLiveData(this)
|
||||||
|
|
|
@ -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
|
package com.afollestad.nocknock.broadcasts
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
@ -52,4 +67,4 @@ class StatusUpdateIntentReceiverTest {
|
||||||
receiver.onPause()
|
receiver.onPause()
|
||||||
verify(app).unregisterReceiver(receiver.intentReceiver)
|
verify(app).unregisterReceiver(receiver.intentReceiver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ package com.afollestad.nocknock.ui.addsite
|
||||||
//import org.junit.Before
|
//import org.junit.Before
|
||||||
//import org.junit.Test
|
//import org.junit.Test
|
||||||
//
|
//
|
||||||
//class AddSitePresenterTest {
|
//class AddSiteViewModelTest {
|
||||||
//
|
//
|
||||||
// private val database = mockDatabase()
|
// private val database = mockDatabase()
|
||||||
// private val checkStatusManager = mock<ValidationManager>()
|
// private val checkStatusManager = mock<ValidationManager>()
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.ui.main
|
package com.afollestad.nocknock.ui.main
|
||||||
|
|
||||||
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import com.afollestad.nocknock.ALL_MOCK_MODELS
|
import com.afollestad.nocknock.ALL_MOCK_MODELS
|
||||||
import com.afollestad.nocknock.MOCK_MODEL_1
|
import com.afollestad.nocknock.MOCK_MODEL_1
|
||||||
import com.afollestad.nocknock.MOCK_MODEL_2
|
import com.afollestad.nocknock.MOCK_MODEL_2
|
||||||
|
@ -28,22 +29,25 @@ import com.nhaarman.mockitokotlin2.verify
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class MainViewModelTest {
|
class MainViewModelTest {
|
||||||
|
|
||||||
private val database = mockDatabase()
|
private val database = mockDatabase()
|
||||||
private val notificationManager = mock<NockNotificationManager>()
|
private val notificationManager = mock<NockNotificationManager>()
|
||||||
private val validationManager = mock<ValidationManager>()
|
private val validationManager = mock<ValidationManager>()
|
||||||
|
|
||||||
|
@Rule @JvmField val rule = InstantTaskExecutorRule()
|
||||||
|
|
||||||
private val viewModel = MainViewModel(
|
private val viewModel = MainViewModel(
|
||||||
database,
|
database,
|
||||||
notificationManager,
|
notificationManager,
|
||||||
validationManager,
|
validationManager,
|
||||||
Dispatchers.Default
|
Dispatchers.Unconfined,
|
||||||
).apply {
|
Dispatchers.Unconfined
|
||||||
this.mainDispatcher = Dispatchers.Default
|
)
|
||||||
}
|
|
||||||
|
|
||||||
@After fun tearDown() = viewModel.destroy()
|
@After fun tearDown() = viewModel.destroy()
|
||||||
|
|
||||||
|
@ -92,7 +96,6 @@ class MainViewModelTest {
|
||||||
viewModel.postSiteUpdate(updatedModel2)
|
viewModel.postSiteUpdate(updatedModel2)
|
||||||
|
|
||||||
sites.assertValues(updatedSites)
|
sites.assertValues(updatedSites)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun refreshSite() {
|
@Test fun refreshSite() {
|
||||||
|
@ -116,6 +119,7 @@ class MainViewModelTest {
|
||||||
listOf(),
|
listOf(),
|
||||||
ALL_MOCK_MODELS
|
ALL_MOCK_MODELS
|
||||||
)
|
)
|
||||||
|
isLoading.assertValues(true, false)
|
||||||
|
|
||||||
val modifiedModel = MOCK_MODEL_1.copy(id = 11111)
|
val modifiedModel = MOCK_MODEL_1.copy(id = 11111)
|
||||||
viewModel.removeSite(modifiedModel)
|
viewModel.removeSite(modifiedModel)
|
||||||
|
@ -140,6 +144,7 @@ class MainViewModelTest {
|
||||||
listOf(),
|
listOf(),
|
||||||
ALL_MOCK_MODELS
|
ALL_MOCK_MODELS
|
||||||
)
|
)
|
||||||
|
isLoading.assertValues(true, false)
|
||||||
|
|
||||||
val modelsWithout1 = ALL_MOCK_MODELS.toMutableList()
|
val modelsWithout1 = ALL_MOCK_MODELS.toMutableList()
|
||||||
.apply {
|
.apply {
|
||||||
|
|
|
@ -15,6 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.ui.viewsite
|
package com.afollestad.nocknock.ui.viewsite
|
||||||
|
|
||||||
class ViewSitePresenterTest {
|
class ViewSiteViewModelTest
|
||||||
|
|
||||||
}
|
// TODO this will be mostly identical to the add site test
|
0
utilities/.gitignore → common/.gitignore
vendored
0
utilities/.gitignore → common/.gitignore
vendored
|
@ -26,9 +26,7 @@ dependencies {
|
||||||
api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines
|
api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines
|
||||||
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines
|
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines
|
||||||
|
|
||||||
implementation 'com.google.dagger:dagger:' + versions.dagger
|
implementation 'org.koin:koin-android:' + versions.koin
|
||||||
kapt 'com.google.dagger:dagger-compiler:' + versions.dagger
|
|
||||||
|
|
||||||
implementation 'org.mozilla:rhino:' + versions.rhino
|
implementation 'org.mozilla:rhino:' + versions.rhino
|
||||||
|
|
||||||
testImplementation 'junit:junit:' + versions.junit
|
testImplementation 'junit:junit:' + versions.junit
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/**
|
||||||
* Designed and developed by Aidan Follestad (@afollestad)
|
* Designed and developed by Aidan Follestad (@afollestad)
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.Qualifiers.IO_DISPATCHER
|
||||||
import com.afollestad.nocknock.utilities.providers.BundleProvider;
|
import com.afollestad.nocknock.utilities.Qualifiers.MAIN_ACTIVITY_CLASS
|
||||||
import com.afollestad.nocknock.utilities.providers.IntentProvider;
|
import com.afollestad.nocknock.utilities.Qualifiers.MAIN_DISPATCHER
|
||||||
import com.afollestad.nocknock.utilities.providers.JobInfoProvider;
|
import com.afollestad.nocknock.utilities.providers.BitmapProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider;
|
import com.afollestad.nocknock.utilities.providers.BundleProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.NotificationProvider;
|
import com.afollestad.nocknock.utilities.providers.IntentProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealBitmapProvider;
|
import com.afollestad.nocknock.utilities.providers.JobInfoProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealBundleProvider;
|
import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealIntentProvider;
|
import com.afollestad.nocknock.utilities.providers.NotificationProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealJobInfoProvider;
|
import com.afollestad.nocknock.utilities.providers.RealBitmapProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealNotificationChannelProvider;
|
import com.afollestad.nocknock.utilities.providers.RealBundleProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealNotificationProvider;
|
import com.afollestad.nocknock.utilities.providers.RealIntentProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealSdkProvider;
|
import com.afollestad.nocknock.utilities.providers.RealJobInfoProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.RealStringProvider;
|
import com.afollestad.nocknock.utilities.providers.RealNotificationChannelProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.SdkProvider;
|
import com.afollestad.nocknock.utilities.providers.RealNotificationProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.StringProvider;
|
import com.afollestad.nocknock.utilities.providers.RealSdkProvider
|
||||||
import dagger.Binds;
|
import com.afollestad.nocknock.utilities.providers.RealStringProvider
|
||||||
import dagger.Module;
|
import com.afollestad.nocknock.utilities.providers.SdkProvider
|
||||||
import javax.inject.Singleton;
|
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) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
@Module
|
val utilitiesModule = module(UTILITIES_MODULE) {
|
||||||
public abstract class UtilitiesModule {
|
|
||||||
|
|
||||||
@Binds
|
factory(name = MAIN_DISPATCHER) { Dispatchers.Main }
|
||||||
@Singleton
|
|
||||||
abstract SdkProvider provideSdkProvider(RealSdkProvider sdkProvider);
|
|
||||||
|
|
||||||
@Binds
|
factory(name = IO_DISPATCHER) { Dispatchers.IO }
|
||||||
@Singleton
|
|
||||||
abstract BitmapProvider provideBitmapProvider(RealBitmapProvider bitmapProvider);
|
|
||||||
|
|
||||||
@Binds
|
factory { RealSdkProvider() } bind SdkProvider::class
|
||||||
@Singleton
|
|
||||||
abstract StringProvider provideStringProvider(RealStringProvider stringProvider);
|
|
||||||
|
|
||||||
@Binds
|
factory { RealBitmapProvider(get()) } bind BitmapProvider::class
|
||||||
@Singleton
|
|
||||||
abstract IntentProvider provideIntentProvider(RealIntentProvider intentProvider);
|
|
||||||
|
|
||||||
@Binds
|
factory { RealStringProvider(get()) } bind StringProvider::class
|
||||||
@Singleton
|
|
||||||
abstract NotificationChannelProvider provideChannelProvider(
|
|
||||||
RealNotificationChannelProvider channelProvider);
|
|
||||||
|
|
||||||
@Binds
|
factory {
|
||||||
@Singleton
|
RealIntentProvider(get(), get(name = MAIN_ACTIVITY_CLASS))
|
||||||
abstract NotificationProvider provideNotificationProvider(
|
} bind IntentProvider::class
|
||||||
RealNotificationProvider notificationProvider);
|
|
||||||
|
|
||||||
@Binds
|
factory {
|
||||||
@Singleton
|
RealNotificationChannelProvider(get())
|
||||||
abstract BundleProvider provideBundleProvider(RealBundleProvider bundleProvider);
|
} bind NotificationChannelProvider::class
|
||||||
|
|
||||||
@Binds
|
factory { RealNotificationProvider(get()) } bind NotificationProvider::class
|
||||||
@Singleton
|
|
||||||
abstract JobInfoProvider provideJobInfoProvider(RealJobInfoProvider jobInfoProvider);
|
factory { RealBundleProvider() } bind BundleProvider::class
|
||||||
|
|
||||||
|
factory { RealJobInfoProvider(get()) } bind JobInfoProvider::class
|
||||||
}
|
}
|
|
@ -15,11 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.utilities.providers
|
package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.app.Application
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory.decodeResource
|
import android.graphics.BitmapFactory.decodeResource
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface BitmapProvider {
|
interface BitmapProvider {
|
||||||
|
@ -28,11 +27,11 @@ interface BitmapProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealBitmapProvider @Inject constructor(
|
class RealBitmapProvider(
|
||||||
private val app: Application
|
private val context: Context
|
||||||
) : BitmapProvider {
|
) : BitmapProvider {
|
||||||
|
|
||||||
override fun get(res: Int): Bitmap {
|
override fun get(res: Int): Bitmap {
|
||||||
return decodeResource(app.resources, res)
|
return decodeResource(context.resources, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,7 +16,6 @@
|
||||||
package com.afollestad.nocknock.utilities.providers
|
package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.os.PersistableBundle
|
import android.os.PersistableBundle
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
interface IBundle {
|
interface IBundle {
|
||||||
fun putLong(
|
fun putLong(
|
||||||
|
@ -34,7 +33,7 @@ interface BundleProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealBundleProvider @Inject constructor() : BundleProvider {
|
class RealBundleProvider : BundleProvider {
|
||||||
|
|
||||||
override fun createPersistable(bundler: IBundler): PersistableBundle {
|
override fun createPersistable(bundler: IBundler): PersistableBundle {
|
||||||
val realBundle = PersistableBundle()
|
val realBundle = PersistableBundle()
|
|
@ -15,13 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.utilities.providers
|
package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
|
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.afollestad.nocknock.utilities.qualifiers.MainActivityClass
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface CanNotifyModel : Serializable {
|
interface CanNotifyModel : Serializable {
|
||||||
|
@ -42,9 +40,9 @@ interface IntentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealIntentProvider @Inject constructor(
|
class RealIntentProvider(
|
||||||
private val app: Application,
|
private val context: Context,
|
||||||
@MainActivityClass private val mainActivity: Class<*>
|
private val mainActivityClass: Class<*>
|
||||||
) : IntentProvider {
|
) : IntentProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -55,7 +53,7 @@ class RealIntentProvider @Inject constructor(
|
||||||
override fun getPendingIntentForViewSite(model: CanNotifyModel): PendingIntent {
|
override fun getPendingIntentForViewSite(model: CanNotifyModel): PendingIntent {
|
||||||
val openIntent = getIntentForViewSite(model)
|
val openIntent = getIntentForViewSite(model)
|
||||||
return PendingIntent.getActivity(
|
return PendingIntent.getActivity(
|
||||||
app,
|
context,
|
||||||
BASE_NOTIFICATION_REQUEST_CODE + model.notiId(),
|
BASE_NOTIFICATION_REQUEST_CODE + model.notiId(),
|
||||||
openIntent,
|
openIntent,
|
||||||
FLAG_CANCEL_CURRENT
|
FLAG_CANCEL_CURRENT
|
||||||
|
@ -63,7 +61,7 @@ class RealIntentProvider @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIntentForViewSite(model: CanNotifyModel) =
|
private fun getIntentForViewSite(model: CanNotifyModel) =
|
||||||
Intent(app, mainActivity).apply {
|
Intent(context, mainActivityClass).apply {
|
||||||
putExtra(KEY_VIEW_NOTIFICATION_MODEL, model)
|
putExtra(KEY_VIEW_NOTIFICATION_MODEL, model)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,13 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.utilities.providers
|
package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.app.job.JobInfo
|
import android.app.job.JobInfo
|
||||||
import android.app.job.JobInfo.NETWORK_TYPE_ANY
|
import android.app.job.JobInfo.NETWORK_TYPE_ANY
|
||||||
import android.app.job.JobInfo.NETWORK_TYPE_UNMETERED
|
import android.app.job.JobInfo.NETWORK_TYPE_UNMETERED
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
import android.os.PersistableBundle
|
import android.os.PersistableBundle
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
interface JobInfoProvider {
|
interface JobInfoProvider {
|
||||||
|
|
||||||
|
@ -34,8 +33,8 @@ interface JobInfoProvider {
|
||||||
): JobInfo
|
): JobInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealJobInfoProvider @Inject constructor(
|
class RealJobInfoProvider(
|
||||||
private val app: Application
|
private val context: Context
|
||||||
) : JobInfoProvider {
|
) : JobInfoProvider {
|
||||||
|
|
||||||
// Note: we don't use the periodic feature of JobScheduler because it requires a
|
// Note: we don't use the periodic feature of JobScheduler because it requires a
|
||||||
|
@ -48,7 +47,7 @@ class RealJobInfoProvider @Inject constructor(
|
||||||
extras: PersistableBundle,
|
extras: PersistableBundle,
|
||||||
target: Class<*>
|
target: Class<*>
|
||||||
): JobInfo {
|
): JobInfo {
|
||||||
val component = ComponentName(app, target)
|
val component = ComponentName(context, target)
|
||||||
val networkType = if (onlyUnmeteredNetwork) {
|
val networkType = if (onlyUnmeteredNetwork) {
|
||||||
NETWORK_TYPE_UNMETERED
|
NETWORK_TYPE_UNMETERED
|
||||||
} else {
|
} else {
|
|
@ -18,7 +18,6 @@ package com.afollestad.nocknock.utilities.providers
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.os.Build.VERSION_CODES
|
import android.os.Build.VERSION_CODES
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface NotificationChannelProvider {
|
interface NotificationChannelProvider {
|
||||||
|
@ -33,7 +32,7 @@ interface NotificationChannelProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealNotificationChannelProvider @Inject constructor(
|
class RealNotificationChannelProvider(
|
||||||
private val sdkProvider: SdkProvider
|
private val sdkProvider: SdkProvider
|
||||||
) : NotificationChannelProvider {
|
) : NotificationChannelProvider {
|
||||||
|
|
|
@ -15,13 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.utilities.providers
|
package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE
|
import androidx.core.app.NotificationCompat.DEFAULT_VIBRATE
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface NotificationProvider {
|
interface NotificationProvider {
|
||||||
|
@ -37,8 +36,8 @@ interface NotificationProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealNotificationProvider @Inject constructor(
|
class RealNotificationProvider(
|
||||||
private val app: Application
|
private val context: Context
|
||||||
) : NotificationProvider {
|
) : NotificationProvider {
|
||||||
|
|
||||||
override fun create(
|
override fun create(
|
||||||
|
@ -49,7 +48,7 @@ class RealNotificationProvider @Inject constructor(
|
||||||
smallIcon: Int,
|
smallIcon: Int,
|
||||||
largeIcon: Bitmap
|
largeIcon: Bitmap
|
||||||
): Notification {
|
): Notification {
|
||||||
return NotificationCompat.Builder(app, channelId)
|
return NotificationCompat.Builder(context, channelId)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setContentText(content)
|
.setContentText(content)
|
||||||
.setContentIntent(intent)
|
.setContentIntent(intent)
|
|
@ -17,7 +17,6 @@ package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.os.Build.VERSION_CODES.O
|
import android.os.Build.VERSION_CODES.O
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface SdkProvider {
|
interface SdkProvider {
|
||||||
|
@ -26,7 +25,7 @@ interface SdkProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealSdkProvider @Inject constructor() : SdkProvider {
|
class RealSdkProvider : SdkProvider {
|
||||||
|
|
||||||
override fun hasOreo() = SDK_INT >= O
|
override fun hasOreo() = SDK_INT >= O
|
||||||
}
|
}
|
|
@ -15,9 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.utilities.providers
|
package com.afollestad.nocknock.utilities.providers
|
||||||
|
|
||||||
import android.app.Application
|
import android.content.Context
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
interface StringProvider {
|
interface StringProvider {
|
||||||
|
@ -26,11 +25,11 @@ interface StringProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealStringProvider @Inject constructor(
|
class RealStringProvider(
|
||||||
private val app: Application
|
private val context: Context
|
||||||
) : StringProvider {
|
) : StringProvider {
|
||||||
|
|
||||||
override fun get(res: Int): String {
|
override fun get(res: Int): String {
|
||||||
return app.resources.getString(res)
|
return context.resources.getString(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,13 +17,10 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':utilities')
|
implementation project(':common')
|
||||||
|
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin
|
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
|
api 'androidx.room:room-runtime:' + versions.room
|
||||||
kapt 'androidx.room:room-compiler:' + versions.room
|
kapt 'androidx.room:room-compiler:' + versions.room
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@ ext.versions = [
|
||||||
okHttp : '3.12.0',
|
okHttp : '3.12.0',
|
||||||
rhino : '1.7.10',
|
rhino : '1.7.10',
|
||||||
|
|
||||||
dagger : '2.19',
|
|
||||||
kotlin : '1.3.10',
|
kotlin : '1.3.10',
|
||||||
coroutines : '1.0.1',
|
coroutines : '1.0.1',
|
||||||
|
koin : '1.0.2',
|
||||||
|
|
||||||
androidx : '1.0.0',
|
androidx : '1.0.0',
|
||||||
room : '2.0.0',
|
room : '2.0.0',
|
||||||
|
@ -30,6 +30,8 @@ ext.versions = [
|
||||||
mockito : '2.23.0',
|
mockito : '2.23.0',
|
||||||
mockitoKotlin : '2.0.0-RC1',
|
mockitoKotlin : '2.0.0-RC1',
|
||||||
truth : '0.42',
|
truth : '0.42',
|
||||||
|
|
||||||
androidxTestRunner: '1.1.0',
|
androidxTestRunner: '1.1.0',
|
||||||
androidxTest : '1.0.0',
|
androidxTest : '1.0.0',
|
||||||
|
archTesting : '2.0.0'
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':utilities')
|
implementation project(':common')
|
||||||
implementation project(':data')
|
implementation project(':data')
|
||||||
implementation project(':notifications')
|
implementation project(':notifications')
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@ dependencies {
|
||||||
api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines
|
api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:' + versions.coroutines
|
||||||
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + 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
|
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
|
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
||||||
|
|
||||||
testImplementation 'junit:junit:' + versions.junit
|
testImplementation 'junit:junit:' + versions.junit
|
||||||
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
||||||
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/**
|
||||||
* Designed and developed by Aidan Follestad (@afollestad)
|
* Designed and developed by Aidan Follestad (@afollestad)
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -13,19 +13,18 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.RealValidationManager
|
||||||
import com.afollestad.nocknock.engine.validation.ValidationManager;
|
import com.afollestad.nocknock.engine.validation.ValidationManager
|
||||||
import dagger.Binds;
|
import org.koin.dsl.module.module
|
||||||
import dagger.Module;
|
|
||||||
import javax.inject.Singleton;
|
const val ENGINE_MODULE = "engine"
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
@Module
|
val engineModule = module(ENGINE_MODULE) {
|
||||||
public abstract class EngineModule {
|
|
||||||
|
|
||||||
@Binds
|
single {
|
||||||
@Singleton
|
RealValidationManager(get(), get(), get(), get(), get(), get())
|
||||||
abstract ValidationManager provideValidationManager(RealValidationManager checkStatusManager);
|
} bind ValidationManager::class
|
||||||
}
|
}
|
|
@ -19,19 +19,22 @@ import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.ACTION_BOOT_COMPLETED
|
import android.content.Intent.ACTION_BOOT_COMPLETED
|
||||||
import com.afollestad.nocknock.utilities.ext.injector
|
import com.afollestad.nocknock.utilities.Qualifiers.IO_DISPATCHER
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import com.afollestad.nocknock.utilities.Qualifiers.MAIN_DISPATCHER
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.launch
|
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
|
import timber.log.Timber.d as log
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class BootReceiver : BroadcastReceiver() {
|
class BootReceiver : BroadcastReceiver(), KoinComponent {
|
||||||
|
|
||||||
@Inject lateinit var checkStatusManager: ValidationManager
|
private val validationManager by inject<ValidationManager>()
|
||||||
|
private val mainDispatcher by inject<CoroutineDispatcher>(name = MAIN_DISPATCHER)
|
||||||
|
private val ioDispatcher by inject<CoroutineDispatcher>(name = IO_DISPATCHER)
|
||||||
|
|
||||||
override fun onReceive(
|
override fun onReceive(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -42,12 +45,10 @@ class BootReceiver : BroadcastReceiver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
log("Received boot event! Let's go.")
|
log("Received boot event! Let's go.")
|
||||||
context.injector()
|
|
||||||
.injectInto(this)
|
|
||||||
|
|
||||||
val pendingResult = goAsync()
|
val pendingResult = goAsync()
|
||||||
GlobalScope.launch(Main) {
|
GlobalScope.launch(mainDispatcher) {
|
||||||
async(IO) { checkStatusManager.ensureScheduledChecks() }.await()
|
withContext(ioDispatcher) { validationManager.ensureScheduledChecks() }
|
||||||
pendingResult.resultCode = 0
|
pendingResult.resultCode = 0
|
||||||
pendingResult.finish()
|
pendingResult.finish()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import android.app.job.JobParameters
|
||||||
import android.app.job.JobService
|
import android.app.job.JobService
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.afollestad.nocknock.data.AppDatabase
|
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.Site
|
||||||
import com.afollestad.nocknock.data.model.Status
|
import com.afollestad.nocknock.data.model.Status
|
||||||
import com.afollestad.nocknock.data.model.Status.CHECKING
|
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.STATUS_CODE
|
||||||
import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH
|
import com.afollestad.nocknock.data.model.ValidationMode.TERM_SEARCH
|
||||||
import com.afollestad.nocknock.data.model.isPending
|
import com.afollestad.nocknock.data.model.isPending
|
||||||
import com.afollestad.nocknock.data.getSite
|
|
||||||
import com.afollestad.nocknock.data.updateSite
|
import com.afollestad.nocknock.data.updateSite
|
||||||
import com.afollestad.nocknock.engine.BuildConfig.APPLICATION_ID
|
import com.afollestad.nocknock.engine.BuildConfig.APPLICATION_ID
|
||||||
import com.afollestad.nocknock.notifications.NockNotificationManager
|
import com.afollestad.nocknock.notifications.NockNotificationManager
|
||||||
import com.afollestad.nocknock.utilities.ext.injector
|
|
||||||
import com.afollestad.nocknock.utilities.js.JavaScript
|
import com.afollestad.nocknock.utilities.js.JavaScript
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
@ -41,8 +40,8 @@ import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import javax.inject.Inject
|
|
||||||
import timber.log.Timber.d as log
|
import timber.log.Timber.d as log
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,12 +58,11 @@ class ValidationJob : JobService() {
|
||||||
const val KEY_SITE_ID = "site.id"
|
const val KEY_SITE_ID = "site.id"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject lateinit var database: AppDatabase
|
private val database by inject<AppDatabase>()
|
||||||
@Inject lateinit var checkStatusManager: ValidationManager
|
private val validaitonManager by inject<ValidationManager>()
|
||||||
@Inject lateinit var notificationManager: NockNotificationManager
|
private val notificationManager by inject<NockNotificationManager>()
|
||||||
|
|
||||||
override fun onStartJob(params: JobParameters): Boolean {
|
override fun onStartJob(params: JobParameters): Boolean {
|
||||||
injector().injectInto(this)
|
|
||||||
val siteId = params.extras.getLong(KEY_SITE_ID)
|
val siteId = params.extras.getLong(KEY_SITE_ID)
|
||||||
|
|
||||||
GlobalScope.launch(Main) {
|
GlobalScope.launch(Main) {
|
||||||
|
@ -84,7 +82,7 @@ class ValidationJob : JobService() {
|
||||||
|
|
||||||
val jobResult = async(IO) {
|
val jobResult = async(IO) {
|
||||||
updateStatus(site, CHECKING)
|
updateStatus(site, CHECKING)
|
||||||
val checkResult = checkStatusManager.performCheck(site)
|
val checkResult = validaitonManager.performCheck(site)
|
||||||
val resultModel = checkResult.model
|
val resultModel = checkResult.model
|
||||||
val resultResponse = checkResult.response
|
val resultResponse = checkResult.response
|
||||||
val result = resultModel.lastResult!!
|
val result = resultModel.lastResult!!
|
||||||
|
@ -144,7 +142,7 @@ class ValidationJob : JobService() {
|
||||||
notificationManager.postStatusNotification(jobResult)
|
notificationManager.postStatusNotification(jobResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkStatusManager.scheduleCheck(
|
validaitonManager.scheduleCheck(
|
||||||
site = jobResult,
|
site = jobResult,
|
||||||
fromFinishingJob = true
|
fromFinishingJob = true
|
||||||
)
|
)
|
||||||
|
|
|
@ -33,7 +33,6 @@ import okhttp3.Response
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||||
import javax.inject.Inject
|
|
||||||
import timber.log.Timber.d as log
|
import timber.log.Timber.d as log
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
|
@ -61,7 +60,7 @@ interface ValidationManager {
|
||||||
suspend fun performCheck(site: Site): CheckResult
|
suspend fun performCheck(site: Site): CheckResult
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealValidationManager @Inject constructor(
|
class RealValidationManager(
|
||||||
private val jobScheduler: JobScheduler,
|
private val jobScheduler: JobScheduler,
|
||||||
private val okHttpClient: OkHttpClient,
|
private val okHttpClient: OkHttpClient,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
|
|
|
@ -14,7 +14,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':utilities')
|
implementation project(':common')
|
||||||
|
|
||||||
api 'androidx.appcompat:appcompat:' + versions.androidx
|
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-core:' + versions.coroutines
|
||||||
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines
|
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:' + versions.coroutines
|
||||||
|
|
||||||
implementation 'com.google.dagger:dagger:' + versions.dagger
|
implementation 'org.koin:koin-android:' + versions.koin
|
||||||
kapt 'com.google.dagger:dagger-compiler:' + versions.dagger
|
|
||||||
|
|
||||||
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
implementation 'com.jakewharton.timber:timber:' + versions.timber
|
||||||
|
|
||||||
testImplementation 'junit:junit:' + versions.junit
|
testImplementation 'junit:junit:' + versions.junit
|
||||||
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
testImplementation 'org.mockito:mockito-core:' + versions.mockito
|
||||||
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:' + versions.mockitoKotlin
|
||||||
|
|
|
@ -26,8 +26,6 @@ import com.afollestad.nocknock.utilities.providers.NotificationChannelProvider
|
||||||
import com.afollestad.nocknock.utilities.providers.NotificationProvider
|
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.RealIntentProvider.Companion.BASE_NOTIFICATION_REQUEST_CODE
|
||||||
import com.afollestad.nocknock.utilities.providers.StringProvider
|
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
|
import timber.log.Timber.d as log
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
|
@ -45,8 +43,8 @@ interface NockNotificationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad) */
|
/** @author Aidan Follestad (@afollestad) */
|
||||||
class RealNockNotificationManager @Inject constructor(
|
class RealNockNotificationManager(
|
||||||
@AppIconRes private val appIconRes: Int,
|
private val appIconRes: Int,
|
||||||
private val stockManager: NotificationManager,
|
private val stockManager: NotificationManager,
|
||||||
private val bitmapProvider: BitmapProvider,
|
private val bitmapProvider: BitmapProvider,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -13,10 +13,28 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.afollestad.nocknock.utilities
|
package com.afollestad.nocknock.notifications
|
||||||
|
|
||||||
/** @author Aidan Follestad (@afollestad)*/
|
import com.afollestad.nocknock.notifications.Qualifiers.APP_ICON_RES
|
||||||
interface Injector {
|
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
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
include ':app', ':engine', ':notifications', ':data', ':utilities', ':viewcomponents'
|
include ':app', ':engine', ':notifications', ':data', ':common', ':viewcomponents'
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -15,16 +15,13 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':utilities')
|
implementation project(':common')
|
||||||
implementation project(':data')
|
implementation project(':data')
|
||||||
|
|
||||||
implementation 'androidx.appcompat:appcompat:' + versions.androidx
|
implementation 'androidx.appcompat:appcompat:' + versions.androidx
|
||||||
api 'androidx.lifecycle:lifecycle-extensions:' + versions.lifecycle
|
api 'androidx.lifecycle:lifecycle-extensions:' + versions.lifecycle
|
||||||
|
|
||||||
api 'com.squareup.okhttp3:okhttp:' + versions.okHttp
|
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'
|
apply from: '../spotless.gradle'
|
|
@ -46,7 +46,14 @@ class LoadingIndicatorFrame(
|
||||||
isFocusable = true
|
isFocusable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setIsLoading(isLoading: Boolean) {
|
fun observe(
|
||||||
|
owner: LifecycleOwner,
|
||||||
|
data: LiveData<Boolean>
|
||||||
|
) = data.observe(owner, Observer {
|
||||||
|
setIsLoading(it)
|
||||||
|
})
|
||||||
|
|
||||||
|
private fun setIsLoading(isLoading: Boolean) {
|
||||||
delayHandler.removeCallbacks(showRunnable)
|
delayHandler.removeCallbacks(showRunnable)
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
delayHandler.postDelayed(showRunnable, SHOW_DELAY_MS)
|
delayHandler.postDelayed(showRunnable, SHOW_DELAY_MS)
|
||||||
|
@ -54,11 +61,4 @@ class LoadingIndicatorFrame(
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun observe(
|
|
||||||
owner: LifecycleOwner,
|
|
||||||
data: LiveData<Boolean>
|
|
||||||
) = data.observe(owner, Observer {
|
|
||||||
setIsLoading(it)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue