Skip to content

Commit 36d46f5

Browse files
author
Patrick Jackson
committed
[WIP]Thunks and presenters working on iOS
1 parent 9de979c commit 36d46f5

File tree

12 files changed

+127
-24
lines changed

12 files changed

+127
-24
lines changed

android/src/main/java/com/jackson/openlibrary/OpenLibraryApp.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.squareup.sqldelight.android.AndroidSqliteDriver
1111
import com.willowtree.common.LibraryDatabase
1212
import com.willowtreeapps.common.LibraryApp
1313
import com.willowtreeapps.common.Logger
14+
import com.willowtreeapps.common.createDatabase
1415
import kotlinx.coroutines.Dispatchers
1516

1617
class OpenLibraryApp : Application() {
@@ -38,7 +39,7 @@ class OpenLibraryApp : Application() {
3839
val sqlHelper = FrameworkSQLiteOpenHelperFactory().create(config)
3940

4041
val navigator = AndroidNavigator()
41-
libraryApp = LibraryApp(navigator, Dispatchers.IO, Dispatchers.Main, AndroidSqliteDriver(sqlHelper))
42+
libraryApp = LibraryApp(navigator, Dispatchers.IO, Dispatchers.Main, createDatabase(AndroidSqliteDriver(sqlHelper)))
4243
registerActivityLifecycleCallbacks(navigator)
4344
registerActivityLifecycleCallbacks(LifeCycleLogger)
4445
}

android/src/main/java/com/jackson/openlibrary/store/BaseLibraryViewFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import kotlin.coroutines.CoroutineContext
1616
open class BaseLibraryViewFragment<V: LibraryView>: Fragment(),
1717
CoroutineScope, LibraryView, LibraryProvider by OpenLibraryApp.gameEngine() {
1818
override lateinit var dispatch: Dispatcher
19-
override lateinit var selectorBuilder: SelectorSubscriberBuilder<AppState>
19+
override var selectorBuilder: SelectorSubscriberBuilder<AppState>? = null
2020

2121
override val coroutineContext: CoroutineContext
2222
get() = Dispatchers.Main

build.gradle

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlinVersion = "1.3.40"
5-
ext.androidx_home = project.properties["androidx.home"] ?: "$projectDir/androidx_prebuilts"
4+
ext.kotlinVersion = "1.3.41"
65
repositories {
76
google()
87
jcenter()
9-
maven { url "$androidx_home/out/ui/build/support_repo/" }
10-
maven { url "$androidx_home/prebuilts/androidx/external/" }
118
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
129
maven { url "https://kotlin.bintray.com/kotlinx" }
1310
maven { url 'https://dl.bintray.com/jetbrains/kotlin-native-dependencies' }
@@ -19,6 +16,8 @@ buildscript {
1916
classpath 'com.google.gms:google-services:4.3.0'
2017
classpath "com.squareup.sqldelight:gradle-plugin:1.1.4"
2118
classpath "com.github.ben-manes:gradle-versions-plugin:0.21.0"
19+
classpath 'co.touchlab:kotlinxcodesync:0.1.5'
20+
2221
// NOTE: Do not place your application dependencies here; they belong
2322
// in the individual module build.gradle files
2423
}
@@ -50,7 +49,7 @@ ext {
5049
stethoVersion = '1.5.0'
5150
ktxVersion = '1.0.0'
5251
ktorVersion = '1.2.2'
53-
serializationVersion = '0.11.0'
54-
multiplatformSettingsVersion = '0.3'
52+
serializationVersion = '0.11.1'
53+
multiplatformSettingsVersion = '0.3.2'
5554
sqldelightVersion = '1.1.4'
5655
}

common/build.gradle

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ apply plugin: 'com.android.library'
66
apply plugin: 'kotlin-multiplatform'
77
apply plugin: 'kotlinx-serialization'
88
apply plugin: 'com.squareup.sqldelight'
9+
apply plugin: 'co.touchlab.kotlinxcodesync'
10+
11+
xcode {
12+
projectPath = "../iOS/OpenLibrary/OpenLibrary.xcodeproj"
13+
target = "OpenLibrary"
14+
}
915

1016

1117
sqldelight {
@@ -136,7 +142,7 @@ android {
136142
//and gradlew is in executable mode (chmod +x gradlew)
137143
task packForXCode(type: Sync) {
138144
final File frameworkDir = new File(buildDir, "xcode-frameworks")
139-
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
145+
final String mode = 'DEBUG' //project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
140146
final def framework = kotlin.targets.ios.binaries.getFramework("common", mode)
141147

142148
inputs.property "mode", mode

common/src/commonMain/kotlin/com/willowtreeapps/common/LibraryApp.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.willowtreeapps.common
22

3-
import com.squareup.sqldelight.db.SqlDriver
3+
import com.willowtree.common.LibraryDatabase
44
import org.reduxkotlin.createStore
55
import org.reduxkotlin.applyMiddleware
66
import com.willowtreeapps.common.middleware.*
@@ -17,17 +17,17 @@ import kotlin.coroutines.CoroutineContext
1717
class LibraryApp(navigator: Navigator,
1818
networkContext: CoroutineContext,
1919
private val uiContext: CoroutineContext,
20-
sqlDriver: SqlDriver): LibraryProvider {
20+
libraryDatabase: LibraryDatabase): LibraryProvider {
2121
private val navigationMiddleware = NavigationMiddleware(navigator)
22-
private val localStorageRepo = BookDatabaseRepo(createDatabase(sqlDriver))
22+
private val localStorageRepo = BookDatabaseRepo(libraryDatabase)
2323
private val databaseMiddleware = DatabaseMiddleware(localStorageRepo)
2424
private val bookRepository: BookRepository by lazy { KtorOpenBookRepository(networkContext) }
2525
private val presenterFactory by lazy { PresenterFactory(this, uiContext) }
2626
// val fetchBooks = fetchBooksThunk(networkContext, bookRepository)
2727
override val networkThunks = NetworkThunks(networkContext, bookRepository)
2828

2929
val store by lazy {
30-
createStore(reducer, AppState.INITIAL_STATE, applyMiddleware(thunk,
30+
createStore(reducer, AppState.INITIAL_STATE, applyMiddleware(createThunkMiddleware2(),
3131
databaseMiddleware.middleware,
3232
navigationMiddleware::dispatch,
3333
loggerMiddleware))

common/src/commonMain/kotlin/com/willowtreeapps/common/NetworkThunks.kt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import kotlinx.coroutines.*
55
import org.reduxkotlin.Dispatcher
66
import org.reduxkotlin.GetState
77
import org.reduxkotlin.Thunk
8+
import org.reduxkotlin.ThunkMiddleware
89
import kotlin.coroutines.CoroutineContext
910

1011
/*
@@ -45,6 +46,7 @@ class NetworkThunks(private val networkContext: CoroutineContext,
4546
fun fetchBooks(query: String): Thunk = { dispatch, getState, extraArgument ->
4647
Logger.d("Fetching Books and Feed")
4748
launch {
49+
Logger.d("INSIDE FetchBooks 1")
4850
dispatch(Actions.FetchingItemsStartedAction())
4951
val result = repo.search(query)
5052
if (result.isSuccessful) {
@@ -56,4 +58,52 @@ class NetworkThunks(private val networkContext: CoroutineContext,
5658
}
5759
}
5860
}
61+
62+
fun fetchBooksThunk2(query: String): Thunk2 = object : Thunk2 {
63+
override fun dispatch(dispatch: Dispatcher, getState: GetState, extraArgument: Any?) {
64+
Logger.d("Fetching Books and Feed")
65+
launch {
66+
Logger.d("INSIDE FetchBooks 1")
67+
dispatch(Actions.FetchingItemsStartedAction())
68+
val result = repo.search(query)
69+
if (result.isSuccessful) {
70+
Logger.d("Success")
71+
dispatch(Actions.FetchingItemsSuccessAction(result.response!!))
72+
} else {
73+
Logger.d("Failure")
74+
dispatch(Actions.FetchingItemsFailedAction(result.message!!))
75+
}
76+
}
77+
}
78+
}
5979
}
80+
81+
interface Thunk2 {
82+
fun dispatch(dispatch: Dispatcher, getState: GetState, extraArgument: Any?)
83+
}
84+
85+
fun createThunkMiddleware2(extraArgument: Any? = null): ThunkMiddleware =
86+
{ store ->
87+
{ next: Dispatcher ->
88+
{ action: Any ->
89+
Logger.d("INSIDE ThunkMiddleware 1: $action")
90+
if (action is Thunk2) {
91+
Logger.d("INSIDE ThunkMiddleware 2: ")
92+
try {
93+
Logger.d("dispatch thunk 1: ${store.dispatch}")
94+
Logger.d("dispatch thunk 2: ${store.getState}")
95+
Logger.d("dispatch thunk 3: ${extraArgument}")
96+
Logger.d("dispatch thunk 4: $action")
97+
action.dispatch(store.dispatch, store.getState, extraArgument)
98+
} catch (e: Exception) {
99+
Logger.d("INSIDE ThunkMiddleware 3: ${e.message}")
100+
throw IllegalArgumentException()
101+
Logger.d("Dispatching functions must use type Thunk: " + e.message)
102+
}
103+
} else {
104+
Logger.d("INSIDE ThunkMiddleware 4: ")
105+
next(action)
106+
}
107+
}
108+
}
109+
}

common/src/commonMain/kotlin/com/willowtreeapps/common/builders.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ fun <S : Any, V: View<S>> SelectorSubscriberFn(store: Store, view: V, selectorSu
7171

7272

7373
view.selectorBuilder = SelectorSubscriberBuilder<S>(store, view)
74-
view.selectorBuilder.selectorSubscriberBuilderInit()
74+
view.selectorBuilder!!.selectorSubscriberBuilderInit()
7575
return {
76-
view.selectorBuilder.selectorList.forEach { entry ->
76+
view.selectorBuilder!!.selectorList.forEach { entry ->
7777
entry.key.onChangeIn(store.getState() as S) { entry.value(store.getState()) }
7878
}
79-
view.selectorBuilder.withAnyChangeFun?.invoke()
79+
view.selectorBuilder!!.withAnyChangeFun?.invoke()
8080
}
8181
}
8282

common/src/commonMain/kotlin/com/willowtreeapps/common/ui/CompletedView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.willowtreeapps.common.ui
22

33

4-
interface CompletedView : LibraryView {
4+
interface CompletedView : LibraryView, PresenterProvider {
55
fun showLoading()
66
fun hideLoading()
77
fun showError(msg: String)

common/src/commonMain/kotlin/com/willowtreeapps/common/ui/PresenterFactory.kt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import org.reduxkotlin.*
99
import kotlin.coroutines.CoroutineContext
1010
import kotlin.reflect.KClass
1111

12-
interface LibraryView: View<AppState>
12+
interface LibraryView: ViewWithProvider<AppState>
13+
interface BaseLibraryView: View<AppState>
1314

1415
fun testMiddleware(store: Store): (Dispatcher) -> Dispatcher {
1516
return { next: Dispatcher ->
@@ -51,11 +52,11 @@ class PresenterFactory(private val libraryApp: LibraryApp,
5152

5253
fun <T : LibraryView> attachView(view: T) {
5354
Logger.d("AttachView: $view", Logger.Category.LIFECYCLE)
54-
view.dispatch = libraryApp.store.dispatch
55+
view.dispatch = libraryApp::dispatch
5556
if (subscription == null) {
5657
subscription = libraryApp.store.subscribe(this::onStateChange)
5758
}
58-
val tmp = view.presenter()//getPresenterBuilder(viewClass)//(view)(libraryApp.appStore)
59+
val tmp = view.presenter()
5960
val subscriber = tmp(view)(libraryApp.store)
6061
//call subscriber to trigger initial view update
6162
subscriber()
@@ -66,7 +67,7 @@ class PresenterFactory(private val libraryApp: LibraryApp,
6667
Logger.d("DetachView: $view", Logger.Category.LIFECYCLE)
6768
subscribers.remove(view)
6869

69-
if (hasAttachedViews()) {
70+
if (!hasAttachedViews()) {
7071
subscription?.invoke()
7172
subscription = null
7273
}
@@ -75,8 +76,13 @@ class PresenterFactory(private val libraryApp: LibraryApp,
7576
private fun hasAttachedViews() = subscribers.isNotEmpty()
7677

7778
private fun onStateChange() {
79+
Logger.d("PresenterFactory::onStateChanged!")
7880
launch {
79-
subscribers.forEach { it.value() }
81+
Logger.d("subscribers.size: ${subscribers.size}")
82+
subscribers.forEach {
83+
Logger.d("Subscriber: ${it.key} + ${it.value}")
84+
it.value()
85+
}
8086
}
8187
}
8288

@@ -92,9 +98,15 @@ interface LibraryProvider {
9298
*/
9399
interface View<S : Any> {
94100
var dispatch: Dispatcher
95-
var selectorBuilder: SelectorSubscriberBuilder<S>
101+
var selectorBuilder: SelectorSubscriberBuilder<S>?
102+
}
103+
104+
105+
interface PresenterProvider {
96106
fun presenter(): Presenter<View<AppState>> = throw NotImplementedError("Must implement this method to provide a presenterBuilder for ${this::class}")
97107
}
98108

109+
interface ViewWithProvider<S: Any>: View<S>, PresenterProvider
110+
99111
//TODO handle config changes on android where view has been destroyed and must be recreated. Probably
100112
//can be treated as if a new state - wipe out the selector cache and treat as new view?

common/src/commonMain/kotlin/com/willowtreeapps/common/ui/ReadingListPresenter.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const val READING_LIST_TITLE = "Reading List"
66

77
val readingListPresenter = presenter<ReadingListView> {
88
{
9+
910
+{ state.toReadBook }+ { showBooks(state.toReadBook.toBookListViewState(READING_LIST_TITLE)) }
1011

1112
+{ state.isLoadingItems }+ {

0 commit comments

Comments
 (0)