Migrate from kodein to koin

This commit is contained in:
ligi 2020-03-01 02:13:52 +01:00
parent 2831f60c30
commit 5fb07e0508
No known key found for this signature in database
GPG key ID: 8E81894010ABF23D
38 changed files with 223 additions and 207 deletions

View file

@ -112,8 +112,7 @@ dependencies {
implementation 'org.permissionsdispatcher:permissionsdispatcher:4.6.0' implementation 'org.permissionsdispatcher:permissionsdispatcher:4.6.0'
kapt 'org.permissionsdispatcher:permissionsdispatcher-processor:4.6.0' kapt 'org.permissionsdispatcher:permissionsdispatcher-processor:4.6.0'
implementation 'com.github.salomonbrys.kodein:kodein:4.1.0' implementation "org.koin:koin-android:2.1.1"
compileOnly 'org.glassfish:javax.annotation:3.1.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

View file

@ -1,10 +1,8 @@
package org.ligi.passandroid package org.ligi.passandroid
import com.github.salomonbrys.kodein.Kodein
import com.github.salomonbrys.kodein.bind
import com.github.salomonbrys.kodein.instance
import com.github.salomonbrys.kodein.singleton
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.koin.core.module.Module
import org.koin.dsl.module
import org.ligi.passandroid.injections.FixedPassListPassStore import org.ligi.passandroid.injections.FixedPassListPassStore
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.Settings import org.ligi.passandroid.model.Settings
@ -20,26 +18,25 @@ import java.util.*
class TestApp : App() { class TestApp : App() {
override fun createKodein() = Kodein.Module { override fun createKoin(): Module {
bind<PassStore>() with singleton {
FixedPassListPassStore(emptyList()) return module {
single { passStore as PassStore }
single { settings }
single { tracker }
single { mock(EventBus::class.java) }
} }
bind<Settings>() with singleton {
mock(Settings::class.java).apply {
`when`(getSortOrder()).thenReturn(PassSortOrder.DATE_ASC)
`when`(getPassesDir()).thenReturn(File(""))
`when`(doTraceDroidEmailSend()).thenReturn(false)
}
}
bind<Tracker>(overrides = true) with singleton { mock(Tracker::class.java) }
bind<EventBus>() with singleton { mock(EventBus::class.java) }
} }
companion object { companion object {
val tracker = mock(Tracker::class.java)
fun passStore(): PassStore = kodein.instance() val passStore = FixedPassListPassStore(emptyList())
fun settings(): Settings = kodein.instance() val settings = mock(Settings::class.java).apply {
`when`(getSortOrder()).thenReturn(PassSortOrder.DATE_ASC)
`when`(getPassesDir()).thenReturn(File(""))
`when`(doTraceDroidEmailSend()).thenReturn(false)
}
fun populatePassStoreWithSinglePass() { fun populatePassStoreWithSinglePass() {
@ -51,13 +48,13 @@ class TestApp : App() {
fixedPassListPassStore().setList(passList) fixedPassListPassStore().setList(passList)
passStore().classifier.moveToTopic(pass, "test") passStore.classifier.moveToTopic(pass, "test")
} }
fun emptyPassStore() { fun emptyPassStore() {
fixedPassListPassStore().setList(emptyList()) fixedPassListPassStore().setList(emptyList())
} }
private fun fixedPassListPassStore() = passStore() as FixedPassListPassStore private fun fixedPassListPassStore() = passStore as FixedPassListPassStore
} }
} }

View file

@ -33,7 +33,7 @@ class TheAddToCalendar {
fun testIfWeOnlyHaveCalendarStartDate() { fun testIfWeOnlyHaveCalendarStartDate() {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
TestApp.passStore().currentPass!!.calendarTimespan = PassImpl.TimeSpan(time) TestApp.passStore.currentPass!!.calendarTimespan = PassImpl.TimeSpan(time)
rule.launchActivity() rule.launchActivity()
intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null)) intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null))
@ -44,7 +44,7 @@ class TheAddToCalendar {
hasType("vnd.android.cursor.item/event"), hasType("vnd.android.cursor.item/event"),
hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000),
hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.plusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.plusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000),
hasExtra("title", TestApp.passStore().currentPass!!.description) hasExtra("title", TestApp.passStore.currentPass!!.description)
)) ))
} }
@ -52,7 +52,7 @@ class TheAddToCalendar {
fun testIfWeOnlyHaveCalendarEndDate() { fun testIfWeOnlyHaveCalendarEndDate() {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
TestApp.passStore().currentPass!!.calendarTimespan = PassImpl.TimeSpan(to = time) TestApp.passStore.currentPass!!.calendarTimespan = PassImpl.TimeSpan(to = time)
rule.launchActivity() rule.launchActivity()
intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null)) intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null))
@ -63,7 +63,7 @@ class TheAddToCalendar {
hasType("vnd.android.cursor.item/event"), hasType("vnd.android.cursor.item/event"),
hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.minusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.minusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000),
hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.toEpochSecond() * 1000),
hasExtra("title", TestApp.passStore().currentPass!!.description) hasExtra("title", TestApp.passStore.currentPass!!.description)
)) ))
} }
@ -71,7 +71,7 @@ class TheAddToCalendar {
fun testIfWeOnlyHaveCalendarStartAndEndDate() { fun testIfWeOnlyHaveCalendarStartAndEndDate() {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
TestApp.passStore().currentPass!!.calendarTimespan = PassImpl.TimeSpan(time, time2) TestApp.passStore.currentPass!!.calendarTimespan = PassImpl.TimeSpan(time, time2)
rule.launchActivity() rule.launchActivity()
intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null)) intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null))
@ -82,7 +82,7 @@ class TheAddToCalendar {
hasType("vnd.android.cursor.item/event"), hasType("vnd.android.cursor.item/event"),
hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000),
hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time2.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time2.toEpochSecond() * 1000),
hasExtra("title", TestApp.passStore().currentPass!!.description) hasExtra("title", TestApp.passStore.currentPass!!.description)
)) ))
} }
@ -91,7 +91,7 @@ class TheAddToCalendar {
fun testIfWeOnlyHaveExpirationDate() { fun testIfWeOnlyHaveExpirationDate() {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
(TestApp.passStore().currentPass as PassImpl).validTimespans = listOf(PassImpl.TimeSpan(time)) (TestApp.passStore.currentPass as PassImpl).validTimespans = listOf(PassImpl.TimeSpan(time))
rule.launchActivity() rule.launchActivity()
intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null)) intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null))
@ -105,7 +105,7 @@ class TheAddToCalendar {
hasType("vnd.android.cursor.item/event"), hasType("vnd.android.cursor.item/event"),
hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000),
hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.plusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.plusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000),
hasExtra("title", TestApp.passStore().currentPass!!.description) hasExtra("title", TestApp.passStore.currentPass!!.description)
)) ))
} }
@ -113,7 +113,7 @@ class TheAddToCalendar {
fun testIfWeOnlyHaveExpirationEndDate() { fun testIfWeOnlyHaveExpirationEndDate() {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
(TestApp.passStore().currentPass as PassImpl).validTimespans = listOf(PassImpl.TimeSpan(to = time)) (TestApp.passStore.currentPass as PassImpl).validTimespans = listOf(PassImpl.TimeSpan(to = time))
rule.launchActivity() rule.launchActivity()
intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null)) intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null))
@ -127,7 +127,7 @@ class TheAddToCalendar {
hasType("vnd.android.cursor.item/event"), hasType("vnd.android.cursor.item/event"),
hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.minusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.minusHours(DEFAULT_EVENT_LENGTH_IN_HOURS).toEpochSecond() * 1000),
hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time.toEpochSecond() * 1000),
hasExtra("title", TestApp.passStore().currentPass!!.description) hasExtra("title", TestApp.passStore.currentPass!!.description)
)) ))
} }
@ -135,7 +135,7 @@ class TheAddToCalendar {
fun testIfWeOnlyHaveExpirationStartAndEndDate() { fun testIfWeOnlyHaveExpirationStartAndEndDate() {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
(TestApp.passStore().currentPass as PassImpl).validTimespans = listOf(PassImpl.TimeSpan(time, time2)) (TestApp.passStore.currentPass as PassImpl).validTimespans = listOf(PassImpl.TimeSpan(time, time2))
rule.launchActivity() rule.launchActivity()
intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null)) intending(hasType("vnd.android.cursor.item/event")).respondWith(Instrumentation.ActivityResult(RESULT_CANCELED, null))
@ -149,7 +149,7 @@ class TheAddToCalendar {
hasType("vnd.android.cursor.item/event"), hasType("vnd.android.cursor.item/event"),
hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, time.toEpochSecond() * 1000),
hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time2.toEpochSecond() * 1000), hasExtra(CalendarContract.EXTRA_EVENT_END_TIME, time2.toEpochSecond() * 1000),
hasExtra("title", TestApp.passStore().currentPass!!.description) hasExtra("title", TestApp.passStore.currentPass!!.description)
)) ))
} }

View file

@ -10,7 +10,6 @@ import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress import androidx.test.filters.SdkSuppress
import com.github.salomonbrys.kodein.instance
import com.linkedin.android.testbutler.TestButler import com.linkedin.android.testbutler.TestButler
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
@ -28,7 +27,7 @@ class TheBarCodeEditing {
@get:Rule @get:Rule
val rule = TruleskActivityRule(PassEditActivity::class.java, false) val rule = TruleskActivityRule(PassEditActivity::class.java, false)
val passStore: PassStore = App.kodein.instance() val passStore: PassStore = TestApp.passStore
private lateinit var currentPass: PassImpl private lateinit var currentPass: PassImpl

View file

@ -20,14 +20,14 @@ class TheCondensedPassViewMode {
@get:Rule @get:Rule
var rule = TruleskActivityRule(PassListActivity::class.java, false) { var rule = TruleskActivityRule(PassListActivity::class.java, false) {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
val currentPass = TestApp.passStore().currentPass as PassImpl val currentPass = TestApp.passStore.currentPass as PassImpl
currentPass.calendarTimespan = PassImpl.TimeSpan(ZonedDateTime.of(2016, 11, 23, 20, 42, 42, 5, ZoneId.systemDefault())) currentPass.calendarTimespan = PassImpl.TimeSpan(ZonedDateTime.of(2016, 11, 23, 20, 42, 42, 5, ZoneId.systemDefault()))
currentPass.fields = mutableListOf(PassField("textprobe", "bar", "yo", false)) currentPass.fields = mutableListOf(PassField("textprobe", "bar", "yo", false))
} }
@Test @Test
fun testDateShowsForCondensedOff() { fun testDateShowsForCondensedOff() {
`when`(TestApp.settings().isCondensedModeEnabled()).thenReturn(false) `when`(TestApp.settings.isCondensedModeEnabled()).thenReturn(false)
rule.launchActivity() rule.launchActivity()
@ -41,7 +41,7 @@ class TheCondensedPassViewMode {
@Test @Test
fun testFieldShowsForCondensedOn() { fun testFieldShowsForCondensedOn() {
`when`(TestApp.settings().isCondensedModeEnabled()).thenReturn(true) `when`(TestApp.settings.isCondensedModeEnabled()).thenReturn(true)
rule.launchActivity() rule.launchActivity()

View file

@ -18,7 +18,7 @@ class TheFieldListEditFragment {
@get:Rule @get:Rule
val rule = TruleskIntentRule(PassEditActivity::class.java) { val rule = TruleskIntentRule(PassEditActivity::class.java) {
TestApp.passStore().currentPass = PassImpl(UUID.randomUUID().toString()).apply { TestApp.passStore.currentPass = PassImpl(UUID.randomUUID().toString()).apply {
fields = arrayListOf(field) fields = arrayListOf(field)
} }
} }

View file

@ -2,11 +2,11 @@ package org.ligi.passandroid
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.widget.ImageView
import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import android.widget.ImageView
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -68,7 +68,7 @@ class TheFullscreenBarcodeActivity {
val pass = PassImpl(UUID.randomUUID().toString()) val pass = PassImpl(UUID.randomUUID().toString())
pass.barCode = BarCode(format, BARCODE_MESSAGE) pass.barCode = BarCode(format, BARCODE_MESSAGE)
TestApp.passStore().currentPass = pass TestApp.passStore.currentPass = pass
rule.launchActivity(null) rule.launchActivity(null)
onView(withId(R.id.fullscreen_barcode)).check(matches(isDisplayed())) onView(withId(R.id.fullscreen_barcode)).check(matches(isDisplayed()))

View file

@ -25,7 +25,7 @@ import org.ligi.trulesk.TruleskIntentRule
@TargetApi(14) @TargetApi(14)
class ThePassEditActivity { class ThePassEditActivity {
val passStore = TestApp.passStore() val passStore = TestApp.passStore
@get:Rule @get:Rule
var rule = TruleskIntentRule(PassEditActivity::class.java) { var rule = TruleskIntentRule(PassEditActivity::class.java) {

View file

@ -9,7 +9,6 @@ import androidx.test.espresso.matcher.ViewMatchers.*
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.ligi.passandroid.App.Companion.passStore
import org.ligi.passandroid.ui.PassListActivity import org.ligi.passandroid.ui.PassListActivity
import org.ligi.passandroid.ui.PassListFragment import org.ligi.passandroid.ui.PassListFragment
import org.ligi.trulesk.TruleskIntentRule import org.ligi.trulesk.TruleskIntentRule
@ -29,7 +28,7 @@ class ThePassListSwiping {
onView(withText(R.string.topic_trash)).perform(click()) onView(withText(R.string.topic_trash)).perform(click())
assertThat(passStore.classifier.getTopics()).containsExactly(rule.activity.getString(R.string.topic_trash)) assertThat(TestApp.passStore.classifier.getTopics()).containsExactly(rule.activity.getString(R.string.topic_trash))
} }
@ -39,7 +38,7 @@ class ThePassListSwiping {
onView(withText(R.string.topic_archive)).perform(click()) onView(withText(R.string.topic_archive)).perform(click())
assertThat(passStore.classifier.getTopics()).containsExactly(rule.activity.getString(R.string.topic_archive)) assertThat(TestApp.passStore.classifier.getTopics()).containsExactly(rule.activity.getString(R.string.topic_archive))
} }
@Test @Test
@ -51,7 +50,7 @@ class ThePassListSwiping {
onView(withText(android.R.string.ok)).perform(click()) onView(withText(android.R.string.ok)).perform(click())
assertThat(passStore.classifier.getTopics()).containsExactly(CUSTOM_PROBE) assertThat(TestApp.passStore.classifier.getTopics()).containsExactly(CUSTOM_PROBE)
} }

View file

@ -22,7 +22,7 @@ import java.util.*
@TargetApi(14) @TargetApi(14)
class ThePassViewActivity { class ThePassViewActivity {
private fun getActPass() = TestApp.passStore().currentPass as PassImpl private fun getActPass() = TestApp.passStore.currentPass as PassImpl
@get:Rule @get:Rule
var rule = TruleskActivityRule(PassViewActivity::class.java, false) var rule = TruleskActivityRule(PassViewActivity::class.java, false)

View file

@ -18,7 +18,7 @@ class ThePassViewHolder {
private val currentPass by lazy { private val currentPass by lazy {
TestApp.populatePassStoreWithSinglePass() TestApp.populatePassStoreWithSinglePass()
App.passStore.currentPass as PassImpl TestApp.passStore.currentPass as PassImpl
} }
@get:Rule @get:Rule

View file

@ -49,7 +49,7 @@ public class TheUnzipPassController {
verify(failCallback).fail(any(String.class)); verify(failCallback).fail(any(String.class));
} catch (Exception e) { } catch (Exception e) {
fail("should be able to load file"); fail("should be able to load file " + e);
} }
} }

View file

@ -3,6 +3,7 @@ package org.ligi.passandroid.functions
import android.content.Context import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import org.assertj.core.api.Fail.fail import org.assertj.core.api.Fail.fail
import org.ligi.passandroid.TestApp
import org.ligi.passandroid.model.InputStreamWithSource import org.ligi.passandroid.model.InputStreamWithSource
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.Pass import org.ligi.passandroid.model.pass.Pass
@ -30,7 +31,7 @@ fun loadPassFromAsset(asset: String, callback: (pass: Pass?) -> Unit) {
object : UnzipPassController.SuccessCallback { object : UnzipPassController.SuccessCallback {
override fun call(uuid: String) { override fun call(uuid: String) {
callback.invoke(AppleStylePassReader.read(File(getTestTargetPath(instrumentation.targetContext), uuid), "en", callback.invoke(AppleStylePassReader.read(File(getTestTargetPath(instrumentation.targetContext), uuid), "en",
instrumentation.targetContext)) instrumentation.targetContext,TestApp.tracker))
} }
}, },
mock mock

View file

@ -2,10 +2,14 @@ package org.ligi.passandroid
import android.app.Application import android.app.Application
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.github.salomonbrys.kodein.*
import com.jakewharton.threetenabp.AndroidThreeTen import com.jakewharton.threetenabp.AndroidThreeTen
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.core.module.Module
import org.koin.dsl.module
import org.ligi.passandroid.json_adapter.ColorAdapter import org.ligi.passandroid.json_adapter.ColorAdapter
import org.ligi.passandroid.json_adapter.ZonedTimeAdapter import org.ligi.passandroid.json_adapter.ZonedTimeAdapter
import org.ligi.passandroid.model.AndroidFileSystemPassStore import org.ligi.passandroid.model.AndroidFileSystemPassStore
@ -17,43 +21,43 @@ import org.ligi.tracedroid.logging.Log
open class App : Application() { open class App : Application() {
private val moshi = Moshi.Builder()
.add(ZonedTimeAdapter())
.add(ColorAdapter())
.build()
private val settings by lazy { AndroidSettings(this) }
open fun createKoin(): Module {
return module {
single { AndroidFileSystemPassStore(this@App, get(), moshi, get()) as PassStore }
single { settings as Settings }
single { EventBus.getDefault() }
single { createTracker(this@App) }
}
}
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
kodein = Kodein { startKoin {
import(createTrackerKodeinModule(this@App)) if (BuildConfig.DEBUG) androidLogger()
import(createKodein(), allowOverride = true) androidContext(this@App)
modules(createKoin())
} }
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
AndroidThreeTen.init(this) AndroidThreeTen.init(this)
initTraceDroid() initTraceDroid()
val settings: Settings = kodein.instance()
AppCompatDelegate.setDefaultNightMode(settings.getNightMode()) AppCompatDelegate.setDefaultNightMode(settings.getNightMode())
} }
open fun createKodein() = Kodein.Module {
val moshi = Moshi.Builder()
.add(ZonedTimeAdapter())
.add(ColorAdapter())
.build()
bind<PassStore>() with singleton { AndroidFileSystemPassStore(this@App, instance(), moshi, instance()) }
bind<Settings>() with singleton { AndroidSettings(this@App) }
bind<EventBus>() with singleton { EventBus.getDefault() }
}
private fun initTraceDroid() { private fun initTraceDroid() {
TraceDroid.init(this) TraceDroid.init(this)
Log.setTAG("PassAndroid") Log.setTAG("PassAndroid")
} }
companion object {
lateinit var kodein: Kodein
val tracker by lazy { kodein.Instance(TT(Tracker::class.java)) }
val passStore by lazy { kodein.Instance(TT(PassStore::class.java)) }
val settings by lazy { kodein.Instance(TT(Settings::class.java)) }
}
} }

View file

@ -4,31 +4,31 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.ligi.passandroid.App import org.ligi.passandroid.Tracker
import org.ligi.passandroid.model.InputStreamWithSource import org.ligi.passandroid.model.InputStreamWithSource
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.net.URL import java.net.URL
const val IPHONE_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53" const val IPHONE_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53"
fun fromURI(context: Context, uri: Uri): InputStreamWithSource? { fun fromURI(context: Context, uri: Uri, tracker: Tracker): InputStreamWithSource? {
App.tracker.trackEvent("protocol", "to_inputstream", uri.scheme, null) tracker.trackEvent("protocol", "to_inputstream", uri.scheme, null)
return when (uri.scheme) { return when (uri.scheme) {
"content" -> fromContent(context, uri) "content" -> fromContent(context, uri)
"http", "https" -> "http", "https" ->
// TODO check if SPDY should be here // TODO check if SPDY should be here
return fromOKHttp(uri) return fromOKHttp(uri, tracker)
"file" -> getDefaultInputStreamForUri(uri) "file" -> getDefaultInputStreamForUri(uri)
else -> { else -> {
App.tracker.trackException("unknown scheme in ImportAsyncTask" + uri.scheme, false) tracker.trackException("unknown scheme in ImportAsyncTask" + uri.scheme, false)
getDefaultInputStreamForUri(uri) getDefaultInputStreamForUri(uri)
} }
} }
} }
private fun fromOKHttp(uri: Uri): InputStreamWithSource? { private fun fromOKHttp(uri: Uri, tracker: Tracker): InputStreamWithSource? {
val client = OkHttpClient() val client = OkHttpClient()
val url = URL(uri.toString()) val url = URL(uri.toString())
val requestBuilder = Request.Builder().url(url) val requestBuilder = Request.Builder().url(url)
@ -47,7 +47,7 @@ private fun fromOKHttp(uri: Uri): InputStreamWithSource? {
for ((key, value) in iPhoneFakeMap) { for ((key, value) in iPhoneFakeMap) {
if (uri.toString().contains(value)) { if (uri.toString().contains(value)) {
App.tracker.trackEvent("quirk_fix", "ua_fake", key, null) tracker.trackEvent("quirk_fix", "ua_fake", key, null)
requestBuilder.header("User-Agent", IPHONE_USER_AGENT) requestBuilder.header("User-Agent", IPHONE_USER_AGENT)
} }
} }

View file

@ -7,8 +7,10 @@ import okio.buffer
import okio.sink import okio.sink
import okio.source import okio.source
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.ligi.passandroid.App import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.passandroid.BuildConfig import org.ligi.passandroid.BuildConfig
import org.ligi.passandroid.Tracker
import org.ligi.passandroid.events.PassStoreChangeEvent import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.model.pass.Pass import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.model.pass.PassImpl import org.ligi.passandroid.model.pass.PassImpl
@ -17,13 +19,19 @@ import org.ligi.passandroid.reader.PassReader
import java.io.File import java.io.File
import java.util.* import java.util.*
class AndroidFileSystemPassStore(private val context: Context, settings: Settings, private val moshi: Moshi, private val bus: EventBus) : PassStore { class AndroidFileSystemPassStore(
private val context: Context, settings: Settings,
private val moshi: Moshi,
private val bus: EventBus
) : PassStore, KoinComponent {
private val path: File = settings.getPassesDir() private val path: File = settings.getPassesDir()
override val passMap = HashMap<String, Pass>() override val passMap = HashMap<String, Pass>()
override var currentPass: Pass? = null override var currentPass: Pass? = null
private val tracker: Tracker by inject ()
override val classifier: PassClassifier by lazy { override val classifier: PassClassifier by lazy {
val classificationFile = File(settings.getStateDir(), "classifier_state.json") val classificationFile = File(settings.getStateDir(), "classifier_state.json")
FileBackedPassClassifier(classificationFile, this, moshi) FileBackedPassClassifier(classificationFile, this, moshi)
@ -71,7 +79,7 @@ class AndroidFileSystemPassStore(private val context: Context, settings: Setting
try { try {
result = jsonAdapter.fromJson(file.source().buffer()) result = jsonAdapter.fromJson(file.source().buffer())
} catch (ignored: JsonDataException) { } catch (ignored: JsonDataException) {
App.tracker.trackException("invalid main.json", false) tracker.trackException("invalid main.json", false)
} }
} }
@ -81,7 +89,7 @@ class AndroidFileSystemPassStore(private val context: Context, settings: Setting
} }
if (result == null && File(pathForID, "pass.json").exists()) { if (result == null && File(pathForID, "pass.json").exists()) {
result = AppleStylePassReader.read(pathForID, language, context) result = AppleStylePassReader.read(pathForID, language, context, tracker)
} }
if (result != null) { if (result != null) {

View file

@ -10,7 +10,6 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import org.ligi.passandroid.App;
public class AppleStylePassTranslation extends HashMap<String, String> { public class AppleStylePassTranslation extends HashMap<String, String> {
@ -74,7 +73,6 @@ public class AppleStylePassTranslation extends HashMap<String, String> {
} }
return new String(fileData); return new String(fileData);
} catch (Throwable e) { } catch (Throwable e) {
App.Companion.getTracker().trackException("problem_reading_translation", e, false);
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }

View file

@ -2,21 +2,21 @@ package org.ligi.passandroid.model.pass
import android.content.res.Resources import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import com.github.salomonbrys.kodein.instance
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import org.ligi.passandroid.App import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import org.ligi.passandroid.functions.generateBitmapDrawable import org.ligi.passandroid.functions.generateBitmapDrawable
import org.ligi.tracedroid.logging.Log import org.ligi.tracedroid.logging.Log
import java.util.* import java.util.*
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
class BarCode(val format: PassBarCodeFormat?, val message: String? = UUID.randomUUID().toString().toUpperCase()) { class BarCode(val format: PassBarCodeFormat?, val message: String? = UUID.randomUUID().toString().toUpperCase()) : KoinComponent {
val tracker: Tracker by inject ()
var alternativeText: String? = null var alternativeText: String? = null
fun getBitmap(resources: Resources): BitmapDrawable? { fun getBitmap(resources: Resources): BitmapDrawable? {
val tracker: Tracker = App.kodein.instance()
if (message == null) { if (message == null) {
// no message -> no barcode // no message -> no barcode
tracker.trackException("No Barcode in pass - strange", false) tracker.trackException("No Barcode in pass - strange", false)

View file

@ -7,8 +7,8 @@ import android.graphics.Color
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import org.ligi.kaxt.parseColor import org.ligi.kaxt.parseColor
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.Tracker
import org.ligi.passandroid.functions.getHumanCategoryString import org.ligi.passandroid.functions.getHumanCategoryString
import org.ligi.passandroid.functions.readJSONSafely import org.ligi.passandroid.functions.readJSONSafely
import org.ligi.passandroid.model.ApplePassbookQuirkCorrector import org.ligi.passandroid.model.ApplePassbookQuirkCorrector
@ -26,7 +26,7 @@ import java.util.*
object AppleStylePassReader { object AppleStylePassReader {
fun read(passFile: File, language: String, context: Context): Pass? { fun read(passFile: File, language: String, context: Context, tracker: Tracker): Pass? {
val translation = AppleStylePassTranslation() val translation = AppleStylePassTranslation()
@ -34,7 +34,7 @@ object AppleStylePassReader {
var passJSON: JSONObject? = null var passJSON: JSONObject? = null
val localizedPath = findLocalizedPath(passFile, language) val localizedPath = findLocalizedPath(passFile, language, tracker)
if (localizedPath != null) { if (localizedPath != null) {
val file = File(localizedPath, "pass.strings") val file = File(localizedPath, "pass.strings")
@ -77,7 +77,7 @@ object AppleStylePassReader {
if (passJSON == null) { if (passJSON == null) {
Log.w("could not load pass.json from passcode ") Log.w("could not load pass.json from passcode ")
App.tracker.trackEvent("problem_event", "pass", "without_pass_json", null) tracker.trackEvent("problem_event", "pass", "without_pass_json", null)
return null return null
} }
@ -86,7 +86,7 @@ object AppleStylePassReader {
if (barcodeJSON != null) { if (barcodeJSON != null) {
val barcodeFormatString = barcodeJSON.getString("format") val barcodeFormatString = barcodeJSON.getString("format")
App.tracker.trackEvent("measure_event", "barcode_format", barcodeFormatString, 0L) tracker.trackEvent("measure_event", "barcode_format", barcodeFormatString, 0L)
val barcodeFormat = BarCode.getFormatFromString(barcodeFormatString) val barcodeFormat = BarCode.getFormatFromString(barcodeFormatString)
val barCode = BarCode(barcodeFormat, barcodeJSON.getString("message")) val barCode = BarCode(barcodeFormat, barcodeJSON.getString("message"))
pass.barCode = barCode pass.barCode = barCode
@ -105,9 +105,9 @@ object AppleStylePassReader {
} catch (e: JSONException) { } catch (e: JSONException) {
// be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here // be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here
// OK then we just have no date here // OK then we just have no date here
App.tracker.trackException("problem parsing relevant date", e, false) tracker.trackException("problem parsing relevant date", e, false)
} catch (e: DateTimeException) { } catch (e: DateTimeException) {
App.tracker.trackException("problem parsing relevant date", e, false) tracker.trackException("problem parsing relevant date", e, false)
} }
} }
@ -118,9 +118,9 @@ object AppleStylePassReader {
} catch (e: JSONException) { } catch (e: JSONException) {
// be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here // be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here
// OK then we just have no date here // OK then we just have no date here
App.tracker.trackException("problem parsing expiration date", e, false) tracker.trackException("problem parsing expiration date", e, false)
} catch (e: DateTimeException) { } catch (e: DateTimeException) {
App.tracker.trackException("problem parsing expiration date", e, false) tracker.trackException("problem parsing expiration date", e, false)
} }
} }
@ -196,12 +196,12 @@ object AppleStylePassReader {
try { try {
pass.creator = passJSON.getString("organizationName") pass.creator = passJSON.getString("organizationName")
App.tracker.trackEvent("measure_event", "organisation_parse", pass.creator, 1L) tracker.trackEvent("measure_event", "organisation_parse", pass.creator, 1L)
} catch (ignored: JSONException) { } catch (ignored: JSONException) {
// ok - we have no organisation - big deal ..-) // ok - we have no organisation - big deal ..-)
} }
ApplePassbookQuirkCorrector(App.tracker).correctQuirks(pass) ApplePassbookQuirkCorrector(tracker).correctQuirks(pass)
return pass return pass
} }
@ -240,18 +240,18 @@ object AppleStylePassReader {
} }
private fun findLocalizedPath(path: File, language: String): String? { private fun findLocalizedPath(path: File, language: String, tracker: Tracker): String? {
val localized = File(path, "$language.lproj") val localized = File(path, "$language.lproj")
if (localized.exists() && localized.isDirectory) { if (localized.exists() && localized.isDirectory) {
App.tracker.trackEvent("measure_event", "pass", language + "_native_lproj", null) tracker.trackEvent("measure_event", "pass", language + "_native_lproj", null)
return localized.path return localized.path
} }
val fallback = File(path, "en.lproj") val fallback = File(path, "en.lproj")
if (fallback.exists() && fallback.isDirectory) { if (fallback.exists() && fallback.isDirectory) {
App.tracker.trackEvent("measure_event", "pass", "en_lproj", null) tracker.trackEvent("measure_event", "pass", "en_lproj", null)
return fallback.path return fallback.path
} }

View file

@ -1,14 +1,14 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import com.google.android.material.snackbar.Snackbar import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import com.google.android.material.snackbar.Snackbar
import android.view.ViewGroup import org.koin.core.KoinComponent
import com.github.salomonbrys.kodein.instance import org.koin.core.inject
import org.ligi.kaxt.startActivityFromClass import org.ligi.kaxt.startActivityFromClass
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.PassStoreProjection import org.ligi.passandroid.model.PassStoreProjection
@ -17,10 +17,13 @@ import org.ligi.passandroid.ui.pass_view_holder.CondensedPassViewHolder
import org.ligi.passandroid.ui.pass_view_holder.PassViewHolder import org.ligi.passandroid.ui.pass_view_holder.PassViewHolder
import org.ligi.passandroid.ui.pass_view_holder.VerbosePassViewHolder import org.ligi.passandroid.ui.pass_view_holder.VerbosePassViewHolder
class PassAdapter(private val passListActivity: AppCompatActivity, private val passStoreProjection: PassStoreProjection) : RecyclerView.Adapter<PassViewHolder>() { class PassAdapter(
private val passListActivity: AppCompatActivity,
private val passStoreProjection: PassStoreProjection
) : RecyclerView.Adapter<PassViewHolder>(), KoinComponent {
val passStore: PassStore = App.kodein.instance() private val passStore: PassStore by inject ()
val settings: Settings = App.kodein.instance() private val settings: Settings by inject ()
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): PassViewHolder { override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): PassViewHolder {
val inflater = LayoutInflater.from(viewGroup.context) val inflater = LayoutInflater.from(viewGroup.context)

View file

@ -1,19 +1,18 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.github.salomonbrys.kodein.instance
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.ligi.passandroid.App import org.koin.android.ext.android.inject
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.Settings import org.ligi.passandroid.model.Settings
open class PassAndroidActivity : AppCompatActivity() { open class PassAndroidActivity : AppCompatActivity() {
val passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
val settings: Settings = App.kodein.instance() val settings: Settings by inject()
val bus: EventBus = App.kodein.instance() val bus: EventBus by inject()
val tracker: Tracker = App.kodein.instance() val tracker: Tracker by inject()
private var lastSetNightMode: Int? = null private var lastSetNightMode: Int? = null

View file

@ -3,19 +3,18 @@ package org.ligi.passandroid.ui
import android.Manifest import android.Manifest
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.annotation.IdRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.Button import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
import com.github.salomonbrys.kodein.instance import androidx.annotation.IdRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.edit.* import kotlinx.android.synthetic.main.edit.*
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.koin.android.ext.android.inject
import org.ligi.kaxt.doAfterEdit import org.ligi.kaxt.doAfterEdit
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassRefreshEvent import org.ligi.passandroid.events.PassRefreshEvent
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
@ -39,8 +38,8 @@ class PassEditActivity : AppCompatActivity() {
private lateinit var currentPass: PassImpl private lateinit var currentPass: PassImpl
private val imageEditHelper by lazy { ImageEditHelper(this, passStore) } private val imageEditHelper by lazy { ImageEditHelper(this, passStore) }
internal val passStore: PassStore = App.kodein.instance() internal val passStore: PassStore by inject()
internal val bus: EventBus = App.kodein.instance() internal val bus: EventBus by inject()
private val passViewHelper: PassViewHelper by lazy { PassViewHelper(this) } private val passViewHelper: PassViewHelper by lazy { PassViewHelper(this) }

View file

@ -4,15 +4,21 @@ import android.app.Activity
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.Intent import android.content.Intent
import android.os.Handler import android.os.Handler
import android.widget.Toast
import androidx.annotation.UiThread import androidx.annotation.UiThread
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import android.widget.Toast import org.koin.core.KoinComponent
import org.ligi.passandroid.App import org.koin.core.inject
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.Tracker
import java.io.File import java.io.File
internal open class PassExportTaskAndShare(protected val activity: Activity, private val inputPath: File) { internal open class PassExportTaskAndShare(
protected val activity: Activity,
private val inputPath: File
) : KoinComponent {
val tracker: Tracker by inject()
@UiThread @UiThread
fun execute() { fun execute() {
val file = File(activity.filesDir, "share/share.espass") // important - the FileProvider must be configured for this path val file = File(activity.filesDir, "share/share.espass") // important - the FileProvider must be configured for this path
@ -31,7 +37,7 @@ internal open class PassExportTaskAndShare(protected val activity: Activity, pri
} }
if (passExporter.exception != null) { if (passExporter.exception != null) {
App.tracker.trackException("passExporterException", passExporter.exception!!, false) tracker.trackException("passExporterException", passExporter.exception!!, false)
Toast.makeText(activity, "could not export pass: " + passExporter.exception, Toast.LENGTH_LONG).show() Toast.makeText(activity, "could not export pass: " + passExporter.exception, Toast.LENGTH_LONG).show()
} else { } else {
val uriForFile = FileProvider.getUriForFile(activity, activity.getString(R.string.authority_fileprovider), file) val uriForFile = FileProvider.getUriForFile(activity, activity.getString(R.string.authority_fileprovider), file)

View file

@ -4,14 +4,16 @@ import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ZipParameters import net.lingala.zip4j.model.ZipParameters
import net.lingala.zip4j.model.enums.CompressionLevel import net.lingala.zip4j.model.enums.CompressionLevel
import net.lingala.zip4j.model.enums.CompressionMethod import net.lingala.zip4j.model.enums.CompressionMethod
import org.koin.core.KoinComponent
import org.ligi.passandroid.App import org.koin.core.inject
import org.ligi.passandroid.Tracker
import java.io.File import java.io.File
class PassExporter(private val inputPath: File, val file: File) { class PassExporter(private val inputPath: File, val file: File) : KoinComponent {
var exception: Exception? = null var exception: Exception? = null
val tracker: Tracker by inject()
fun export() { fun export() {
try { try {
file.delete() file.delete()
@ -28,7 +30,7 @@ class PassExporter(private val inputPath: File, val file: File) {
} catch (exception: Exception) { } catch (exception: Exception) {
exception.printStackTrace() exception.printStackTrace()
App.tracker.trackException("when exporting pass to zip", exception, false) tracker.trackException("when exporting pass to zip", exception, false)
this.exception = exception // we need to take action on the main thread later this.exception = exception // we need to take action on the main thread later
file.delete() // prevent zombies from taking over file.delete() // prevent zombies from taking over
} }

View file

@ -5,14 +5,13 @@ import android.os.Bundle
import android.view.View.GONE import android.view.View.GONE
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.github.salomonbrys.kodein.instance
import kotlinx.android.synthetic.main.activity_import.* import kotlinx.android.synthetic.main.activity_import.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import org.ligi.kaxt.startActivityFromClass import org.ligi.kaxt.startActivityFromClass
import org.ligi.kaxtui.alert import org.ligi.kaxtui.alert
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import org.ligi.passandroid.functions.fromURI import org.ligi.passandroid.functions.fromURI
@ -25,8 +24,8 @@ import permissions.dispatcher.RuntimePermissions
@RuntimePermissions @RuntimePermissions
class PassImportActivity : AppCompatActivity() { class PassImportActivity : AppCompatActivity() {
val tracker: Tracker = App.kodein.instance() val tracker: Tracker by inject()
val passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -51,7 +50,7 @@ class PassImportActivity : AppCompatActivity() {
fun doImport(withPermission: Boolean) { fun doImport(withPermission: Boolean) {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
try { try {
val fromURI = fromURI(this@PassImportActivity, intent!!.data!!) val fromURI = fromURI(this@PassImportActivity, intent!!.data!!, tracker)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {

View file

@ -1,23 +1,22 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.os.Bundle import android.os.Bundle
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.github.salomonbrys.kodein.instance import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import kotlinx.android.synthetic.main.pass_recycler.view.* import kotlinx.android.synthetic.main.pass_recycler.view.*
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import org.ligi.passandroid.App import org.koin.android.ext.android.inject
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassStoreChangeEvent import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.events.ScanFinishedEvent import org.ligi.passandroid.events.ScanFinishedEvent
@ -32,9 +31,9 @@ class PassListFragment : Fragment() {
private lateinit var passStoreProjection: PassStoreProjection private lateinit var passStoreProjection: PassStoreProjection
private lateinit var adapter: PassAdapter private lateinit var adapter: PassAdapter
val passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
val settings: Settings = App.kodein.instance() val settings: Settings by inject()
val bus: EventBus = App.kodein.instance() val bus: EventBus by inject()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val inflate = inflater.inflate(R.layout.pass_recycler, container, false) val inflate = inflater.inflate(R.layout.pass_recycler, container, false)

View file

@ -2,14 +2,14 @@ package org.ligi.passandroid.ui
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import androidx.core.app.NavUtils
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import com.github.salomonbrys.kodein.instance import androidx.appcompat.app.AlertDialog
import androidx.core.app.NavUtils
import kotlinx.android.synthetic.main.delete_dialog_layout.view.* import kotlinx.android.synthetic.main.delete_dialog_layout.view.*
import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.kaxt.startActivityFromClass import org.ligi.kaxt.startActivityFromClass
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import org.ligi.passandroid.maps.PassbookMapsFacade import org.ligi.passandroid.maps.PassbookMapsFacade
@ -19,11 +19,11 @@ import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.printing.doPrint import org.ligi.passandroid.printing.doPrint
import java.io.File import java.io.File
class PassMenuOptions(val activity: Activity, val pass: Pass) { class PassMenuOptions(val activity: Activity, val pass: Pass) : KoinComponent {
var passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
var tracker: Tracker = App.kodein.instance() val tracker: Tracker by inject()
var settings: Settings = App.kodein.instance() val settings: Settings by inject()
fun process(item: MenuItem): Boolean { fun process(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {

View file

@ -4,22 +4,22 @@ import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import com.google.android.material.navigation.NavigationView
import android.util.AttributeSet import android.util.AttributeSet
import com.github.salomonbrys.kodein.instance import com.google.android.material.navigation.NavigationView
import kotlinx.android.synthetic.main.navigation_drawer_header.view.* import kotlinx.android.synthetic.main.navigation_drawer_header.view.*
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import org.ligi.passandroid.App import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassStoreChangeEvent import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView(context, attrs) { class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView(context, attrs), KoinComponent {
val passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
val bus: EventBus = App.kodein.instance() val bus: EventBus by inject()
private fun getIntent(id: Int) = when (id) { private fun getIntent(id: Int) = when (id) {
R.id.menu_settings -> Intent(context, PreferenceActivity::class.java) R.id.menu_settings -> Intent(context, PreferenceActivity::class.java)

View file

@ -2,23 +2,22 @@ package org.ligi.passandroid.ui
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.core.text.util.LinkifyCompat
import android.text.util.Linkify import android.text.util.Linkify
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.text.util.LinkifyCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.github.salomonbrys.kodein.instance
import kotlinx.android.synthetic.main.activity_pass_view.* import kotlinx.android.synthetic.main.activity_pass_view.*
import kotlinx.android.synthetic.main.barcode.* import kotlinx.android.synthetic.main.barcode.*
import kotlinx.android.synthetic.main.pass_list_item.* import kotlinx.android.synthetic.main.pass_list_item.*
import kotlinx.android.synthetic.main.pass_view_extra_data.* import kotlinx.android.synthetic.main.pass_view_extra_data.*
import org.koin.android.ext.android.inject
import org.ligi.compat.HtmlCompat import org.ligi.compat.HtmlCompat
import org.ligi.kaxt.startActivityFromClass import org.ligi.kaxt.startActivityFromClass
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.maps.PassbookMapsFacade import org.ligi.passandroid.maps.PassbookMapsFacade
import org.ligi.passandroid.model.PassBitmapDefinitions import org.ligi.passandroid.model.PassBitmapDefinitions
@ -29,7 +28,7 @@ import org.ligi.passandroid.ui.pass_view_holder.VerbosePassViewHolder
class PassViewFragment : Fragment() { class PassViewFragment : Fragment() {
private val passViewHelper by lazy { PassViewHelper(requireActivity()) } private val passViewHelper by lazy { PassViewHelper(requireActivity()) }
private var passStore : PassStore = App.kodein.instance() internal val passStore : PassStore by inject()
lateinit var pass : Pass lateinit var pass : Pass
private fun processImage(view: ImageView, name: String, pass: Pass) { private fun processImage(view: ImageView, name: String, pass: Pass) {

View file

@ -6,14 +6,17 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_AUTO import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_AUTO
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import org.ligi.passandroid.App import org.koin.android.ext.android.inject
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.Settings
import permissions.dispatcher.NeedsPermission import permissions.dispatcher.NeedsPermission
import permissions.dispatcher.RuntimePermissions import permissions.dispatcher.RuntimePermissions
@RuntimePermissions @RuntimePermissions
class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener {
val settings : Settings by inject()
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this) preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
@ -26,7 +29,7 @@ class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPref
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == getString(R.string.preference_key_nightmode)) { if (key == getString(R.string.preference_key_nightmode)) {
@AppCompatDelegate.NightMode val nightMode = App.settings.getNightMode() @AppCompatDelegate.NightMode val nightMode = settings.getNightMode()
if (nightMode == MODE_NIGHT_AUTO) { if (nightMode == MODE_NIGHT_AUTO) {
ensureDayNightWithPermissionCheck() ensureDayNightWithPermissionCheck()

View file

@ -11,9 +11,8 @@ import android.os.Build
import android.os.Environment import android.os.Environment
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.github.salomonbrys.kodein.instance
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.ligi.passandroid.App import org.koin.android.ext.android.inject
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import org.ligi.passandroid.events.ScanFinishedEvent import org.ligi.passandroid.events.ScanFinishedEvent
@ -43,9 +42,9 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
private var lastProgressUpdate: Long = 0 private var lastProgressUpdate: Long = 0
val passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
val bus: EventBus = App.kodein.instance() val bus: EventBus by inject()
val tracker: Tracker = App.kodein.instance() val tracker: Tracker by inject()
override fun onHandleIntent(intent: Intent?) { override fun onHandleIntent(intent: Intent?) {
@ -130,7 +129,7 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
Log.i("found" + file.absolutePath) Log.i("found" + file.absolutePath)
try { try {
val ins = fromURI(baseContext, Uri.parse("file://" + file.absolutePath)) val ins = fromURI(baseContext, Uri.parse("file://" + file.absolutePath), tracker)
val onSuccessCallback = SearchSuccessCallback(baseContext, val onSuccessCallback = SearchSuccessCallback(baseContext,
passStore, passStore,
foundList, foundList,

View file

@ -1,16 +1,15 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem import android.view.MenuItem
import com.github.salomonbrys.kodein.instance import androidx.appcompat.app.AppCompatActivity
import com.ortiz.touch.TouchImageView import com.ortiz.touch.TouchImageView
import org.ligi.passandroid.App import org.koin.android.ext.android.inject
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
class TouchImageActivity : AppCompatActivity() { class TouchImageActivity : AppCompatActivity() {
val passStore: PassStore = App.kodein.instance() val passStore: PassStore by inject()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

View file

@ -1,8 +1,8 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.content.Context import android.content.Context
import org.ligi.passandroid.App
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.Settings
import org.ligi.passandroid.ui.UnzipPassController.FailCallback import org.ligi.passandroid.ui.UnzipPassController.FailCallback
import org.ligi.passandroid.ui.UnzipPassController.SuccessCallback import org.ligi.passandroid.ui.UnzipPassController.SuccessCallback
import java.io.File import java.io.File
@ -14,7 +14,7 @@ open class UnzipControllerSpec(var targetPath: File,
val failCallback: FailCallback?) { val failCallback: FailCallback?) {
var overwrite = false var overwrite = false
constructor(context: Context, passStore: PassStore, onSuccessCallback: SuccessCallback?, failCallback: FailCallback?) constructor(context: Context, passStore: PassStore, onSuccessCallback: SuccessCallback?, failCallback: FailCallback?, settings: Settings)
: this(App.settings.getPassesDir(), context, passStore, onSuccessCallback, failCallback) : this(settings.getPassesDir(), context, passStore, onSuccessCallback, failCallback)
} }

View file

@ -11,18 +11,25 @@ import net.lingala.zip4j.exception.ZipException
import okio.buffer import okio.buffer
import okio.source import okio.source
import org.json.JSONObject import org.json.JSONObject
import org.ligi.passandroid.App import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.passandroid.Tracker
import org.ligi.passandroid.functions.createPassForImageImport import org.ligi.passandroid.functions.createPassForImageImport
import org.ligi.passandroid.functions.createPassForPDFImport import org.ligi.passandroid.functions.createPassForPDFImport
import org.ligi.passandroid.functions.readJSONSafely import org.ligi.passandroid.functions.readJSONSafely
import org.ligi.passandroid.model.AndroidSettings
import org.ligi.passandroid.model.InputStreamWithSource import org.ligi.passandroid.model.InputStreamWithSource
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.Settings
import org.ligi.tracedroid.logging.Log import org.ligi.tracedroid.logging.Log
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.util.* import java.util.*
object UnzipPassController { object UnzipPassController : KoinComponent {
val tracker :Tracker by inject()
val settings : Settings by inject()
interface SuccessCallback { interface SuccessCallback {
fun call(uuid: String) fun call(uuid: String)
@ -39,7 +46,7 @@ object UnzipPassController {
processFile(FileUnzipControllerSpec(tempFile.absolutePath, spec)) processFile(FileUnzipControllerSpec(tempFile.absolutePath, spec))
tempFile.delete() tempFile.delete()
} catch (e: Exception) { } catch (e: Exception) {
App.tracker.trackException("problem processing InputStream", e, false) tracker.trackException("problem processing InputStream", e, false)
spec.failCallback?.fail("problem with temp file: $e") spec.failCallback?.fail("problem with temp file: $e")
} }
@ -158,6 +165,6 @@ object UnzipPassController {
} }
class InputStreamUnzipControllerSpec(internal val inputStreamWithSource: InputStreamWithSource, context: Context, passStore: PassStore, class InputStreamUnzipControllerSpec(internal val inputStreamWithSource: InputStreamWithSource, context: Context, passStore: PassStore,
onSuccessCallback: SuccessCallback?, failCallback: FailCallback?) : UnzipControllerSpec(context, passStore, onSuccessCallback, failCallback) onSuccessCallback: SuccessCallback?, failCallback: FailCallback?) : UnzipControllerSpec(context, passStore, onSuccessCallback, failCallback, settings)
} }

View file

@ -1,22 +1,25 @@
package org.ligi.passandroid.ui.edit package org.ligi.passandroid.ui.edit
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.edit_field.view.* import kotlinx.android.synthetic.main.edit_field.view.*
import kotlinx.android.synthetic.main.edit_fields.view.* import kotlinx.android.synthetic.main.edit_fields.view.*
import org.koin.android.ext.android.inject
import org.ligi.kaxt.doAfterEdit import org.ligi.kaxt.doAfterEdit
import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.PassField import org.ligi.passandroid.model.pass.PassField
import org.ligi.passandroid.model.pass.PassImpl import org.ligi.passandroid.model.pass.PassImpl
class FieldsEditFragment : Fragment() { class FieldsEditFragment : Fragment() {
private fun getPass(): PassImpl = App.passStore.currentPass as PassImpl val passStore by inject<PassStore>()
private fun getPass(): PassImpl = passStore.currentPass as PassImpl
private var isEditingHiddenFields: Boolean = false private var isEditingHiddenFields: Boolean = false

View file

@ -1,10 +1,5 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.content.Context import android.content.Context
import com.github.salomonbrys.kodein.Kodein
import com.github.salomonbrys.kodein.bind
import com.github.salomonbrys.kodein.singleton
fun createTrackerKodeinModule(context: Context) = Kodein.Module { fun createTracker(context: Context) = NotTracker() as Tracker
bind<Tracker>() with singleton { NotTracker() }
}

View file

@ -1,10 +1,5 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.content.Context import android.content.Context
import com.github.salomonbrys.kodein.Kodein
import com.github.salomonbrys.kodein.bind
import com.github.salomonbrys.kodein.singleton
fun createTrackerKodeinModule(context: Context) = Kodein.Module { fun createTracker(context: Context) = AnalyticsTracker(context) as Tracker
bind<Tracker>() with singleton { AnalyticsTracker(context) }
}

View file

@ -11,12 +11,16 @@ import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.LatLngBounds import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MarkerOptions import com.google.android.gms.maps.model.MarkerOptions
import org.koin.android.ext.android.inject
import org.ligi.kaxt.startActivityFromClass import org.ligi.kaxt.startActivityFromClass
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.ui.PassViewActivityBase import org.ligi.passandroid.ui.PassViewActivityBase
class LocationsMapFragment : SupportMapFragment() { class LocationsMapFragment : SupportMapFragment() {
var clickToFullscreen = false var clickToFullscreen = false
val passStore : PassStore by inject()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val root = super.onCreateView(inflater, container, savedInstanceState) val root = super.onCreateView(inflater, container, savedInstanceState)
val baseActivity = activity as PassViewActivityBase val baseActivity = activity as PassViewActivityBase
@ -25,7 +29,7 @@ class LocationsMapFragment : SupportMapFragment() {
map.setOnMapLoadedCallback { map.setOnMapLoadedCallback {
if (clickToFullscreen) if (clickToFullscreen)
map.setOnMapClickListener { map.setOnMapClickListener {
App.passStore.currentPass = baseActivity.currentPass passStore.currentPass = baseActivity.currentPass
baseActivity.startActivityFromClass(FullscreenMapActivity::class.java) baseActivity.startActivityFromClass(FullscreenMapActivity::class.java)
} }