Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 31 additions & 27 deletions app/src/main/kotlin/me/xizzhu/android/joshua/Injection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ object AppModule {
@Singleton
fun provideApp(application: Application): App = application as App

@Provides
@Singleton
fun provideCoroutineDispatcherProvider(): CoroutineDispatcherProvider = DefaultCoroutineDispatcherProvider()

@Provides
@Singleton
fun provideAppScope(): CoroutineScope = appScope
Expand All @@ -57,67 +61,67 @@ object AppModule {
highlightRepository: VerseAnnotationRepository<Highlight>,
noteRepository: VerseAnnotationRepository<Note>,
readingProgressRepository: ReadingProgressRepository): BackupManager =
BackupManager(BackupJsonSerializer(), bookmarkRepository, highlightRepository, noteRepository, readingProgressRepository)
BackupManager(BackupJsonSerializer(), bookmarkRepository, highlightRepository, noteRepository, readingProgressRepository)

@Provides
@Singleton
fun provideBibleReadingManager(
bibleReadingRepository: BibleReadingRepository,
translationRepository: TranslationRepository,
appScope: CoroutineScope
bibleReadingRepository: BibleReadingRepository,
translationRepository: TranslationRepository,
appScope: CoroutineScope
): BibleReadingManager = BibleReadingManager(bibleReadingRepository, translationRepository, appScope)

@Provides
@Singleton
fun provideBookmarkManager(bookmarkRepository: VerseAnnotationRepository<Bookmark>): VerseAnnotationManager<Bookmark> =
VerseAnnotationManager(bookmarkRepository)
VerseAnnotationManager(bookmarkRepository)

@Provides
@Singleton
fun provideCrossReferencesManager(crossReferencesRepository: CrossReferencesRepository): CrossReferencesManager =
CrossReferencesManager(crossReferencesRepository)
CrossReferencesManager(crossReferencesRepository)

@Provides
@Singleton
fun provideHighlightManager(highlightRepository: VerseAnnotationRepository<Highlight>): VerseAnnotationManager<Highlight> =
VerseAnnotationManager(highlightRepository)
VerseAnnotationManager(highlightRepository)

@Provides
@Singleton
fun provideNoteManager(noteRepository: VerseAnnotationRepository<Note>): VerseAnnotationManager<Note> =
VerseAnnotationManager(noteRepository)
VerseAnnotationManager(noteRepository)

@Provides
@Singleton
fun provideReadingProgressManager(
bibleReadingRepository: BibleReadingRepository,
readingProgressRepository: ReadingProgressRepository,
appScope: CoroutineScope
bibleReadingRepository: BibleReadingRepository,
readingProgressRepository: ReadingProgressRepository,
appScope: CoroutineScope
): ReadingProgressManager = ReadingProgressManager(bibleReadingRepository, readingProgressRepository, appScope)

@Provides
@Singleton
fun provideSearchManager(
bibleReadingRepository: BibleReadingRepository,
bookmarkRepository: VerseAnnotationRepository<Bookmark>,
highlightRepository: VerseAnnotationRepository<Highlight>,
noteRepository: VerseAnnotationRepository<Note>
bibleReadingRepository: BibleReadingRepository,
bookmarkRepository: VerseAnnotationRepository<Bookmark>,
highlightRepository: VerseAnnotationRepository<Highlight>,
noteRepository: VerseAnnotationRepository<Note>
): SearchManager = SearchManager(bibleReadingRepository, bookmarkRepository, highlightRepository, noteRepository)

@Provides
@Singleton
fun provideSettingsManager(settingsRepository: SettingsRepository): SettingsManager =
SettingsManager(settingsRepository)
SettingsManager(settingsRepository)

@Provides
@Singleton
fun provideStrongNumberManager(strongNumberRepository: StrongNumberRepository): StrongNumberManager =
StrongNumberManager(strongNumberRepository)
StrongNumberManager(strongNumberRepository)

@Provides
@Singleton
fun provideTranslationManager(translationRepository: TranslationRepository): TranslationManager =
TranslationManager(translationRepository)
TranslationManager(translationRepository)
}

@Module
Expand All @@ -130,45 +134,45 @@ object RepositoryModule {
@Provides
@Singleton
fun provideBibleReadingRepository(androidDatabase: AndroidDatabase, appScope: CoroutineScope): BibleReadingRepository =
BibleReadingRepository(AndroidReadingStorage(androidDatabase), appScope)
BibleReadingRepository(AndroidReadingStorage(androidDatabase), appScope)

@Provides
@Singleton
fun provideBookmarkRepository(androidDatabase: AndroidDatabase, appScope: CoroutineScope): VerseAnnotationRepository<Bookmark> =
VerseAnnotationRepository(AndroidBookmarkStorage(androidDatabase), appScope)
VerseAnnotationRepository(AndroidBookmarkStorage(androidDatabase), appScope)

@Provides
@Singleton
fun provideCrossReferencesRepository(app: App, androidDatabase: AndroidDatabase): CrossReferencesRepository =
CrossReferencesRepository(AndroidCrossReferencesStorage(androidDatabase), HttpCrossReferencesService(app))
CrossReferencesRepository(AndroidCrossReferencesStorage(androidDatabase), HttpCrossReferencesService(app))

@Provides
@Singleton
fun provideHighlightRepository(androidDatabase: AndroidDatabase, appScope: CoroutineScope): VerseAnnotationRepository<Highlight> =
VerseAnnotationRepository(AndroidHighlightStorage(androidDatabase), appScope)
VerseAnnotationRepository(AndroidHighlightStorage(androidDatabase), appScope)

@Provides
@Singleton
fun provideNoteRepository(androidDatabase: AndroidDatabase, appScope: CoroutineScope): VerseAnnotationRepository<Note> =
VerseAnnotationRepository(AndroidNoteStorage(androidDatabase), appScope)
VerseAnnotationRepository(AndroidNoteStorage(androidDatabase), appScope)

@Provides
@Singleton
fun provideReadingProgressRepository(androidDatabase: AndroidDatabase): ReadingProgressRepository =
ReadingProgressRepository(AndroidReadingProgressStorage(androidDatabase))
ReadingProgressRepository(AndroidReadingProgressStorage(androidDatabase))

@Provides
@Singleton
fun provideSettingsRepository(androidDatabase: AndroidDatabase, appScope: CoroutineScope): SettingsRepository =
SettingsRepository(AndroidSettingsStorage(androidDatabase), appScope)
SettingsRepository(AndroidSettingsStorage(androidDatabase), appScope)

@Provides
@Singleton
fun provideStrongNumberRepository(app: App, androidDatabase: AndroidDatabase): StrongNumberRepository =
StrongNumberRepository(AndroidStrongNumberStorage(androidDatabase), HttpStrongNumberService(app))
StrongNumberRepository(AndroidStrongNumberStorage(androidDatabase), HttpStrongNumberService(app))

@Provides
@Singleton
fun provideTranslationRepository(app: App, androidDatabase: AndroidDatabase, appScope: CoroutineScope): TranslationRepository =
TranslationRepository(AndroidTranslationStorage(androidDatabase), HttpTranslationService(app), appScope)
TranslationRepository(AndroidTranslationStorage(androidDatabase), HttpTranslationService(app), appScope)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 Xizhi Zhu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package me.xizzhu.android.joshua.core

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

interface CoroutineDispatcherProvider {
val main: CoroutineDispatcher
val default: CoroutineDispatcher
val io: CoroutineDispatcher
val unconfined: CoroutineDispatcher
}

class DefaultCoroutineDispatcherProvider : CoroutineDispatcherProvider {
override val main: CoroutineDispatcher
get() = Dispatchers.Main

override val default: CoroutineDispatcher
get() = Dispatchers.Default

override val io: CoroutineDispatcher
get() = Dispatchers.IO

override val unconfined: CoroutineDispatcher
get() = Dispatchers.Unconfined
}
105 changes: 105 additions & 0 deletions app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivityV2.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2022 Xizhi Zhu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package me.xizzhu.android.joshua.infra

import android.os.Bundle
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import me.xizzhu.android.joshua.Navigator
import me.xizzhu.android.logger.Log
import javax.inject.Inject

abstract class BaseActivityV2<VB : ViewBinding, ViewAction, ViewState, VM : BaseViewModelV2<ViewAction, ViewState>> : AppCompatActivity() {
protected val tag: String = javaClass.simpleName

@Inject
protected lateinit var navigator: Navigator

protected lateinit var viewBinding: VB

protected abstract fun inflateViewBinding(): VB

protected abstract fun viewModel(): VM

protected abstract fun onViewActionEmitted(viewAction: ViewAction)

protected abstract fun onViewStateUpdated(viewState: ViewState)

@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i(tag, "onCreate()")

viewBinding = inflateViewBinding()
setContentView(viewBinding.root)

viewModel().viewAction().onEach(::onViewActionEmitted).launchIn(lifecycleScope)
viewModel().viewState().onEach(::onViewStateUpdated).launchIn(lifecycleScope)
}

@CallSuper
override fun onStart() {
super.onStart()
Log.i(tag, "onStart()")
}

@CallSuper
override fun onResume() {
super.onResume()
Log.i(tag, "onResume()")
}

@CallSuper
override fun onPause() {
super.onPause()
Log.i(tag, "onPause()")
}

@CallSuper
override fun onStop() {
super.onStop()
Log.i(tag, "onStop()")
}

@CallSuper
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Log.i(tag, "onSaveInstanceState()")
}

@CallSuper
override fun onDestroy() {
super.onDestroy()
Log.i(tag, "onDestroy()")
}

@CallSuper
override fun onLowMemory() {
super.onLowMemory()
Log.i(tag, "onLowMemory()")
}

@CallSuper
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
Log.i(tag, "onTrimMemory(): level - $level")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 Xizhi Zhu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package me.xizzhu.android.joshua.infra

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

abstract class BaseViewModelV2<ViewAction, ViewState>(initialViewState: ViewState) : ViewModel() {
protected val tag: String = javaClass.simpleName

private val viewAction: MutableSharedFlow<ViewAction> = MutableSharedFlow()
private val viewState: MutableStateFlow<ViewState> = MutableStateFlow(initialViewState)

fun viewAction(): Flow<ViewAction> = viewAction

fun emitViewAction(action: ViewAction) {
viewModelScope.launch { viewAction.emit(action) }
}

fun viewState(): StateFlow<ViewState> = viewState

protected fun updateViewState(block: (currentViewState: ViewState) -> ViewState?) {
viewState.update { block(it) ?: it }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,33 @@ import me.xizzhu.android.joshua.ui.recyclerview.BaseItem
import me.xizzhu.android.joshua.utils.firstNotEmpty
import java.util.ArrayList

class PreviewViewData(val settings: Settings, val title: String, val items: List<BaseItem>, val currentPosition: Int)
data class PreviewViewData(val settings: Settings, val title: String, val items: List<BaseItem>, val currentPosition: Int)

fun loadPreview(
bibleReadingManager: BibleReadingManager,
settingsManager: SettingsManager,
verseIndex: VerseIndex,
converter: List<Verse>.() -> List<BaseItem>
): Flow<BaseViewModel.ViewData<PreviewViewData>> = viewData {
loadPreviewV2(bibleReadingManager, settingsManager, verseIndex, converter)
}

suspend fun loadPreviewV2(
bibleReadingManager: BibleReadingManager,
settingsManager: SettingsManager,
verseIndex: VerseIndex,
converter: List<Verse>.() -> List<BaseItem>
): PreviewViewData {
if (!verseIndex.isValid()) {
throw IllegalArgumentException("Verse index [$verseIndex] is invalid")
}

val currentTranslation = bibleReadingManager.currentTranslation().firstNotEmpty()
PreviewViewData(
settings = settingsManager.settings().first(),
title = "${bibleReadingManager.readBookShortNames(currentTranslation)[verseIndex.bookIndex]}, ${verseIndex.chapterIndex + 1}",
items = converter(bibleReadingManager.readVerses(currentTranslation, verseIndex.bookIndex, verseIndex.chapterIndex)),
currentPosition = verseIndex.verseIndex
return PreviewViewData(
settings = settingsManager.settings().first(),
title = "${bibleReadingManager.readBookShortNames(currentTranslation)[verseIndex.bookIndex]}, ${verseIndex.chapterIndex + 1}",
items = converter(bibleReadingManager.readVerses(currentTranslation, verseIndex.bookIndex, verseIndex.chapterIndex)),
currentPosition = verseIndex.verseIndex
)
}

Expand Down
Loading