Skip to content

Commit

Permalink
Merge pull request #4 from Merseyside/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Merseyside authored Dec 12, 2021
2 parents 122f67b + b4bb66f commit 6962e11
Show file tree
Hide file tree
Showing 56 changed files with 557 additions and 1,074 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ on:
jobs:
publish:
name: Release build and publish
runs-on: macos-latest
runs-on: macos-11
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up JDK 1.8
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 1.8
java-version: 1.11

- name: Build and publish to mavenCentral
run: ./gradlew publish
Expand Down
14 changes: 4 additions & 10 deletions archy-android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
`android-convention`
id(Plugins.kotlinAndroid)
id(Plugins.androidConvention)
id(Plugins.kotlinConvention)
id(Plugins.kotlinKapt)
id(Plugins.navigationArgs)
`maven-publish-config`
}

Expand All @@ -13,12 +12,6 @@ android {
}
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xinline-classes", "-Xopt-in=org.mylibrary.OptInAnnotation")
}
}

val androidLibraries = listOf(
common.serialization,
androidLibs.appCompat,
Expand Down Expand Up @@ -49,6 +42,7 @@ dependencies {
}

androidLibraries.forEach { lib -> implementation(lib) }
implementation(androidLibs.bundles.navigation)
}

afterEvaluate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,12 @@ import com.merseyside.utils.reflection.ReflectionUtils
import com.merseyside.utils.requestPermissions
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import org.koin.androidx.scope.activityScope
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.scope.getViewModel
import org.koin.core.component.KoinScopeComponent
import org.koin.core.parameter.parametersOf
import org.koin.core.scope.Scope
import kotlin.reflect.KClass

abstract class BaseVMActivity<B : ViewDataBinding, M : BaseViewModel>
: BaseBindingActivity<B>(), KoinScopeComponent {
: BaseBindingActivity<B>() {

override val scope: Scope by activityScope()

protected lateinit var viewModel: M
protected abstract val viewModel: M

private val messageObserver = { message: BaseViewModel.TextMessage? ->
if (message != null) {
Expand All @@ -35,17 +27,13 @@ abstract class BaseVMActivity<B : ViewDataBinding, M : BaseViewModel>
} else {
showMsg(message)
}

viewModel.messageLiveEvent.value = null
}
}

private val loadingObserver = { isLoading: Boolean -> this.loadingObserver(isLoading) }
private val alertDialogModel = { model: BaseViewModel.AlertDialogModel? ->
model?.apply {
showAlertDialog(title, message, positiveButtonText, negativeButtonText, onPositiveClick, onNegativeClick, isCancelable)

viewModel.alertDialogLiveEvent.value = null
}

Unit
Expand All @@ -66,14 +54,6 @@ abstract class BaseVMActivity<B : ViewDataBinding, M : BaseViewModel>
observeViewModel()
}

override fun performInjection(bundle: Bundle?, vararg params: Any) {
viewModel = scope.getViewModel(
owner = { ViewModelOwner.from(this)},
clazz = persistentClass,
parameters = { parametersOf(*params, bundle) }
)
}

abstract fun getBindingVariable(): Int

private fun setBindingVariable() {
Expand All @@ -100,10 +80,10 @@ abstract class BaseVMActivity<B : ViewDataBinding, M : BaseViewModel>

private fun observeViewModel() {
viewModel.apply {
messageLiveEvent.addObserver(messageObserver)
isInProgress.addObserver(loadingObserver)
alertDialogLiveEvent.addObserver(alertDialogModel)
grantPermissionLiveEvent.addObserver(permissionObserver)
messageLiveEvent.ld().observe(this@BaseVMActivity, messageObserver)
isInProgress.ld().observe(this@BaseVMActivity, loadingObserver)
alertDialogLiveEvent.ld().observe(this@BaseVMActivity, alertDialogModel)
grantPermissionLiveEvent.ld().observe(this@BaseVMActivity, permissionObserver)
}
}

Expand Down Expand Up @@ -133,6 +113,11 @@ abstract class BaseVMActivity<B : ViewDataBinding, M : BaseViewModel>
}
}

internal val persistentClass: KClass<M> =
ReflectionUtils.getGenericParameterClass(this.javaClass, BaseVMActivity::class.java, 1).kotlin as KClass<M>
protected fun getPersistentClass(): KClass<M> {
return ReflectionUtils.getGenericParameterClass(
this.javaClass,
BaseVMActivity::class.java,
1
).kotlin as KClass<M>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import android.view.ViewGroup
import androidx.databinding.ViewDataBinding
import com.merseyside.archy.presentation.dialog.BaseBindingDialog
import com.merseyside.merseyLib.archy.core.presentation.model.BaseViewModel
import com.merseyside.merseyLib.archy.android.presentation.fragment.BaseVMFragment
import com.merseyside.utils.reflection.ReflectionUtils
import org.koin.androidx.viewmodel.ext.android.getViewModel
import org.koin.core.parameter.parametersOf
import kotlin.reflect.KClass

abstract class BaseVMDialog<B : ViewDataBinding, M : BaseViewModel> : BaseBindingDialog<B>() {
Expand All @@ -32,8 +29,6 @@ abstract class BaseVMDialog<B : ViewDataBinding, M : BaseViewModel> : BaseBindin
} else {
showMsg(it)
}

viewModel.messageLiveEvent.value = null
}
Unit
}
Expand All @@ -43,25 +38,15 @@ abstract class BaseVMDialog<B : ViewDataBinding, M : BaseViewModel> : BaseBindin
override fun onCreate(onSavedInstanceState: Bundle?) {
performInjection(onSavedInstanceState)
super.onCreate(onSavedInstanceState)

setHasOptionsMenu(false)
}

override fun performInjection(bundle: Bundle?, vararg params: Any) {
requireParentFragment().getViewModel(
clazz = persistentClass,
parameters = { parametersOf(*params, bundle) }
)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)

requireBinding().apply {
setVariable(getBindingVariable(), viewModel)
executePendingBindings()
}

return dialog
}

Expand All @@ -70,12 +55,10 @@ abstract class BaseVMDialog<B : ViewDataBinding, M : BaseViewModel> : BaseBindin
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {

viewModel.apply {
errorLiveEvent.addObserver(errorObserver)
messageLiveEvent.addObserver(messageObserver)
errorLiveEvent.ld().observe(this@BaseVMDialog, errorObserver)
messageLiveEvent.ld().observe(this@BaseVMDialog, messageObserver)
}

return super.onCreateView(inflater, container, savedInstanceState)
}

Expand All @@ -95,6 +78,12 @@ abstract class BaseVMDialog<B : ViewDataBinding, M : BaseViewModel> : BaseBindin
}
}

private val persistentClass: KClass<M> =
ReflectionUtils.getGenericParameterClass(this.javaClass, BaseVMFragment::class.java, 1).kotlin as KClass<M>
protected open fun getPersistentClass(): KClass<M> {
return ReflectionUtils.getGenericParameterClass(
this.javaClass,
BaseVMDialog::class.java,
1
).kotlin as KClass<M>
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,23 @@ import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModel
import com.merseyside.archy.presentation.fragment.BaseBindingFragment
import com.merseyside.merseyLib.archy.core.presentation.model.BaseViewModel
import com.merseyside.merseyLib.archy.core.presentation.model.StateViewModel
import com.merseyside.merseyLib.archy.core.presentation.model.StateViewModel.Companion.INSTANCE_STATE_KEY
import com.merseyside.merseyLib.utils.core.SavedState
import com.merseyside.utils.ext.log
import com.merseyside.utils.ext.putSerialize
import com.merseyside.utils.reflection.ReflectionUtils
import com.merseyside.utils.requestPermissions
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import org.koin.androidx.scope.fragmentScope
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.scope.getViewModel
import org.koin.core.component.KoinScopeComponent
import org.koin.core.parameter.parametersOf
import org.koin.core.scope.Scope
import kotlin.reflect.KClass

abstract class BaseVMFragment<B : ViewDataBinding, M : BaseViewModel>
: BaseBindingFragment<B>(), KoinScopeComponent {
: BaseBindingFragment<B>() {

override val scope: Scope by fragmentScope()

protected lateinit var viewModel: M
protected abstract val viewModel: M

private val messageObserver = { message: BaseViewModel.TextMessage? ->
if (message != null) {
Expand All @@ -37,7 +29,6 @@ abstract class BaseVMFragment<B : ViewDataBinding, M : BaseViewModel>
} else {
showMsg(message)
}
viewModel.messageLiveEvent.value = null
}
}

Expand All @@ -47,14 +38,22 @@ abstract class BaseVMFragment<B : ViewDataBinding, M : BaseViewModel>
}
}

private val progressObserver = { isLoading: Boolean ->
this.loadingObserver(isLoading)
private val progressObserver = { isLoading: Boolean? ->
this.loadingObserver(isLoading ?: false)
}

private val alertDialogModelObserver = { model: BaseViewModel.AlertDialogModel? ->
model?.apply {
showAlertDialog(title, message, positiveButtonText, negativeButtonText, onPositiveClick, onNegativeClick, isSingleAction, isCancelable)
viewModel.alertDialogLiveEvent.value = null
showAlertDialog(
title,
message,
positiveButtonText,
negativeButtonText,
onPositiveClick,
onNegativeClick,
isSingleAction,
isCancelable
)
}
Unit
}
Expand All @@ -67,32 +66,30 @@ abstract class BaseVMFragment<B : ViewDataBinding, M : BaseViewModel>

abstract fun getBindingVariable(): Int

open fun initDataBinding(): ViewDataBinding.() -> Unit {
return {
setVariable(getBindingVariable(), viewModel)
executePendingBindings()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(false)
}

override fun performInjection(bundle: Bundle?, vararg params: Any) {
viewModel = scope.getViewModel(
owner = { ViewModelOwner.from(this)},
clazz = persistentClass,
parameters = { parametersOf(*params, bundle) }
)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

requireBinding().apply {
setVariable(getBindingVariable(), viewModel)
executePendingBindings()
initDataBinding().invoke(this)
}

viewModel.apply {
errorLiveEvent.addObserver(errorObserver)
messageLiveEvent.addObserver(messageObserver)
isInProgress.addObserver(progressObserver)
alertDialogLiveEvent.addObserver(alertDialogModelObserver)
grantPermissionLiveEvent.addObserver(permissionObserver)
errorLiveEvent.ld().observe(viewLifecycleOwner, errorObserver)
messageLiveEvent.ld().observe(viewLifecycleOwner, messageObserver)
isInProgress.ld().observe(viewLifecycleOwner, progressObserver)
alertDialogLiveEvent.ld().observe(viewLifecycleOwner, alertDialogModelObserver)
grantPermissionLiveEvent.ld().observe(viewLifecycleOwner, permissionObserver)
}

super.onViewCreated(view, savedInstanceState)
Expand All @@ -105,8 +102,10 @@ abstract class BaseVMFragment<B : ViewDataBinding, M : BaseViewModel>
val bundle = SavedState()

(viewModel as StateViewModel).onSaveState(bundle)
outState.putSerialize(INSTANCE_STATE_KEY, bundle.getAll(),
MapSerializer(String.serializer(), String.serializer()))
outState.putSerialize(
INSTANCE_STATE_KEY, bundle.getAll(),
MapSerializer(String.serializer(), String.serializer())
)
}
}

Expand Down Expand Up @@ -153,6 +152,11 @@ abstract class BaseVMFragment<B : ViewDataBinding, M : BaseViewModel>
}
}

internal val persistentClass: KClass<M> =
ReflectionUtils.getGenericParameterClass(this.javaClass, BaseVMFragment::class.java, 1).kotlin as KClass<M>
protected fun <M : ViewModel> getViewModelClass(): KClass<M> {
return ReflectionUtils.getGenericParameterClass(
this.javaClass,
BaseVMFragment::class.java,
1
).kotlin as KClass<M>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.merseyside.merseyLib.archy.android.utils

import androidx.annotation.IdRes
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.navigation.NavBackStackEntry
import androidx.navigation.fragment.findNavController
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.scope.getViewModel
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.component.KoinComponent
import org.koin.core.context.GlobalContext
import org.koin.core.scope.Scope
import kotlin.reflect.KClass

fun <VM : ViewModel> Fragment.navGraphViewModel(
@IdRes navGraphId: Int,
clazz: KClass<VM>
): VM {
val backStackEntry: NavBackStackEntry by lazy { findNavController().getBackStackEntry(navGraphId) }
return getKoinScope(this).getViewModel(
owner = { ViewModelOwner(backStackEntry.viewModelStore) },
clazz = clazz
)
}

@OptIn(KoinInternalApi::class)
fun getKoinScope(any: Any): Scope {
return when (any) {
is KoinComponent -> any.getKoin().scopeRegistry.rootScope
else -> GlobalContext.get().scopeRegistry.rootScope
}
}
Loading

0 comments on commit 6962e11

Please sign in to comment.