Create example application
This commit is contained in:
parent
edf94325d8
commit
d9ba8c5e27
24 changed files with 322 additions and 52 deletions
|
|
@ -1,6 +1,8 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
id 'dagger.hilt.android.plugin'
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
@ -29,15 +31,24 @@ android {
|
|||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
testImplementation 'junit:junit:4.+'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
|
||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
|
||||
implementation project(":annotation")
|
||||
kapt project(":processor")
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package org.fnives.library.reloadable.module.hilt
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("org.fnives.library.reloadable.module.hilt", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,14 +3,16 @@
|
|||
package="org.fnives.library.reloadable.module.hilt">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:name=".ExampleApplication"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.HiltReloadableModule">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".LoginActivity"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
|
@ -18,6 +20,8 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".MainActivity" />
|
||||
<activity android:name=".SettingsActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package org.fnives.library.reloadable.module.hilt
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class ExampleApplication : Application()
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package org.fnives.library.reloadable.module.hilt
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.fnives.library.reloadable.module.hilt.usecase.LoginUseCase
|
||||
import org.fnives.library.reloadable.module.hilt.databinding.ActivityLoginBinding
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LoginActivity : AppCompatActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var loginUseCase: LoginUseCase
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val binding = ActivityLoginBinding.inflate(LayoutInflater.from(this))
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.loginCta.setOnClickListener {
|
||||
try {
|
||||
loginUseCase.login(binding.nameEditText.text?.toString().orEmpty())
|
||||
} catch (illegalArgumentException: IllegalArgumentException) {
|
||||
binding.nameInput.error = getString(R.string.please_fill_username)
|
||||
return@setOnClickListener
|
||||
}
|
||||
startActivity(Intent(this, MainActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
|
||||
binding.nameEditText.doAfterTextChanged {
|
||||
binding.nameInput.isErrorEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,29 @@
|
|||
package org.fnives.library.reloadable.module.hilt
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.fnives.library.reloadable.module.hilt.databinding.ActivityMainBinding
|
||||
import org.fnives.library.reloadable.module.hilt.usecase.GetUser
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var getUser: GetUser
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
val binding = ActivityMainBinding.inflate(LayoutInflater.from(this))
|
||||
setContentView(binding.root)
|
||||
|
||||
val user = getUser.invoke()
|
||||
binding.welcome.text = getString(R.string.hello_user, user.name, user.content)
|
||||
binding.settingsCta.setOnClickListener {
|
||||
startActivity(Intent(this, SettingsActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package org.fnives.library.reloadable.module.hilt
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.fnives.library.reloadable.module.hilt.databinding.ActivityLogoutBinding
|
||||
import org.fnives.library.reloadable.module.hilt.usecase.GetUser
|
||||
import org.fnives.library.reloadable.module.hilt.usecase.LogoutUseCase
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var logoutUseCase: LogoutUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var getUserUseCase: GetUser
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val binding = ActivityLogoutBinding.inflate(LayoutInflater.from(this))
|
||||
setContentView(binding.root)
|
||||
val user = getUserUseCase.invoke()
|
||||
binding.bye.text = getString(R.string.bye_user, user.name, user.content)
|
||||
|
||||
binding.logoutCta.setOnClickListener {
|
||||
logoutUseCase.invoke()
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
finishAffinity()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package org.fnives.library.reloadable.module.hilt.data
|
||||
|
||||
import javax.inject.Inject
|
||||
import kotlin.random.Random
|
||||
|
||||
class ContentGenerator @Inject constructor(){
|
||||
|
||||
fun getContent() = Random.nextInt(100)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package org.fnives.library.reloadable.module.hilt.data
|
||||
|
||||
import org.fnives.library.reloadable.module.hilt.di.LoggedInModuleInject
|
||||
|
||||
class ContentRepository @LoggedInModuleInject constructor(private val contentGenerator: ContentGenerator) {
|
||||
|
||||
private var content: Int? = null
|
||||
|
||||
fun getContent() = content ?: contentGenerator.getContent().also { content = it }
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package org.fnives.library.reloadable.module.hilt.data
|
||||
|
||||
data class User(val name: String, val content: Int)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package org.fnives.library.reloadable.module.hilt.data
|
||||
|
||||
import org.fnives.library.reloadable.module.hilt.di.LoggedInModuleInject
|
||||
|
||||
class UserRepository @LoggedInModuleInject constructor() {
|
||||
|
||||
var userName: String? = null
|
||||
private set
|
||||
|
||||
fun login(name: String) {
|
||||
userName = name
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package org.fnives.library.reloadable.module.hilt.di
|
||||
|
||||
import org.fnives.library.reloadable.module.annotation.ReloadableModule
|
||||
|
||||
@ReloadableModule
|
||||
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class LoggedInModuleInject
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package org.fnives.library.reloadable.module.hilt.usecase
|
||||
|
||||
import org.fnives.library.reloadable.module.hilt.data.ContentRepository
|
||||
import org.fnives.library.reloadable.module.hilt.data.User
|
||||
import org.fnives.library.reloadable.module.hilt.data.UserRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetUser @Inject constructor(
|
||||
private val userRepository: UserRepository,
|
||||
private val contentRepository: ContentRepository
|
||||
) {
|
||||
|
||||
fun invoke() = User(userRepository.userName.orEmpty(), contentRepository.getContent())
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package org.fnives.library.reloadable.module.hilt.usecase
|
||||
|
||||
import org.fnives.library.reloadable.module.hilt.data.UserRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginUseCase @Inject constructor(private val userRepository: UserRepository) {
|
||||
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun login(name: String) {
|
||||
if (name.isEmpty()) throw IllegalArgumentException("")
|
||||
userRepository.login(name)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package org.fnives.library.reloadable.module.hilt.usecase
|
||||
|
||||
import org.fnives.library.reloadable.module.hilt.di.ReloadLoggedInModuleInjectModule
|
||||
import javax.inject.Inject
|
||||
|
||||
class LogoutUseCase @Inject constructor(
|
||||
private val reloadLoggedInModuleInjectModule: ReloadLoggedInModuleInjectModule
|
||||
) {
|
||||
|
||||
fun invoke() {
|
||||
reloadLoggedInModuleInjectModule.reload()
|
||||
}
|
||||
}
|
||||
10
app/src/main/res/drawable/ic_exit.xml
Normal file
10
app/src/main/res/drawable/ic_exit.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_settings.xml
Normal file
10
app/src/main/res/drawable/ic_settings.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
||||
38
app/src/main/res/layout/activity_login.xml
Normal file
38
app/src/main/res/layout/activity_login.xml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/name_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
app:layout_constraintBottom_toTopOf="@id/login_cta"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/name_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/any_name" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/login_cta"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/default_margin"
|
||||
android:layout_marginEnd="@dimen/default_margin"
|
||||
android:minHeight="@dimen/min_button_height"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
android:text="@string/login"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
30
app/src/main/res/layout/activity_logout.xml
Normal file
30
app/src/main/res/layout/activity_logout.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/logout_cta"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/default_margin"
|
||||
android:contentDescription="@string/exit"
|
||||
android:src="@drawable/ic_exit"
|
||||
android:tint="?attr/colorOnPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bye"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/bye_user"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -6,10 +6,22 @@
|
|||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/settings_cta"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World!"
|
||||
android:layout_margin="@dimen/default_margin"
|
||||
android:contentDescription="@string/settings"
|
||||
android:src="@drawable/ic_settings"
|
||||
android:tint="?attr/colorOnPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcome"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello_user"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
|
|
|
|||
5
app/src/main/res/values/dimens.xml
Normal file
5
app/src/main/res/values/dimens.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="default_margin">24dp</dimen>
|
||||
<dimen name="min_button_height">48dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
<resources>
|
||||
<string name="app_name">HiltReloadableModule</string>
|
||||
<string name="login">login</string>
|
||||
<string name="any_name">Any Name</string>
|
||||
<string name="please_fill_username">Please give a name</string>
|
||||
<string name="hello_user">hello %1$s your content: %2$d!</string>
|
||||
<string name="bye_user">Bye %1$s your content: %2$d!</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="exit">Logout</string>
|
||||
</resources>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package org.fnives.library.reloadable.module.hilt
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue