Skip to content

Commit

Permalink
Add viewmodels
Browse files Browse the repository at this point in the history
  • Loading branch information
StephaneBg committed Feb 4, 2020
1 parent 374b3e6 commit d159ce5
Show file tree
Hide file tree
Showing 22 changed files with 166 additions and 124 deletions.
1 change: 1 addition & 0 deletions Examples/DemoApp/androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ dependencies {
implementation(Coroutines.android)
implementation(AndroidX.appCompat)
implementation(AndroidX.coreKtx)
implementation(AndroidX.viewModel)
implementation(Libs.koinAndroid)
implementation(Libs.timber)
implementation(Libs.coil)
Expand Down
2 changes: 1 addition & 1 deletion Examples/DemoApp/androidApp/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
tools:ignore="GoogleAppIndexingWarning"
>

<activity android:name=".ui.MainActivity">
<activity android:name=".ui.KomposeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.jtouzy.demo.app.di

import com.jtouzy.demo.app.ui.NavigationManager
import com.jtouzy.demo.app.ui.characters.CharactersViewModel
import com.jtouzy.demo.app.ui.quote.QuoteViewModel
import com.jtouzy.demo.cache.DataStore
import com.jtouzy.demo.cache.InMemoryDataStore
import com.jtouzy.demo.network.BreakingBadApi
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

val appModule = module {

single { NavigationManager() }
single { BreakingBadApi() }
single<DataStore> { InMemoryDataStore(get()) }

viewModel { CharactersViewModel(get()) }
viewModel { QuoteViewModel(get()) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ import androidx.compose.Composable
import androidx.ui.core.setContent
import androidx.ui.material.MaterialTheme
import com.jtouzy.demo.app.ui.characters.CharactersScreen
import com.jtouzy.demo.app.ui.characters.CharactersViewModel
import com.jtouzy.demo.app.ui.common.themeColors
import com.jtouzy.demo.app.ui.quote.QuoteScreen
import com.jtouzy.demo.cache.DataStore
import com.jtouzy.demo.app.ui.quote.QuoteViewModel
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel

class MainActivity : AppCompatActivity() {
class KomposeActivity : AppCompatActivity() {

private val navigationManager by inject<NavigationManager>()
private val dataStore by inject<DataStore>()
private val charactersViewModel by viewModel<CharactersViewModel>()
private val quoteViewModel by viewModel<QuoteViewModel>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -29,8 +32,8 @@ class MainActivity : AppCompatActivity() {
private fun KomposeApp() {
MaterialTheme(colors = themeColors) {
when (val screen = navigationManager.currentScreen) {
Screen.Home -> CharactersScreen.show(navigationManager, dataStore)
is Screen.Quote -> QuoteScreen.show(navigationManager, dataStore, screen.character)
Screen.Home -> CharactersScreen(navigationManager, charactersViewModel).MainScreen()
is Screen.Quote -> QuoteScreen(navigationManager, quoteViewModel).MainScreen(screen.character)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,25 @@ import androidx.ui.material.ripple.Ripple
import androidx.ui.res.stringResource
import com.jtouzy.demo.app.R
import com.jtouzy.demo.app.ui.NavigationManager
import com.jtouzy.demo.app.ui.ObservableStore
import com.jtouzy.demo.app.ui.Screen
import com.jtouzy.demo.app.ui.common.ErrorScreen
import com.jtouzy.demo.app.ui.common.LoadingScreen
import com.jtouzy.demo.app.ui.common.VectorImage
import com.jtouzy.demo.app.ui.common.image
import com.jtouzy.demo.cache.DataStore
import com.jtouzy.demo.ui.Store
import com.jtouzy.demo.ui.characters.CharactersPresenter
import com.jtouzy.demo.ui.characters.CharactersPresenterImpl
import com.jtouzy.demo.ui.characters.CharactersViewState
import com.jtouzy.demo.ui.model.Character

class CharactersScreen(
private val navigationManager: NavigationManager,
private val store: Store<CharactersViewState>,
presenter: CharactersPresenter
private val viewModel: CharactersViewModel
) {

init {
presenter.loadCharacters()
}

@Composable
private fun MainScreen() {
fun MainScreen() {
viewModel.loadCharacters()
Column {
TopAppBar(title = { Text(text = +stringResource(R.string.app_name)) })
Crossfade(store.viewState) { state ->
Crossfade(viewModel.viewState) { state ->
when (state) {
CharactersViewState.Loading -> LoadingScreen()
is CharactersViewState.Content -> CharacterList(state.characters)
Expand Down Expand Up @@ -92,12 +83,4 @@ class CharactersScreen(
}
}
}

companion object {
fun show(navigationManager: NavigationManager, dataStore: DataStore) {
val store = ObservableStore<CharactersViewState>(CharactersViewState.Loading)
val presenter = CharactersPresenterImpl(store, dataStore)
CharactersScreen(navigationManager, store, presenter).MainScreen()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.jtouzy.demo.app.ui.characters

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.jtouzy.demo.app.ui.ObservableStore
import com.jtouzy.demo.cache.DataStore
import com.jtouzy.demo.ui.characters.CharactersUseCase
import com.jtouzy.demo.ui.characters.CharactersViewState
import kotlinx.coroutines.launch

class CharactersViewModel(dataStore: DataStore) : ViewModel() {

val viewState: CharactersViewState
get() = store.viewState
private val store = ObservableStore<CharactersViewState>(CharactersViewState.Loading)
private val useCase = CharactersUseCase(store, dataStore)

fun loadCharacters() {
viewModelScope.launch {
useCase.asyncLoadCharacters()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,31 @@ import androidx.ui.material.TopAppBar
import androidx.ui.res.stringResource
import com.jtouzy.demo.app.R
import com.jtouzy.demo.app.ui.NavigationManager
import com.jtouzy.demo.app.ui.ObservableStore
import com.jtouzy.demo.app.ui.common.ErrorScreen
import com.jtouzy.demo.app.ui.common.LoadingScreen
import com.jtouzy.demo.app.ui.common.VectorImageButton
import com.jtouzy.demo.cache.DataStore
import com.jtouzy.demo.ui.Store
import com.jtouzy.demo.ui.model.Character
import com.jtouzy.demo.ui.model.Quote
import com.jtouzy.demo.ui.quotes.QuotesPresenter
import com.jtouzy.demo.ui.quotes.QuotesPresenterImpl
import com.jtouzy.demo.ui.quotes.QuotesViewState

class QuoteScreen(
private val navigationManager: NavigationManager,
private val store: Store<QuotesViewState>,
presenter: QuotesPresenter
private val viewModel: QuoteViewModel
) {

init {
presenter.loadQuotes()
}

@Composable
private fun MainScreen() {
fun MainScreen(character: Character) {
viewModel.loadQuote(character)
Column {
TopAppBar(
title = { Text(store.viewState.title) },
title = { Text(viewModel.viewState.title) },
navigationIcon = {
VectorImageButton(R.drawable.ic_back) {
navigationManager.pop()
}
}
)
Crossfade(store.viewState) { state ->
Crossfade(viewModel.viewState) { state ->
when (state) {
is QuotesViewState.Loading -> LoadingScreen()
is QuotesViewState.Content -> QuoteList(state.quotes)
Expand Down Expand Up @@ -87,12 +78,4 @@ class QuoteScreen(
Divider(color = (+MaterialTheme.colors()).onBackground)
}
}

companion object {
fun show(navigationManager: NavigationManager, dataStore: DataStore, character: Character) {
val store = ObservableStore<QuotesViewState>(QuotesViewState.Loading(character.name))
val presenter = QuotesPresenterImpl(store, dataStore, character)
QuoteScreen(navigationManager, store, presenter).MainScreen()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.jtouzy.demo.app.ui.quote

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.jtouzy.demo.app.ui.ObservableStore
import com.jtouzy.demo.cache.DataStore
import com.jtouzy.demo.ui.model.Character
import com.jtouzy.demo.ui.quotes.QuotesUseCase
import com.jtouzy.demo.ui.quotes.QuotesViewState
import kotlinx.coroutines.launch

class QuoteViewModel(dataStore: DataStore) : ViewModel() {

val viewState: QuotesViewState
get() = store.viewState
private val store = ObservableStore<QuotesViewState>(QuotesViewState.Loading(""))
private val useCase = QuotesUseCase(store, dataStore)

fun loadQuote(character: Character) {
viewModelScope.launch {
useCase.asyncLoadQuotes(character)
}
}
}
2 changes: 2 additions & 0 deletions Examples/DemoApp/buildSrc/src/main/kotlin/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ object AndroidX {
private object Versions {
const val appCompat = "1.1.0"
const val coreKtx = "1.1.0"
const val viewModel = "2.1.0-beta01"
const val compose = "0.1.0-dev03"
}

const val appCompat = "androidx.appcompat:appcompat:${Versions.appCompat}"
const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}"
const val viewModel = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.viewModel}"

const val composeFoundation = "androidx.ui:ui-foundation:${Versions.compose}"
const val composeFramework = "androidx.ui:ui-framework:${Versions.compose}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import shared
class CharactersAssembler {
static func assemble() -> CharactersView {
let store = ObservableStore<CharactersViewState>(baseState: CharactersViewState.Loading())
let presenter = CharactersPresenterImpl(store: store, dataStore: Factory.dataStore)
return CharactersView(presenter: presenter, store: store)
let useCase = CharactersUseCase(store: store, dataStore: Factory.dataStore)
return CharactersView(useCase: useCase, store: store)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import shared
// MARK: View Layout
//
struct CharactersView: View {
let presenter: CharactersPresenter
let useCase: CharactersUseCase
@ObservedObject var store: ObservableStore<CharactersViewState>
var viewState: CharactersViewState { store.state }

Expand Down Expand Up @@ -55,6 +55,6 @@ struct CharactersView: View {
//
extension CharactersView {
func onViewAppear() {
presenter.loadCharacters()
useCase.loadCharacters()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class QuotesAssembler {
let store = ObservableStore<QuotesViewState>(
baseState: QuotesViewState.Loading(title: character.name)
)
let presenter = QuotesPresenterImpl(
store: store, dataStore: Factory.dataStore, character: character
let useCase = QuotesUseCase(
store: store, dataStore: Factory.dataStore
)
return QuotesView(presenter: presenter, store: store)
return QuotesView(useCase: useCase, store: store, character: character)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import shared
// MARK: View Layout
//
struct QuotesView: View {
let presenter: QuotesPresenter
let useCase: QuotesUseCase
@ObservedObject var store: ObservableStore<QuotesViewState>
let character: Character
var viewState: QuotesViewState { store.state }

var body: some View {
Expand Down Expand Up @@ -57,6 +58,6 @@ struct QuotesView: View {
//
extension QuotesView {
func onViewAppear() {
presenter.loadQuotes()
useCase.loadQuotes(character)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.jtouzy.demo.ui.characters

interface CharactersInteractor {
suspend fun asyncLoadCharacters()
fun loadCharacters()
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class CharactersPresenterImpl(
class CharactersUseCase(
private val store: Store<CharactersViewState>,
private val dataStore: DataStore
) : CharactersPresenter {
) : CharactersInteractor {

override suspend fun asyncLoadCharacters() {
store.viewState = CharactersViewState.Loading
try {
val characters = withContext(ioDispatcher) { dataStore.getCharacters() }
store.viewState = CharactersViewState.Content(characters.map { Character(it) })
} catch (exception: Exception) {
store.viewState = CharactersViewState.Error
}
}

override fun loadCharacters() {
GlobalScope.launch(mainDispatcher) {
store.viewState = CharactersViewState.Loading
try {
val characters = withContext(ioDispatcher) { dataStore.getCharacters() }
store.viewState = CharactersViewState.Content(characters.map { Character(it) })
} catch (exception: Exception) {
store.viewState = CharactersViewState.Error
}
loadCharacters()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.jtouzy.demo.ui.quotes

import com.jtouzy.demo.ui.model.Character

interface QuotesInteractor {
suspend fun asyncLoadQuotes(character: Character)
fun loadQuotes(character: Character)
}

This file was deleted.

Loading

0 comments on commit d159ce5

Please sign in to comment.