From 48acc64ee3512b3cc24dbedcba5a6a3798d60821 Mon Sep 17 00:00:00 2001
From: Yahor Berdnikau <egorr.berd@gmail.com>
Date: Fri, 3 Aug 2018 21:50:21 +0200
Subject: [PATCH 1/2] Migrate Koin to 1.0.0-beta3 version.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
---
 dependencies.gradle                           |  4 +-
 .../api/subsonic/di/SubsonicApiModule.kt      |  6 +--
 .../kotlin/org/moire/ultrasonic/app/UApp.kt   | 22 ++++++----
 .../di/AppPermanentStorageModule.kt           | 10 +++++
 .../moire/ultrasonic/di/BaseNetworkModule.kt  |  6 +--
 .../org/moire/ultrasonic/di/DiProperties.kt   |  5 +++
 .../moire/ultrasonic/di/DirectoriesModule.kt  |  6 +--
 .../moire/ultrasonic/di/FeatureFlagsModule.kt |  9 ++--
 .../moire/ultrasonic/di/MusicServiceModule.kt | 42 +++++++++----------
 .../ultrasonic/service/MusicServiceFactory.kt |  4 +-
 10 files changed, 65 insertions(+), 49 deletions(-)
 create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
 create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt

diff --git a/dependencies.gradle b/dependencies.gradle
index a9ee8ed2..c803fd2e 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -20,7 +20,7 @@ ext.versions = [
         okhttp               : "3.10.0",
         semver               : "1.0.0",
         twitterSerial        : "0.1.6",
-        koin                 : "0.9.3",
+        koin                 : "1.0.0-beta-3",
         picasso              : "2.71828",
 
         junit                : "4.12",
@@ -57,6 +57,7 @@ ext.other = [
         semver             : "net.swiftzer.semver:semver:$versions.semver",
         twitterSerial      : "com.twitter.serial:serial:$versions.twitterSerial",
         koinCore           : "org.koin:koin-core:$versions.koin",
+        koinJava           : "org.koin:koin-java:$versions.koin",
         koinAndroid        : "org.koin:koin-android:$versions.koin",
         picasso            : "com.squareup.picasso:picasso:$versions.picasso",
 ]
@@ -73,4 +74,5 @@ ext.testing = [
         apacheCodecs  : "commons-codec:commons-codec:$versions.apacheCodecs",
         testRunner    : "com.android.support.test:runner:$versions.testRunner",
         robolectric   : "org.robolectric:robolectric:$versions.robolectric",
+        koinTest      : "org.koin:koin-test:$versions.koin"
 ]
diff --git a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/di/SubsonicApiModule.kt b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/di/SubsonicApiModule.kt
index 200b6328..f5820cb7 100644
--- a/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/di/SubsonicApiModule.kt
+++ b/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/di/SubsonicApiModule.kt
@@ -1,10 +1,10 @@
 package org.moire.ultrasonic.api.subsonic.di
 
-import org.koin.dsl.context.Context
+import org.koin.dsl.context.ModuleDefinition
 import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient
 
 const val SUBSONIC_API_CLIENT_CONTEXT = "SubsonicApiClientContext"
 
-fun Context.subsonicApiModule() = context(SUBSONIC_API_CLIENT_CONTEXT) {
-    bean { return@bean SubsonicAPIClient(get(), get()) }
+fun ModuleDefinition.subsonicApiModule() = module(SUBSONIC_API_CLIENT_CONTEXT) {
+    single { SubsonicAPIClient(get(), get()) }
 }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
index 8eb735b6..89b92ff0 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
@@ -3,25 +3,31 @@ package org.moire.ultrasonic.app
 import android.app.Application
 import org.koin.android.ext.android.get
 import org.koin.android.ext.android.startKoin
+import org.moire.ultrasonic.di.DiProperties
+import org.moire.ultrasonic.di.appPermanentStorage
 import org.moire.ultrasonic.di.baseNetworkModule
 import org.moire.ultrasonic.di.directoriesModule
 import org.moire.ultrasonic.di.featureFlagsModule
 import org.moire.ultrasonic.di.musicServiceModule
 import org.moire.ultrasonic.featureflags.FeatureStorage
 import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader
-import org.moire.ultrasonic.util.Util
 
 class UApp : Application() {
     override fun onCreate() {
         super.onCreate()
 
-        val sharedPreferences = Util.getPreferences(this)
-        startKoin(this, listOf(
-            directoriesModule,
-            baseNetworkModule,
-            featureFlagsModule(this),
-            musicServiceModule(sharedPreferences, this)
-        ))
+        startKoin(this,
+            listOf(
+                directoriesModule,
+                appPermanentStorage,
+                baseNetworkModule,
+                featureFlagsModule,
+                musicServiceModule
+            ),
+            extraProperties = mapOf(
+                DiProperties.APP_CONTEXT to applicationContext
+            )
+        )
     }
 
     /**
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
new file mode 100644
index 00000000..7a4346fc
--- /dev/null
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
@@ -0,0 +1,10 @@
+package org.moire.ultrasonic.di
+
+import org.koin.dsl.module.module
+import org.moire.ultrasonic.util.Util
+
+const val SP_NAME = "Default_SP"
+
+val appPermanentStorage = module {
+    single(name = SP_NAME) { Util.getPreferences(getProperty(DiProperties.APP_CONTEXT)) }
+}
\ No newline at end of file
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/BaseNetworkModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/BaseNetworkModule.kt
index 0455ff53..7bf4ee73 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/BaseNetworkModule.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/BaseNetworkModule.kt
@@ -1,11 +1,11 @@
 package org.moire.ultrasonic.di
 
 import okhttp3.OkHttpClient
-import org.koin.dsl.module.applicationContext
+import org.koin.dsl.module.module
 
 /**
  * Provides base network dependencies.
  */
-val baseNetworkModule = applicationContext {
-    bean { OkHttpClient.Builder().build() }
+val baseNetworkModule = module {
+    single { OkHttpClient.Builder().build() }
 }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt
new file mode 100644
index 00000000..70d5860b
--- /dev/null
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt
@@ -0,0 +1,5 @@
+package org.moire.ultrasonic.di
+
+object DiProperties {
+    const val APP_CONTEXT = "app_context"
+}
\ No newline at end of file
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DirectoriesModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DirectoriesModule.kt
index ddbe21f0..577568ec 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DirectoriesModule.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DirectoriesModule.kt
@@ -1,9 +1,9 @@
 package org.moire.ultrasonic.di
 
-import org.koin.dsl.module.applicationContext
+import org.koin.dsl.module.module
 import org.moire.ultrasonic.cache.AndroidDirectories
 import org.moire.ultrasonic.cache.Directories
 
-val directoriesModule = applicationContext {
-    bean { AndroidDirectories(get()) } bind Directories::class
+val directoriesModule = module {
+    single { AndroidDirectories(get()) } bind Directories::class
 }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt
index 81a1b09f..5d8d484b 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt
@@ -1,11 +1,8 @@
 package org.moire.ultrasonic.di
 
-import android.content.Context
-import org.koin.dsl.module.applicationContext
+import org.koin.dsl.module.module
 import org.moire.ultrasonic.featureflags.FeatureStorage
 
-fun featureFlagsModule(
-    context: Context
-) = applicationContext {
-    factory { FeatureStorage(context) }
+val featureFlagsModule = module {
+    factory { FeatureStorage(getProperty(DiProperties.APP_CONTEXT)) }
 }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MusicServiceModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MusicServiceModule.kt
index 7809ff1b..661079a3 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MusicServiceModule.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MusicServiceModule.kt
@@ -1,10 +1,9 @@
 @file:JvmName("MusicServiceModule")
 package org.moire.ultrasonic.di
 
-import android.content.Context
 import android.content.SharedPreferences
 import android.util.Log
-import org.koin.dsl.module.applicationContext
+import org.koin.dsl.module.module
 import org.moire.ultrasonic.BuildConfig
 import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient
 import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
@@ -26,40 +25,38 @@ private const val DEFAULT_SERVER_INSTANCE = 1
 private const val UNKNOWN_SERVER_URL = "not-exists"
 private const val LOG_TAG = "MusicServiceModule"
 
-fun musicServiceModule(
-    sp: SharedPreferences,
-    context: Context
-) = applicationContext {
-    context(MUSIC_SERVICE_CONTEXT) {
+val musicServiceModule = module(MUSIC_SERVICE_CONTEXT) {
         subsonicApiModule()
 
-        bean(name = "ServerInstance") {
-            return@bean sp.getInt(
+        single(name = "ServerInstance") {
+            return@single get<SharedPreferences>(SP_NAME).getInt(
                 Constants.PREFERENCES_KEY_SERVER_INSTANCE,
                 DEFAULT_SERVER_INSTANCE
             )
         }
 
-        bean(name = "ServerID") {
+        single(name = "ServerID") {
             val serverInstance = get<Int>(name = "ServerInstance")
+            val sp: SharedPreferences = get(SP_NAME)
             val serverUrl = sp.getString(
                 Constants.PREFERENCES_KEY_SERVER_URL + serverInstance,
                 null
             )
-            return@bean if (serverUrl == null) {
+            return@single if (serverUrl == null) {
                 UNKNOWN_SERVER_URL
             } else {
                 abs("$serverUrl$serverInstance".hashCode()).toString()
             }
         }
 
-        bean {
+        single {
             val serverId = get<String>(name = "ServerID")
-            return@bean PermanentFileStorage(get(), serverId, BuildConfig.DEBUG)
+            return@single PermanentFileStorage(get(), serverId, BuildConfig.DEBUG)
         }
 
-        bean {
+        single {
             val instance = get<Int>(name = "ServerInstance")
+            val sp: SharedPreferences = get(SP_NAME)
             val serverUrl = sp.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null)
             val username = sp.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null)
             val password = sp.getString(Constants.PREFERENCES_KEY_PASSWORD + instance, null)
@@ -77,7 +74,7 @@ fun musicServiceModule(
                 password == null
             ) {
                 Log.i(LOG_TAG, "Server credentials is not available")
-                return@bean SubsonicClientConfiguration(
+                return@single SubsonicClientConfiguration(
                     baseUrl = "http://localhost",
                     username = "",
                     password = "",
@@ -90,7 +87,7 @@ fun musicServiceModule(
                     debug = BuildConfig.DEBUG
                 )
             } else {
-                return@bean SubsonicClientConfiguration(
+                return@single SubsonicClientConfiguration(
                     baseUrl = serverUrl,
                     username = username,
                     password = password,
@@ -105,16 +102,15 @@ fun musicServiceModule(
             }
         }
 
-        bean { return@bean SubsonicAPIClient(get()) }
+        single { SubsonicAPIClient(get()) }
 
-        bean<MusicService>(name = ONLINE_MUSIC_SERVICE) {
-            return@bean CachedMusicService(RESTMusicService(get(), get()))
+        single<MusicService>(name = ONLINE_MUSIC_SERVICE) {
+            CachedMusicService(RESTMusicService(get(), get()))
         }
 
-        bean<MusicService>(name = OFFLINE_MUSIC_SERVICE) {
-            return@bean OfflineMusicService(get(), get())
+        single<MusicService>(name = OFFLINE_MUSIC_SERVICE) {
+            OfflineMusicService(get(), get())
         }
 
-        bean { return@bean SubsonicImageLoader(context, get()) }
+        single { SubsonicImageLoader(getProperty(DiProperties.APP_CONTEXT), get()) }
     }
-}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt
index 5fbb393e..fa10ec1e 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MusicServiceFactory.kt
@@ -21,7 +21,7 @@ package org.moire.ultrasonic.service
 import android.content.Context
 import org.koin.standalone.KoinComponent
 import org.koin.standalone.get
-import org.koin.standalone.releaseContext
+import org.koin.standalone.release
 import org.moire.ultrasonic.cache.Directories
 import org.moire.ultrasonic.di.MUSIC_SERVICE_CONTEXT
 import org.moire.ultrasonic.di.OFFLINE_MUSIC_SERVICE
@@ -45,7 +45,7 @@ object MusicServiceFactory : KoinComponent {
      */
     @JvmStatic
     fun resetMusicService() {
-        releaseContext(MUSIC_SERVICE_CONTEXT)
+        release(MUSIC_SERVICE_CONTEXT)
     }
 
     @JvmStatic

From c2924df25f417692994bbfbf5d01a9e1f1891b9a Mon Sep 17 00:00:00 2001
From: Yahor Berdnikau <egorr.berd@gmail.com>
Date: Fri, 3 Aug 2018 22:08:30 +0200
Subject: [PATCH 2/2] Use Koin java module.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
---
 ultrasonic/build.gradle                         |  1 +
 .../activity/SubsonicTabActivity.java           |  8 +++++---
 .../ultrasonic/fragment/SettingsFragment.java   |  4 ++--
 .../kotlin/org/moire/ultrasonic/app/UApp.kt     | 17 -----------------
 .../ultrasonic/di/AppPermanentStorageModule.kt  |  2 +-
 .../org/moire/ultrasonic/di/DiProperties.kt     |  2 +-
 6 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle
index 6697dd4e..e26e6631 100644
--- a/ultrasonic/build.gradle
+++ b/ultrasonic/build.gradle
@@ -63,6 +63,7 @@ dependencies {
 
     implementation other.kotlinStdlib
     implementation other.koinAndroid
+    implementation other.koinJava
 
     testImplementation other.kotlinReflect
     testImplementation testing.junit
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java
index be2783af..9423d117 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java
@@ -38,15 +38,17 @@ import android.view.View.OnTouchListener;
 import android.widget.*;
 import net.simonvt.menudrawer.MenuDrawer;
 import net.simonvt.menudrawer.Position;
+import org.koin.java.standalone.KoinJavaComponent;
 import org.moire.ultrasonic.R;
-import org.moire.ultrasonic.app.UApp;
 import org.moire.ultrasonic.domain.MusicDirectory;
 import org.moire.ultrasonic.domain.MusicDirectory.Entry;
 import org.moire.ultrasonic.domain.PlayerState;
 import org.moire.ultrasonic.domain.Share;
 import org.moire.ultrasonic.featureflags.Feature;
+import org.moire.ultrasonic.featureflags.FeatureStorage;
 import org.moire.ultrasonic.service.*;
 import org.moire.ultrasonic.subsonic.SubsonicImageLoaderProxy;
+import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader;
 import org.moire.ultrasonic.util.*;
 
 import java.io.File;
@@ -808,12 +810,12 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
                     Util.getImageLoaderConcurrency(this)
             );
 
-            boolean isNewImageLoaderEnabled = ((UApp) getApplication()).getFeaturesStorage()
+            boolean isNewImageLoaderEnabled = KoinJavaComponent.get(FeatureStorage.class)
                     .isFeatureEnabled(Feature.NEW_IMAGE_DOWNLOADER);
             if (isNewImageLoaderEnabled) {
                 IMAGE_LOADER = new SubsonicImageLoaderProxy(
                         legacyImageLoader,
-                        ((UApp) getApplication()).getSubsonicImageLoader()
+                        KoinJavaComponent.get(SubsonicImageLoader.class)
                 );
             } else {
                 IMAGE_LOADER = legacyImageLoader;
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java
index 98feabc8..4dc2fe6f 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java
@@ -9,10 +9,10 @@ import android.provider.SearchRecentSuggestions;
 import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.View;
+import org.koin.java.standalone.KoinJavaComponent;
 import org.moire.ultrasonic.R;
 import org.moire.ultrasonic.activity.ServerSettingsActivity;
 import org.moire.ultrasonic.activity.SubsonicTabActivity;
-import org.moire.ultrasonic.app.UApp;
 import org.moire.ultrasonic.featureflags.Feature;
 import org.moire.ultrasonic.featureflags.FeatureStorage;
 import org.moire.ultrasonic.provider.SearchSuggestionProvider;
@@ -175,7 +175,7 @@ public class SettingsFragment extends PreferenceFragment
         CheckBoxPreference ffImageLoader = (CheckBoxPreference) findPreference(
                 Constants.PREFERENCES_KEY_FF_IMAGE_LOADER);
 
-        final FeatureStorage featureStorage = ((UApp) getActivity().getApplication()).getFeaturesStorage();
+        final FeatureStorage featureStorage = KoinJavaComponent.get(FeatureStorage.class);
         if (ffImageLoader != null) {
             ffImageLoader.setChecked(featureStorage.isFeatureEnabled(Feature.NEW_IMAGE_DOWNLOADER));
             ffImageLoader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
index 89b92ff0..0f2bdc5f 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
@@ -1,7 +1,6 @@
 package org.moire.ultrasonic.app
 
 import android.app.Application
-import org.koin.android.ext.android.get
 import org.koin.android.ext.android.startKoin
 import org.moire.ultrasonic.di.DiProperties
 import org.moire.ultrasonic.di.appPermanentStorage
@@ -9,8 +8,6 @@ import org.moire.ultrasonic.di.baseNetworkModule
 import org.moire.ultrasonic.di.directoriesModule
 import org.moire.ultrasonic.di.featureFlagsModule
 import org.moire.ultrasonic.di.musicServiceModule
-import org.moire.ultrasonic.featureflags.FeatureStorage
-import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader
 
 class UApp : Application() {
     override fun onCreate() {
@@ -29,18 +26,4 @@ class UApp : Application() {
             )
         )
     }
-
-    /**
-     * Temporary method to get subsonic image loader from java code.
-     */
-    fun getSubsonicImageLoader(): SubsonicImageLoader {
-        return get()
-    }
-
-    /**
-     * Temporary method to get features storage.
-     */
-    fun getFeaturesStorage(): FeatureStorage {
-        return get()
-    }
 }
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
index 7a4346fc..fb9c9fb9 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt
@@ -7,4 +7,4 @@ const val SP_NAME = "Default_SP"
 
 val appPermanentStorage = module {
     single(name = SP_NAME) { Util.getPreferences(getProperty(DiProperties.APP_CONTEXT)) }
-}
\ No newline at end of file
+}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt
index 70d5860b..ac4748be 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/DiProperties.kt
@@ -2,4 +2,4 @@ package org.moire.ultrasonic.di
 
 object DiProperties {
     const val APP_CONTEXT = "app_context"
-}
\ No newline at end of file
+}