Create example application

This commit is contained in:
Gergely Hegedus 2021-07-30 23:33:35 +03:00
parent edf94325d8
commit d9ba8c5e27
24 changed files with 322 additions and 52 deletions

View file

@ -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")
}

View file

@ -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)
}
}

View file

@ -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>

View file

@ -0,0 +1,7 @@
package org.fnives.library.reloadable.module.hilt
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class ExampleApplication : Application()

View file

@ -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
}
}
}

View file

@ -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))
}
}
}

View file

@ -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()
}
}
}

View file

@ -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)
}

View file

@ -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 }
}

View file

@ -0,0 +1,3 @@
package org.fnives.library.reloadable.module.hilt.data
data class User(val name: String, val content: Int)

View file

@ -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
}
}

View file

@ -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

View file

@ -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())
}

View file

@ -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)
}
}

View file

@ -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()
}
}

View 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>

View 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>

View 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>

View 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>

View file

@ -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"

View 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>

View file

@ -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>

View file

@ -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)
}
}