Skip to content
This repository has been archived by the owner on Aug 19, 2023. It is now read-only.

Commit

Permalink
Include external dependency mvp-bakery directly
Browse files Browse the repository at this point in the history
  • Loading branch information
d4rken committed Oct 11, 2021
1 parent 66abd11 commit 4383a56
Show file tree
Hide file tree
Showing 33 changed files with 713 additions and 40 deletions.
39 changes: 6 additions & 33 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,17 @@ android {
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.0"
implementation project(':library-mvp-bakery')

// Support libs
implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.annotation:annotation:1.2.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'

// MVP lib
implementation 'eu.darken.mvpbakery:library:0.7.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'

// RX
implementation "io.reactivex.rxjava2:rxjava:2.2.17"
implementation "io.reactivex.rxjava2:rxjava:2.2.21"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"

//Dagger
Expand All @@ -103,27 +99,4 @@ dependencies {
implementation "com.jakewharton.timber:timber:4.7.1"

implementation 'com.github.tbruyelle:rxpermissions:0.10.2'

// Testing
testImplementation "junit:junit:4.13"
testImplementation "org.mockito:mockito-core:3.0.0"
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0'
testImplementation 'com.github.tmurakami:dexopener:1.0.2'

androidTestImplementation "org.mockito:mockito-core:3.0.0"
androidTestImplementation 'org.mockito:mockito-android:2.23.0'
androidTestImplementation 'com.github.tmurakami:dexopener:1.0.2'

androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0'
androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.2.0'
}

kotlin {
experimental {

}
}
14 changes: 8 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ buildscript {
'compileSdk': 30,
'minSdk' : 16,
'targetSdk' : 30,

'deps' : [
'dagger': '2.21',
],
'version' : [
'major': 3,
'minor': 3,
Expand All @@ -16,21 +18,21 @@ buildscript {
ext.buildConfig.version['fullName'] = "${buildConfig.version.name}.${buildConfig.version.build}"
ext.buildConfig.version['code'] = buildConfig.version.major * 1000000 + buildConfig.version.minor * 10000 + buildConfig.version.patch * 100 + buildConfig.version.build


repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0"
classpath 'com.android.tools.build:gradle:7.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
}
}

allprojects {
repositories {
google()
jcenter()

mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
1 change: 1 addition & 0 deletions library-mvp-bakery/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
45 changes: 45 additions & 0 deletions library-mvp-bakery/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
plugins {
id 'com.android.library'
id 'kotlin-android-extensions'
id 'kotlin-android'
}

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion buildConfig.compileSdk

defaultConfig {
minSdkVersion buildConfig.minSdk
targetSdkVersion buildConfig.targetSdk

consumerProguardFiles 'proguard-rules.pro'
}
buildTypes {
debug {
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation "androidx.lifecycle:lifecycle-common:2.3.1"
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

implementation "androidx.annotation:annotation:1.2.0"
implementation "androidx.appcompat:appcompat:1.3.1"
implementation "androidx.preference:preference-ktx:1.1.1"

implementation "com.google.dagger:dagger:${buildConfig.deps.dagger}"
implementation "com.google.dagger:dagger-android:${buildConfig.deps.dagger}"
implementation "com.google.dagger:dagger-android-support:${buildConfig.deps.dagger}"

annotationProcessor "com.google.dagger:dagger-compiler:${buildConfig.deps.dagger}"
annotationProcessor "com.google.dagger:dagger-android-processor:${buildConfig.deps.dagger}"
}
18 changes: 18 additions & 0 deletions library-mvp-bakery/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/darken/android-sdks/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-keep class androidx.lifecycle.** { *; }
5 changes: 5 additions & 0 deletions library-mvp-bakery/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<manifest package="eu.darken.mvpbakery">

<application />

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package eu.darken.mvpbakery.base

import android.app.Activity
import android.app.Fragment
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.LifecycleOwner
import eu.darken.mvpbakery.injection.InjectedPresenter
import java.util.*

class MVPBakery<ViewT : Presenter.View, PresenterT : Presenter<ViewT>> internal constructor(builder: Builder<ViewT, PresenterT>) {
companion object {
@JvmStatic
fun <ViewT : Presenter.View, PresenterT : Presenter<ViewT>> builder(): Builder<ViewT, PresenterT> {
return Builder()
}
}

private val presenterRetainer: PresenterRetainer<ViewT, PresenterT>
private val stateForwarder: StateForwarder?
private val presenterFactory: PresenterFactory<PresenterT>
private val presenterCallbacks: List<PresenterRetainer.Callback<ViewT, PresenterT>>

val presenter: PresenterT?
get() = presenterRetainer.presenter

init {
this.presenterRetainer = builder.presenterRetainer
this.stateForwarder = builder.stateForwarder
this.presenterCallbacks = builder.presenterCallbacks
this.presenterFactory = builder.presenterFactory
}

fun attach(lifecycleOwner: LifecycleOwner) {
if (stateForwarder != null) this.presenterRetainer.stateForwarder = stateForwarder
this.presenterRetainer.presenterFactory = presenterFactory
this.presenterRetainer.attach(lifecycleOwner, object : PresenterRetainer.Callback<ViewT, PresenterT> {
override fun onPresenterAvailable(presenter: PresenterT) {
presenterCallbacks.forEach { it.onPresenterAvailable(presenter) }
}
})
}

class Builder<ViewT, PresenterT : Presenter<ViewT>> internal constructor() where ViewT : Presenter.View, ViewT : LifecycleOwner {
internal lateinit var presenterFactory: PresenterFactory<PresenterT>
internal lateinit var presenterRetainer: PresenterRetainer<ViewT, PresenterT>
internal var stateForwarder: StateForwarder? = null
internal val presenterCallbacks: MutableList<PresenterRetainer.Callback<ViewT, PresenterT>> = ArrayList()

/**
* If you want the presenter to be able to store data via [Activity.onSaveInstanceState] then you need to call this.
*
* @param stateForwarder pass a [object][StateForwarder] that you have to call on in onCreate()/onSaveInstance()
*/
fun stateForwarder(stateForwarder: StateForwarder): Builder<ViewT, PresenterT> {
this.stateForwarder = stateForwarder
return this
}

fun addPresenterCallback(callback: PresenterRetainer.Callback<ViewT, PresenterT>): Builder<ViewT, PresenterT> {
presenterCallbacks.add(callback)
return this
}

/**
* For injection you probably want to pass a [eu.darken.mvpbakery.injection.PresenterInjectionCallback]
*/
fun presenterRetainer(presenterRetainer: PresenterRetainer<ViewT, PresenterT>): Builder<ViewT, PresenterT> {
this.presenterRetainer = presenterRetainer
return this
}

/**
* For injection pass an [InjectedPresenter]
*/
fun presenterFactory(presenterFactory: PresenterFactory<PresenterT>): Builder<ViewT, PresenterT> {
this.presenterFactory = presenterFactory
return this
}

fun build(): MVPBakery<ViewT, PresenterT> {
return MVPBakery(this)
}

/**
* @param lifecycleOwner Your [AppCompatActivity], [Fragment] or [Fragment]
*/
fun attach(lifecycleOwner: ViewT): MVPBakery<ViewT, PresenterT> {
val lib = build()
lib.attach(lifecycleOwner)
return lib
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package eu.darken.mvpbakery.base


import androidx.lifecycle.LifecycleOwner

interface Presenter<ViewT : Presenter.View> {
fun onBindChange(view: ViewT?)

fun onDestroy()

interface View : LifecycleOwner
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package eu.darken.mvpbakery.base

interface PresenterFactory<PresenterT : Presenter<*>> {
fun createPresenter(): FactoryResult<PresenterT>

class FactoryResult<PresenterT : Presenter<*>> internal constructor(
internal val presenter: PresenterT?,
internal val retry: Boolean,
internal val retryException: Throwable? = null
) {
companion object {

fun <PresenterT : Presenter<*>> retry(retryException: Throwable? = null): FactoryResult<PresenterT> {
return FactoryResult(null, true, retryException)
}

fun <PresenterT : Presenter<*>> forPresenter(presenter: PresenterT): FactoryResult<PresenterT> {
return FactoryResult(presenter, false)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package eu.darken.mvpbakery.base


import android.os.Bundle
import androidx.lifecycle.LifecycleOwner

interface PresenterRetainer<ViewT : Presenter.View, PresenterT : Presenter<ViewT>> {
val presenter: PresenterT?
var stateForwarder: StateForwarder?
var presenterFactory: PresenterFactory<PresenterT>

fun attach(lifecycleOwner: LifecycleOwner, callback: Callback<ViewT, PresenterT>)

interface Callback<ViewT : Presenter.View, PresenterT : Presenter<ViewT>> {
fun onPresenterAvailable(presenter: PresenterT)
}

class DefaultStateListener(private val retainer: PresenterRetainer<*, *>) : StateForwarder.Listener {

override fun onCreate(savedInstanceState: Bundle?): Boolean {
if (retainer.presenter is StateListener) {
(retainer.presenter as StateListener).onRestoreState(savedInstanceState)
return true
}
return false
}

override fun onSaveInstanceState(outState: Bundle) {
if (retainer.presenter is StateListener) {
(retainer.presenter as StateListener).onSaveState(outState)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package eu.darken.mvpbakery.base

import android.os.Bundle

class StateForwarder {
private var internalCallback: Listener? = null
internal var inState: Bundle? = null
private var outState: Bundle? = null
private var isRestoreConsumed = false
val hasRestoreEvent: Boolean
get() = !isRestoreConsumed

fun setListener(internalCallback: Listener?) {
this.internalCallback = internalCallback
if (internalCallback == null) return
if (inState != null) {
isRestoreConsumed = internalCallback.onCreate(inState)
if (isRestoreConsumed) inState = null
}
outState?.let {
internalCallback.onSaveInstanceState(it)
outState = null
}
}

fun onCreate(savedInstanceState: Bundle?) {
isRestoreConsumed = internalCallback != null && internalCallback!!.onCreate(savedInstanceState)
if (!isRestoreConsumed) this.inState = savedInstanceState
}

fun onSaveInstanceState(outState: Bundle) {
if (internalCallback != null) {
internalCallback!!.onSaveInstanceState(outState)
} else {
this.outState = outState
}
}

interface Listener {
/**
* Call directly after [android.app.Activity.onCreate] or [android.app.Fragment.onCreate]
*
* @return true if the instance state was delivered or false if it should be persisted
*/
fun onCreate(savedInstanceState: Bundle?): Boolean

/**
* Call before [android.app.Activity.onSaveInstanceState] or [android.app.Fragment.onSaveInstanceState]
*/
fun onSaveInstanceState(outState: Bundle)
}
}
Loading

0 comments on commit 4383a56

Please sign in to comment.