Skip to content

Commit d499d15

Browse files
committed
added standard project overhead for dagger etc
1 parent abc6b6d commit d499d15

File tree

15 files changed

+356
-13
lines changed

15 files changed

+356
-13
lines changed

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ android {
1717

1818
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1919
}
20-
20+
buildFeatures {
21+
viewBinding true
22+
}
2123
buildTypes {
2224
release {
2325
minifyEnabled false
@@ -30,12 +32,19 @@ android {
3032
}
3133
kotlinOptions {
3234
jvmTarget = '1.8'
35+
freeCompilerArgs += [
36+
'-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi'
37+
]
3338
}
3439
}
3540

3641
dependencies {
3742

3843
implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin"
44+
def coroutinesVersion = "1.3.9"
45+
46+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
47+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion"
3948
implementation 'androidx.core:core-ktx:1.3.2'
4049
implementation 'androidx.appcompat:appcompat:1.2.0'
4150
implementation 'com.google.android.material:material:1.2.1'
@@ -49,4 +58,14 @@ dependencies {
4958
kapt "com.google.dagger:dagger-compiler:${versions.dagger}"
5059
kapt "com.google.dagger:dagger-android-processor:${versions.dagger}"
5160

61+
implementation("androidx.navigation:navigation-fragment-ktx:2.3.1")
62+
implementation("androidx.navigation:navigation-ui-ktx:2.3.1")
63+
64+
def lifecycle = "2.2.0"
65+
implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:$lifecycle")
66+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle")
67+
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle")
68+
implementation("androidx.lifecycle:lifecycle-extensions:$lifecycle")
69+
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle")
70+
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle")
5271
}

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
android:allowBackup="true"
77
android:icon="@mipmap/ic_launcher"
88
android:label="@string/app_name"
9+
android:name=".App"
910
android:roundIcon="@mipmap/ic_launcher_round"
1011
android:supportsRtl="true"
1112
android:theme="@style/Theme.Androidtemplate">
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.monstarlab.base
2+
3+
import android.os.Bundle
4+
import androidx.annotation.LayoutRes
5+
import androidx.appcompat.app.AppCompatActivity
6+
import androidx.lifecycle.ViewModel
7+
import androidx.lifecycle.ViewModelProvider
8+
import com.monstarlab.extensions.getViewModel
9+
import com.monstarlab.extensions.lifecycleAwareLazy
10+
import dagger.android.AndroidInjection
11+
import dagger.android.DispatchingAndroidInjector
12+
import dagger.android.HasAndroidInjector
13+
import javax.inject.Inject
14+
15+
abstract class BaseActivity : AppCompatActivity, HasAndroidInjector {
16+
17+
constructor() : super()
18+
constructor(@LayoutRes resId: Int) : super(resId)
19+
20+
@Inject
21+
lateinit var viewModelFactory: ViewModelProvider.Factory
22+
23+
@Inject
24+
lateinit var androidInjector: DispatchingAndroidInjector<Any>
25+
26+
override fun onCreate(savedInstanceState: Bundle?) {
27+
AndroidInjection.inject(this)
28+
super.onCreate(savedInstanceState)
29+
}
30+
31+
protected inline fun <reified VM : ViewModel> getViewModel(): VM =
32+
getViewModel(viewModelFactory)
33+
34+
protected inline fun <reified VM : ViewModel> viewModel(): Lazy<VM> {
35+
return lifecycleAwareLazy(this) { getViewModel<VM>() }
36+
}
37+
38+
override fun androidInjector() = androidInjector
39+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.monstarlab.base
2+
3+
import android.content.Context
4+
import android.os.Bundle
5+
import androidx.annotation.LayoutRes
6+
import androidx.fragment.app.Fragment
7+
import androidx.lifecycle.ViewModel
8+
import androidx.lifecycle.ViewModelProvider
9+
import dagger.android.DispatchingAndroidInjector
10+
import dagger.android.HasAndroidInjector
11+
import dagger.android.support.AndroidSupportInjection
12+
import com.google.android.material.transition.MaterialFadeThrough
13+
import com.monstarlab.extensions.getSharedViewModel
14+
import com.monstarlab.extensions.getViewModel
15+
import com.monstarlab.extensions.lifecycleAwareLazy
16+
import javax.inject.Inject
17+
18+
abstract class BaseFragment : Fragment, HasAndroidInjector {
19+
20+
constructor()
21+
constructor(@LayoutRes resId: Int) : super(resId)
22+
23+
@Inject
24+
lateinit var viewModelFactory: ViewModelProvider.Factory
25+
26+
@Inject
27+
lateinit var androidInjector: DispatchingAndroidInjector<Any>
28+
29+
protected inline fun <reified VM : ViewModel> getViewModel(): VM =
30+
getViewModel(viewModelFactory)
31+
32+
protected inline fun <reified VM : ViewModel> getSharedViewModel(): VM =
33+
getSharedViewModel(viewModelFactory)
34+
35+
protected inline fun <reified VM : ViewModel> viewModel(): Lazy<VM> = lifecycleAwareLazy(this) {
36+
getViewModel<VM>()
37+
}
38+
39+
protected inline fun <reified VM : ViewModel> sharedViewModel(): Lazy<VM> =
40+
lifecycleAwareLazy(this) {
41+
getSharedViewModel<VM>()
42+
}
43+
44+
override fun onAttach(context: Context) {
45+
AndroidSupportInjection.inject(this)
46+
super.onAttach(context)
47+
}
48+
49+
override fun onCreate(savedInstanceState: Bundle?) {
50+
super.onCreate(savedInstanceState)
51+
52+
enterTransition = MaterialFadeThrough()
53+
exitTransition = MaterialFadeThrough()
54+
}
55+
56+
override fun androidInjector() = androidInjector
57+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.monstarlab.extensions
2+
3+
import androidx.fragment.app.Fragment
4+
import androidx.lifecycle.lifecycleScope
5+
import kotlinx.coroutines.flow.Flow
6+
import kotlinx.coroutines.flow.collect
7+
import kotlinx.coroutines.flow.combine
8+
import kotlinx.coroutines.flow.zip
9+
import kotlinx.coroutines.launch
10+
11+
fun <T> Fragment.collectFlow(targetFlow: Flow<T>, collectBlock: ((T) -> Unit)) {
12+
viewLifecycleOwner.lifecycleScope.launch {
13+
targetFlow.collect {
14+
collectBlock.invoke(it)
15+
}
16+
}
17+
}
18+
19+
fun <T1, T2> Fragment.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, collectBlock: ((T1, T2) -> Unit)) {
20+
viewLifecycleOwner.lifecycleScope.launch {
21+
flow1.combine(flow2) { v1, v2 ->
22+
collectBlock.invoke(v1, v2)
23+
}.collect {
24+
// Empty collect block to trigger ^
25+
}
26+
}
27+
}
28+
29+
fun <T1, T2, T3> Fragment.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, flow3: Flow<T3>, collectBlock: ((T1, T2, T3) -> Unit)) {
30+
viewLifecycleOwner.lifecycleScope.launch {
31+
combine(flow1, flow2, flow3) { v1, v2, v3 ->
32+
collectBlock.invoke(v1, v2, v3)
33+
}.collect {
34+
// Empty collect block to trigger ^
35+
}
36+
}
37+
}
38+
39+
fun <T1, T2, T3, T4> Fragment.combineFlows(flow1: Flow<T1>, flow2: Flow<T2>, flow3: Flow<T3>, flow4: Flow<T4>, collectBlock: ((T1, T2, T3, T4) -> Unit)) {
40+
viewLifecycleOwner.lifecycleScope.launch {
41+
combine(flow1, flow2, flow3, flow4) { v1, v2, v3, v4 ->
42+
collectBlock.invoke(v1, v2, v3, v4)
43+
}.collect {
44+
// Empty collect block to trigger ^
45+
}
46+
}
47+
}
48+
49+
fun <T1, T2> Fragment.zipFlows(flow1: Flow<T1>, flow2: Flow<T2>, collectBlock: ((T1, T2) -> Unit)) {
50+
viewLifecycleOwner.lifecycleScope.launch {
51+
flow1.zip(flow2) { v1, v2 ->
52+
collectBlock.invoke(v1, v2)
53+
}.collect {
54+
// Empty collect block to trigger ^
55+
}
56+
}
57+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.monstarlab.extensions
2+
3+
import androidx.fragment.app.Fragment
4+
import androidx.lifecycle.Lifecycle
5+
import androidx.lifecycle.LifecycleObserver
6+
import androidx.lifecycle.LifecycleOwner
7+
import androidx.lifecycle.OnLifecycleEvent
8+
import androidx.lifecycle.ViewModel
9+
import androidx.lifecycle.ViewModelProvider
10+
import androidx.lifecycle.ViewModelStoreOwner
11+
import java.io.Serializable
12+
13+
inline fun <reified VM : ViewModel> ViewModelStoreOwner.getViewModel(factory: ViewModelProvider.Factory): VM {
14+
return ViewModelProvider(this, factory).get(VM::class.java)
15+
}
16+
17+
inline fun <reified VM : ViewModel> Fragment.getSharedViewModel(factory: ViewModelProvider.Factory): VM {
18+
return ViewModelProvider(requireActivity(), factory).get(VM::class.java)
19+
}
20+
21+
private object UninitializedValue
22+
23+
/**
24+
* This was copied from SynchronizedLazyImpl but modified to automatically initialize in ON_CREATE.
25+
*/
26+
@Suppress("ClassName")
27+
class lifecycleAwareLazy<out T>(private val owner: LifecycleOwner, initializer: () -> T) : Lazy<T>,
28+
Serializable {
29+
private var initializer: (() -> T)? = initializer
30+
@Volatile
31+
private var _value: Any? = UninitializedValue
32+
// final field is required to enable safe publication of constructed instance
33+
private val lock = this
34+
35+
init {
36+
owner.lifecycle.addObserver(object : LifecycleObserver {
37+
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
38+
fun onStart() {
39+
if (!isInitialized()) value
40+
owner.lifecycle.removeObserver(this)
41+
}
42+
})
43+
}
44+
45+
@Suppress("LocalVariableName")
46+
override val value: T
47+
get() {
48+
val _v1 = _value
49+
if (_v1 !== UninitializedValue) {
50+
@Suppress("UNCHECKED_CAST")
51+
return _v1 as T
52+
}
53+
54+
return synchronized(lock) {
55+
val _v2 = _value
56+
if (_v2 !== UninitializedValue) {
57+
@Suppress("UNCHECKED_CAST") (_v2 as T)
58+
} else {
59+
val typedValue = initializer!!()
60+
_value = typedValue
61+
initializer = null
62+
typedValue
63+
}
64+
}
65+
}
66+
67+
override fun isInitialized(): Boolean = _value !== UninitializedValue
68+
69+
override fun toString(): String =
70+
if (isInitialized()) value.toString() else "Lazy value not initialized yet."
71+
}
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package com.monstarlab.features.main
22

3-
import androidx.appcompat.app.AppCompatActivity
43
import android.os.Bundle
54
import com.monstarlab.R
5+
import com.monstarlab.base.BaseActivity
66

7-
class MainActivity : AppCompatActivity() {
7+
class MainActivity : BaseActivity(R.layout.activity_main) {
88
override fun onCreate(savedInstanceState: Bundle?) {
99
super.onCreate(savedInstanceState)
10-
setContentView(R.layout.activity_main)
1110
}
1211
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.monstarlab.injection.builders
2+
3+
import androidx.lifecycle.ViewModel
4+
import com.monstarlab.features.main.MainActivity
5+
import dagger.Binds
6+
import dagger.Module
7+
import dagger.android.ContributesAndroidInjector
8+
import dagger.multibindings.IntoMap
9+
10+
@Module
11+
internal abstract class MainActivityBuilder {
12+
13+
@ContributesAndroidInjector(modules = [])
14+
internal abstract fun mainActivity(): MainActivity
15+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.monstarlab.injection.builders
2+
3+
import androidx.lifecycle.ViewModel
4+
import com.monstarlab.features.sample.SampleFragment
5+
import com.monstarlab.features.sample.SampleViewModel
6+
import dagger.Binds
7+
import dagger.Module
8+
import dagger.android.ContributesAndroidInjector
9+
import dagger.multibindings.IntoMap
10+
import dk.nodes.template.injection.modules.ViewModelKey
11+
12+
@Module
13+
internal abstract class SampleBuilder {
14+
@ContributesAndroidInjector
15+
abstract fun sampleFragment(): SampleFragment
16+
17+
@Binds
18+
@IntoMap
19+
@ViewModelKey(SampleViewModel::class)
20+
internal abstract fun bindSampleViewModel(viewModel: SampleViewModel): ViewModel
21+
}

0 commit comments

Comments
 (0)