Compare commits
No commits in common. "develop" and "master" have entirely different histories.
|
|
@ -19,8 +19,3 @@ local.properties
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
app/src/main/res/*/*strings.xml
|
app/src/main/res/*/*strings.xml
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
[submodule "Template-common"]
|
||||||
|
path = Template-common
|
||||||
|
url = git@github.com:TouchInstinct/Template-common.git
|
||||||
[submodule "RoboSwag"]
|
[submodule "RoboSwag"]
|
||||||
path = RoboSwag
|
path = RoboSwag
|
||||||
url = https://git.svc.touchin.ru/TouchInstinct/RoboSwag.git
|
url = git@github.com:TouchInstinct/RoboSwag.git
|
||||||
[submodule "BuildScripts"]
|
[submodule "BuildScripts"]
|
||||||
path = BuildScripts
|
path = BuildScripts
|
||||||
url = https://git.svc.touchin.ru/TouchInstinct/BuildScripts.git
|
url = git@github.com:TouchInstinct/BuildScripts.git
|
||||||
[submodule "common-template"]
|
|
||||||
path = common-template
|
|
||||||
url = https://git.svc.touchin.ru/TouchInstinct/common-template.git
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1 @@
|
||||||
/build
|
/build
|
||||||
|
|
||||||
app/src/main/res/*/*strings.xml
|
|
||||||
|
|
|
||||||
|
|
@ -1,98 +1,74 @@
|
||||||
plugins {
|
plugins {
|
||||||
id(libs.plugins.android.app.get().pluginId)
|
id(Plugins.ANDROID_APP_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
alias(libs.plugins.firebase.crashlytics)
|
id(Plugins.FIREBASE_CRASH)
|
||||||
alias(libs.plugins.firebase.perf)
|
id(Plugins.GOOGLE_SERVICES)
|
||||||
id(libs.plugins.google.oss.licenses.plugin.get().pluginId)
|
id(Plugins.LICENCE_PLUGIN)
|
||||||
}
|
}
|
||||||
|
|
||||||
val customEndpoint: String? = Environment.ENDPOINT.getenv()?.takeIf(String::isNotBlank)
|
val customEndpoint: String? = Environment.ENDPOINT.getenv()?.takeIf(String::isNotBlank)
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "ru.touchin.template"
|
|
||||||
|
|
||||||
configureSigningConfig(this@Build_gradle::file)
|
configureSigningConfig(this@Build_gradle::file)
|
||||||
|
|
||||||
with(defaultConfig) {
|
with(defaultConfig) {
|
||||||
addResourceConfigurations("ru")
|
applicationId = Environment.APP_ID.getenv() ?: AndroidConfig.TEST_APP_ID
|
||||||
|
signingConfig = signingConfigs.getByName(SigningConfig.CONFIG_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
addBuildType(type = BuildType.Develop, project = rootProject)
|
firebaseCrashlytics {
|
||||||
addBuildType(type = BuildType.Debug, project = rootProject)
|
mappingFileUploadEnabled = true
|
||||||
addBuildType(type = BuildType.Customer, project = rootProject)
|
}
|
||||||
addBuildType(type = BuildType.Release, project = rootProject)
|
|
||||||
|
|
||||||
addMobileServicesFlavor()
|
addBuildType(BuildType.Debug, buildScriptDir = buildScriptDir)
|
||||||
|
addBuildType(BuildType.Release, buildScriptDir = buildScriptDir)
|
||||||
|
|
||||||
ext["languageMap"] = mapOf("ru" to "${rootProject.projectDir}/${AndroidConfig.COMMON_FOLDER}/strings/default_common_strings.json")
|
flavorDimensions(
|
||||||
|
ApiFlavour.DIMENSION_NAME,
|
||||||
|
SSLPinningFlavour.DIMENSION_NAME,
|
||||||
|
TestPanelFlavour.DIMENSION_NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
addFlavour(flavour = ApiFlavour.CustomerStage, customEndpoint = customEndpoint)
|
||||||
|
addFlavour(flavour = ApiFlavour.CustomerProd, customEndpoint = customEndpoint)
|
||||||
|
|
||||||
|
addFlavour(SSLPinningFlavour.OFF)
|
||||||
|
addFlavour(SSLPinningFlavour.ON)
|
||||||
|
|
||||||
|
addEmptyFlavour(TestPanelFlavour.OFF)
|
||||||
|
addEmptyFlavour(TestPanelFlavour.ON)
|
||||||
|
|
||||||
|
ignoreCustomerProdFlavourIfReleaseIsDebuggable()
|
||||||
|
}
|
||||||
|
|
||||||
|
androidExtensions {
|
||||||
|
features = setOf("parcelize")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// AndroidX
|
androidX()
|
||||||
implementation(libs.bundles.androidX)
|
featureModules()
|
||||||
|
mvi()
|
||||||
// KotlinX
|
materialDesign()
|
||||||
implementation(libs.coroutines)
|
dagger()
|
||||||
|
retrofit()
|
||||||
// UI
|
moshi()
|
||||||
implementation(libs.bundles.ui)
|
navigation()
|
||||||
|
leakCanary()
|
||||||
// Lifecycle
|
sharedPrefs()
|
||||||
implementation(libs.bundles.lifecycle)
|
chucker()
|
||||||
kapt(libs.androidx.lifecycle.compiler)
|
implementation(Library.FIREBASE_ANAL)
|
||||||
|
implementation(Library.FIREBASE_CRASH)
|
||||||
// Dagger
|
implementation(Library.FIREBASE_PERF)
|
||||||
implementation(libs.bundles.dagger)
|
implementation(Library.ANDROIDX_SECURE)
|
||||||
kapt(libs.dagger.compiler)
|
coreNetwork()
|
||||||
kapt(libs.dagger.assisted.inject.processor)
|
coreStrings()
|
||||||
|
implementationModule(Module.Core.UI)
|
||||||
// Glide
|
implementationModule(Module.Core.UTILS)
|
||||||
implementation(libs.glide)
|
implementationModule(Module.Core.DATA)
|
||||||
implementation(libs.glide.okhttp3)
|
implementationModule(Module.RoboSwag.UTILS)
|
||||||
kapt(libs.glide.compiler)
|
|
||||||
|
|
||||||
// Retrofit2, OkHttp3
|
|
||||||
implementation(libs.retrofit)
|
|
||||||
implementation(libs.retrofit.converter.moshi)
|
|
||||||
implementation(libs.okhttp)
|
|
||||||
implementation(libs.okhttp.logging.interceptor)
|
|
||||||
|
|
||||||
// Moshi
|
|
||||||
implementation(libs.moshi)
|
|
||||||
implementation(libs.moshi.kotlin)
|
|
||||||
kapt(libs.moshi.codegen)
|
|
||||||
|
|
||||||
// Room
|
|
||||||
implementation(libs.room)
|
|
||||||
implementation(libs.room.ktx)
|
|
||||||
kapt(libs.room.compiler)
|
|
||||||
|
|
||||||
// LeakCanary
|
|
||||||
implementation(libs.leakcanary)
|
|
||||||
|
|
||||||
// Chucker
|
|
||||||
debugImplementation(libs.chucker.debug)
|
|
||||||
releaseImplementation(libs.chucker.release)
|
|
||||||
|
|
||||||
// GMS
|
|
||||||
implementation(platform(libs.firebase.bom))
|
|
||||||
implementation(libs.bundles.firebase)
|
|
||||||
implementation(libs.google.oss.licenses)
|
|
||||||
|
|
||||||
// Security
|
|
||||||
implementation(libs.androidx.security.crypto)
|
|
||||||
|
|
||||||
// Biometric
|
|
||||||
implementation(libs.androidx.biometric)
|
|
||||||
|
|
||||||
// Groupie
|
|
||||||
implementation(libs.groupie)
|
|
||||||
implementation(libs.groupie.viewbinding)
|
|
||||||
|
|
||||||
// Cicecrone
|
|
||||||
implementation(libs.cicerone)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(from = "${rootProject.ext["buildScriptsDir"]}/gradle/scripts/stringGenerator.gradle")
|
apply(from = "$buildScriptDir/gradle/scripts/applicationFileNaming.gradle")
|
||||||
|
|
||||||
val Project.buildScriptDir: String
|
val Project.buildScriptDir: String
|
||||||
get() = rootProject.ext["buildScriptsDir"] as String
|
get() = rootProject.ext["buildScriptsDir"] as String
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "1084813714260",
|
||||||
|
"firebase_url": "https://testproject-ac7fe.firebaseio.com",
|
||||||
|
"project_id": "testproject-ac7fe",
|
||||||
|
"storage_bucket": "testproject-ac7fe.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:1084813714260:android:b6d7bb18a0acfe96255ec1",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.touchin.template"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "1084813714260-ijq13dkdc1h5i5j87t45tiibl8eg2v9e.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBVsh_CN-RCfU3LkHuvhLdqVS-ZUJbOljE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "1084813714260-ijq13dkdc1h5i5j87t45tiibl8eg2v9e.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<manifest
|
<manifest
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
package="ru.touchin.template">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
|
@ -8,17 +9,17 @@
|
||||||
android:name="ru.touchin.template.App"
|
android:name="ru.touchin.template.App"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/common_app_name"
|
android:label="@string/common_global_app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="false"
|
android:supportsRtl="false"
|
||||||
tools:ignore="GoogleAppIndexingWarning"
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".feature.SingleActivity"
|
android:name="ru.touchin.template.SingleActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:theme="@style/AppTheme"
|
||||||
android:exported="true">
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,25 @@
|
||||||
package ru.touchin.template
|
package ru.touchin.template
|
||||||
|
|
||||||
import android.app.Application
|
import me.vponomarenko.injectionmanager.IHasComponent
|
||||||
import ru.touchin.template.di.DI
|
import me.vponomarenko.injectionmanager.x.XInjectionManager
|
||||||
import ru.touchin.template.di.SharedComponent
|
import ru.touchin.roboswag.navigation_base.TouchinApp
|
||||||
import ru.touchin.template.di.SharedComponentProvider
|
import ru.touchin.template.di.ApplicationComponent
|
||||||
|
import ru.touchin.template.di.DaggerApplicationComponent
|
||||||
|
|
||||||
class App : Application(), SharedComponentProvider {
|
class App : TouchinApp(), IHasComponent<ApplicationComponent> {
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
initDagger()
|
||||||
DI.init(applicationContext)
|
|
||||||
DI.getComponent().inject(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getModule(): SharedComponent = DI.getComponent()
|
fun initDagger() {
|
||||||
|
XInjectionManager.init(this)
|
||||||
|
XInjectionManager.bindComponent(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getComponent(): ApplicationComponent = DaggerApplicationComponent
|
||||||
|
.factory()
|
||||||
|
.create(this)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package ru.touchin.template
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
|
import com.google.firebase.analytics.ktx.analytics
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
import me.vponomarenko.injectionmanager.x.XInjectionManager
|
||||||
|
import ru.terrakok.cicerone.NavigatorHolder
|
||||||
|
import ru.terrakok.cicerone.android.support.SupportAppNavigator
|
||||||
|
import ru.touchin.roboswag.navigation_base.activities.BaseActivity
|
||||||
|
import ru.touchin.roboswag.navigation_cicerone.CiceroneTuner
|
||||||
|
import ru.touchin.template.di.ApplicationComponent
|
||||||
|
import ru.touchin.template.navigation.MainNavigation
|
||||||
|
import ru.touchin.template.navigation.StartUpCoordinator
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
// TDOD: change package name everywhere
|
||||||
|
// TODO: change google play config
|
||||||
|
class SingleActivity : BaseActivity() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@MainNavigation
|
||||||
|
lateinit var navigatorHolder: NavigatorHolder
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var coordinator: StartUpCoordinator
|
||||||
|
|
||||||
|
private lateinit var firebaseAnalytics: FirebaseAnalytics
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
firebaseAnalytics = Firebase.analytics
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
injectDependencies()
|
||||||
|
|
||||||
|
lifecycle.addObserver(
|
||||||
|
CiceroneTuner(
|
||||||
|
navigatorHolder = navigatorHolder,
|
||||||
|
navigator = SupportAppNavigator(this, R.id.fragment_container)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
coordinator.start()
|
||||||
|
|
||||||
|
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
coordinator.closeCurrentScreen()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun injectDependencies() {
|
||||||
|
XInjectionManager
|
||||||
|
.findComponent<ApplicationComponent>()
|
||||||
|
.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ru.touchin.template.base.activity
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import ru.touchin.template.di.SharedComponent
|
|
||||||
import ru.touchin.template.di.getSharedModule
|
|
||||||
|
|
||||||
abstract class BaseActivity<T : ViewModel> : AppCompatActivity() {
|
|
||||||
|
|
||||||
protected val viewModel: T by lazy { createViewModelLazy().value }
|
|
||||||
|
|
||||||
protected val viewModelFactory by lazy { getSharedComponent().viewModelFactory() }
|
|
||||||
|
|
||||||
abstract fun createViewModelLazy(): Lazy<T>
|
|
||||||
|
|
||||||
protected fun getSharedComponent(): SharedComponent = getSharedModule()
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package ru.touchin.template.base.fragment
|
|
||||||
|
|
||||||
import androidx.annotation.LayoutRes
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import ru.touchin.template.base.viewmodel.BaseViewModel
|
|
||||||
import ru.touchin.template.di.SharedComponent
|
|
||||||
import ru.touchin.template.di.getSharedModule
|
|
||||||
import ru.touchin.template.navigation.backpress.OnBackPressedListener
|
|
||||||
|
|
||||||
abstract class BaseFragment<T : BaseViewModel>(@LayoutRes layoutId: Int) : Fragment(layoutId), OnBackPressedListener {
|
|
||||||
|
|
||||||
protected val viewModel: T by lazy { createViewModelLazy().value }
|
|
||||||
|
|
||||||
protected val viewModelFactory by lazy { getSharedComponent().viewModelFactory() }
|
|
||||||
|
|
||||||
protected abstract fun createViewModelLazy(): Lazy<T>
|
|
||||||
|
|
||||||
protected fun getSharedComponent(): SharedComponent = getSharedModule()
|
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
|
||||||
return viewModel.onBackClicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package ru.touchin.template.base.viewmodel
|
|
||||||
|
|
||||||
interface BaseController {
|
|
||||||
|
|
||||||
fun onBackClicked(): Boolean = true
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package ru.touchin.template.base.viewmodel
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
|
|
||||||
abstract class BaseViewModel : ViewModel(), BaseController
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
package ru.touchin.template.di
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import dagger.BindsInstance
|
|
||||||
import dagger.Component
|
|
||||||
import ru.touchin.template.App
|
|
||||||
import ru.touchin.template.di.auth.AuthComponent
|
|
||||||
import ru.touchin.template.di.modules.AppModule
|
|
||||||
import ru.touchin.template.di.modules.NavigationModule
|
|
||||||
import ru.touchin.template.di.modules.ViewModelModule
|
|
||||||
import ru.touchin.template.feature.SingleActivity
|
|
||||||
|
|
||||||
@Component(
|
|
||||||
modules = [
|
|
||||||
AppModule::class,
|
|
||||||
ViewModelModule::class,
|
|
||||||
NavigationModule::class
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@AppScope
|
|
||||||
interface AppComponent : SharedComponent {
|
|
||||||
|
|
||||||
fun authComponent(): AuthComponent.Builder
|
|
||||||
|
|
||||||
@Component.Builder
|
|
||||||
interface Builder {
|
|
||||||
|
|
||||||
@BindsInstance
|
|
||||||
fun appContext(appContext: Context): Builder
|
|
||||||
|
|
||||||
fun build(): AppComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inject(entry: App)
|
|
||||||
|
|
||||||
fun inject(entry: SingleActivity)
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package ru.touchin.template.di
|
|
||||||
|
|
||||||
import javax.inject.Scope
|
|
||||||
|
|
||||||
@Scope
|
|
||||||
annotation class AppScope
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package ru.touchin.template.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.BindsInstance
|
||||||
|
import dagger.Component
|
||||||
|
import ru.terrakok.cicerone.Router
|
||||||
|
import ru.touchin.template.feature_login.LoginDeps
|
||||||
|
import ru.touchin.template.network.di.NetworkModule
|
||||||
|
import ru.touchin.template.App
|
||||||
|
import ru.touchin.template.SingleActivity
|
||||||
|
import ru.touchin.template.core_prefs.PreferencesModule
|
||||||
|
import ru.touchin.template.navigation.MainNavigation
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = [
|
||||||
|
ApplicationModule::class,
|
||||||
|
PreferencesModule::class,
|
||||||
|
MainNavigationModule::class,
|
||||||
|
NetworkModule::class,
|
||||||
|
CoordinatorsImpl::class
|
||||||
|
])
|
||||||
|
interface ApplicationComponent : LoginDeps {
|
||||||
|
|
||||||
|
@MainNavigation
|
||||||
|
fun router(): Router
|
||||||
|
|
||||||
|
fun inject(application: App)
|
||||||
|
|
||||||
|
fun inject(activity: SingleActivity)
|
||||||
|
|
||||||
|
@Component.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(@BindsInstance context: Context): ApplicationComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package ru.touchin.template.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import ru.touchin.template.network.di.ApiUrl
|
||||||
|
import ru.touchin.template.network.di.ChuckInterceptor
|
||||||
|
import ru.touchin.template.network.di.WithSslPinning
|
||||||
|
import ru.touchin.template.BuildConfig
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class ApplicationModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@ApiUrl
|
||||||
|
fun provideApiUrl() = BuildConfig.API_URL
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@WithSslPinning
|
||||||
|
fun providePluggerForSsl() = BuildConfig.WithSSLPinning
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@ChuckInterceptor
|
||||||
|
fun provideChucker(context: Context): Interceptor = ChuckerInterceptor(context)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ru.touchin.template.di
|
||||||
|
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import ru.touchin.template.feature_login.navigation.LoginCoordinator
|
||||||
|
import ru.touchin.template.navigation.login.LoginCoordinatorImpl
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class CoordinatorsImpl {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun loginCoordinator(impl: LoginCoordinatorImpl): LoginCoordinator
|
||||||
|
}
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package ru.touchin.template.di
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
|
|
||||||
object DI {
|
|
||||||
|
|
||||||
private lateinit var appComponent: AppComponent
|
|
||||||
|
|
||||||
fun init(context: Context) {
|
|
||||||
appComponent = DaggerAppComponent.builder()
|
|
||||||
.appContext(context)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getComponent(): AppComponent = appComponent
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package ru.touchin.template.di
|
||||||
|
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import ru.terrakok.cicerone.Cicerone
|
||||||
|
import ru.terrakok.cicerone.NavigatorHolder
|
||||||
|
import ru.terrakok.cicerone.Router
|
||||||
|
import ru.touchin.template.navigation.MainNavigation
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class MainNavigationModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@MainNavigation
|
||||||
|
fun provideCicerone(): Cicerone<Router> = Cicerone.create()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@MainNavigation
|
||||||
|
fun provideNavigatorHolder(@MainNavigation cicerone: Cicerone<Router>): NavigatorHolder = cicerone.navigatorHolder
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@MainNavigation
|
||||||
|
fun provideRouter(@MainNavigation cicerone: Cicerone<Router>): Router = cicerone.router
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ru.touchin.template.di
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
|
|
||||||
fun Context.getSharedModule(): SharedComponent {
|
|
||||||
return (applicationContext as SharedComponentProvider).getModule()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Activity.getSharedModule(): SharedComponent {
|
|
||||||
return (applicationContext as SharedComponentProvider).getModule()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Fragment.getSharedModule(): SharedComponent {
|
|
||||||
return requireContext().getSharedModule()
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ru.touchin.template.di
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
import ru.touchin.template.di.viewmodel.ViewModelFactory
|
|
||||||
import ru.touchin.template.feature.second.SecondViewModel
|
|
||||||
|
|
||||||
interface SharedComponent {
|
|
||||||
fun viewModelFactory(): ViewModelFactory
|
|
||||||
fun secondScreenViewModelFactory(): SecondViewModel.Factory
|
|
||||||
}
|
|
||||||
|
|
||||||
@Module
|
|
||||||
class SharedModule
|
|
||||||
|
|
||||||
interface SharedComponentProvider {
|
|
||||||
fun getModule(): SharedComponent
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package ru.touchin.template.di.auth
|
|
||||||
|
|
||||||
import dagger.Subcomponent
|
|
||||||
import ru.touchin.template.feature.first.FirstFragment
|
|
||||||
|
|
||||||
@Subcomponent(modules = [AuthModule::class])
|
|
||||||
@AuthScope
|
|
||||||
interface AuthComponent {
|
|
||||||
|
|
||||||
@Subcomponent.Builder
|
|
||||||
interface Builder {
|
|
||||||
|
|
||||||
fun build(): AuthComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inject(entry: FirstFragment)
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package ru.touchin.template.di.auth
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
|
|
||||||
@Module
|
|
||||||
class AuthModule {
|
|
||||||
|
|
||||||
// @Provides
|
|
||||||
// @AuthScope
|
|
||||||
// internal fun providesSecondRepository(): SecondRepository {
|
|
||||||
// return SecondRepositoryImpl()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package ru.touchin.template.di.auth
|
|
||||||
|
|
||||||
import javax.inject.Scope
|
|
||||||
|
|
||||||
@Scope
|
|
||||||
annotation class AuthScope
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package ru.touchin.template.di.modules
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
import ru.touchin.template.di.auth.AuthComponent
|
|
||||||
|
|
||||||
@Module(
|
|
||||||
includes = [
|
|
||||||
RepositoryModule::class,
|
|
||||||
NetworkModule::class
|
|
||||||
],
|
|
||||||
subcomponents = [AuthComponent::class]
|
|
||||||
)
|
|
||||||
class AppModule
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package ru.touchin.template.di.modules
|
|
||||||
|
|
||||||
import com.github.terrakok.cicerone.Cicerone
|
|
||||||
import com.github.terrakok.cicerone.NavigatorHolder
|
|
||||||
import com.github.terrakok.cicerone.Router
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import ru.touchin.template.di.AppScope
|
|
||||||
|
|
||||||
@Module
|
|
||||||
class NavigationModule {
|
|
||||||
|
|
||||||
private val cicerone: Cicerone<Router> = Cicerone.create()
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@AppScope
|
|
||||||
fun provideRouter(): Router {
|
|
||||||
return cicerone.router
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@AppScope
|
|
||||||
fun provideNavigatorHolder(): NavigatorHolder {
|
|
||||||
return cicerone.getNavigatorHolder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package ru.touchin.template.di.modules
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
|
|
||||||
@Module
|
|
||||||
class NetworkModule {
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package ru.touchin.template.di.modules
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
|
|
||||||
@Module
|
|
||||||
class RepositoryModule {
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package ru.touchin.template.di.modules
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import dagger.Binds
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.multibindings.IntoMap
|
|
||||||
import ru.touchin.template.di.viewmodel.ViewModelFactory
|
|
||||||
import ru.touchin.template.di.viewmodel.ViewModelKey
|
|
||||||
import ru.touchin.template.feature.SingleViewModel
|
|
||||||
import ru.touchin.template.feature.first.FirstViewModel
|
|
||||||
|
|
||||||
@Module
|
|
||||||
interface ViewModelModule {
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@ViewModelKey(SingleViewModel::class)
|
|
||||||
fun bindsSingleViewModel(viewModel: SingleViewModel): ViewModel
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@ViewModelKey(FirstViewModel::class)
|
|
||||||
fun bindsFirstViewModel(viewModel: FirstViewModel): ViewModel
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
package ru.touchin.template.di.viewmodel
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.lifecycle.AbstractSavedStateViewModelFactory
|
|
||||||
import androidx.lifecycle.SavedStateHandle
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.savedstate.SavedStateRegistryOwner
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Provider
|
|
||||||
|
|
||||||
class ViewModelFactory @Inject constructor(
|
|
||||||
private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>
|
|
||||||
) : ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
||||||
val viewModel = viewModels[modelClass]?.get()
|
|
||||||
return viewModel as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified VM : ViewModel> Fragment.assistedViewModel(
|
|
||||||
crossinline creator: (SavedStateHandle) -> VM,
|
|
||||||
): Lazy<VM> = viewModels { createAbstractSavedStateViewModelFactory(arguments, creator) }
|
|
||||||
|
|
||||||
inline fun <reified T : ViewModel> SavedStateRegistryOwner.createAbstractSavedStateViewModelFactory(
|
|
||||||
arguments: Bundle? = Bundle(),
|
|
||||||
crossinline creator: (SavedStateHandle) -> T,
|
|
||||||
): ViewModelProvider.Factory {
|
|
||||||
return object : AbstractSavedStateViewModelFactory(
|
|
||||||
owner = this@createAbstractSavedStateViewModelFactory,
|
|
||||||
defaultArgs = arguments,
|
|
||||||
) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel> create(
|
|
||||||
key: String,
|
|
||||||
modelClass: Class<T>,
|
|
||||||
handle: SavedStateHandle,
|
|
||||||
): T = creator(handle) as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package ru.touchin.template.di.viewmodel
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import dagger.MapKey
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
|
||||||
@MapKey
|
|
||||||
annotation class ViewModelKey(val value: KClass<out ViewModel>)
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package ru.touchin.template.feature
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.activity.viewModels
|
|
||||||
import com.github.terrakok.cicerone.NavigatorHolder
|
|
||||||
import com.github.terrakok.cicerone.androidx.AppNavigator
|
|
||||||
import javax.inject.Inject
|
|
||||||
import ru.touchin.template.R
|
|
||||||
import ru.touchin.template.base.activity.BaseActivity
|
|
||||||
import ru.touchin.template.databinding.ActivityMainBinding
|
|
||||||
import ru.touchin.template.di.DI
|
|
||||||
|
|
||||||
class SingleActivity : BaseActivity<SingleViewModel>() {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var navigatorHolder: NavigatorHolder
|
|
||||||
|
|
||||||
private val rootNavigator by lazy {
|
|
||||||
AppNavigator(this, R.id.activityScreensContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
|
||||||
|
|
||||||
override fun createViewModelLazy(): Lazy<SingleViewModel> = viewModels { viewModelFactory }
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
|
|
||||||
DI.getComponent().inject(this)
|
|
||||||
|
|
||||||
viewModel.navigate()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResumeFragments() {
|
|
||||||
super.onResumeFragments()
|
|
||||||
navigatorHolder.setNavigator(rootNavigator)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
navigatorHolder.removeNavigator()
|
|
||||||
super.onPause()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package ru.touchin.template.feature
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import com.github.terrakok.cicerone.Router
|
|
||||||
import javax.inject.Inject
|
|
||||||
import ru.touchin.template.navigation.Screens
|
|
||||||
|
|
||||||
class SingleViewModel @Inject constructor(
|
|
||||||
private val router: Router,
|
|
||||||
) : ViewModel() {
|
|
||||||
fun navigate() {
|
|
||||||
router.newRootScreen(Screens.First())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package ru.touchin.template.feature.first
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import ru.touchin.template.R
|
|
||||||
import ru.touchin.template.base.fragment.BaseFragment
|
|
||||||
import ru.touchin.template.databinding.FragmentFirstBinding
|
|
||||||
import ru.touchin.template.utils.binding.viewBinding
|
|
||||||
|
|
||||||
class FirstFragment : BaseFragment<FirstViewModel>(R.layout.fragment_first) {
|
|
||||||
|
|
||||||
private val binding by viewBinding { FragmentFirstBinding.bind(it) }
|
|
||||||
|
|
||||||
override fun createViewModelLazy() = viewModels<FirstViewModel> { viewModelFactory }
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
with(binding) {
|
|
||||||
button.apply {
|
|
||||||
text = "Next"
|
|
||||||
setOnClickListener { viewModel.onNextButtonClicked(this@FirstFragment::class.toString()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
textView.text = "First Fragment"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package ru.touchin.template.feature.first
|
|
||||||
|
|
||||||
import com.github.terrakok.cicerone.Router
|
|
||||||
import javax.inject.Inject
|
|
||||||
import ru.touchin.template.base.viewmodel.BaseViewModel
|
|
||||||
import ru.touchin.template.navigation.Screens
|
|
||||||
|
|
||||||
class FirstViewModel @Inject constructor(
|
|
||||||
private val router: Router
|
|
||||||
) : BaseViewModel() {
|
|
||||||
|
|
||||||
fun onNextButtonClicked(from: String) {
|
|
||||||
router.navigateTo(Screens.Second(from))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
package ru.touchin.template.feature.second
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.flowWithLifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import ru.touchin.template.R
|
|
||||||
import ru.touchin.template.base.fragment.BaseFragment
|
|
||||||
import ru.touchin.template.databinding.FragmentSecondBinding
|
|
||||||
import ru.touchin.template.di.viewmodel.assistedViewModel
|
|
||||||
import ru.touchin.template.utils.binding.viewBinding
|
|
||||||
|
|
||||||
class SecondFragment : BaseFragment<SecondViewModel>(R.layout.fragment_second) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val FROM_KEY = "FROM"
|
|
||||||
private const val SCREEN_NAME_KEY = "SCREEN_NAME"
|
|
||||||
private const val FRAGMENT_NAME = "Second Fragment"
|
|
||||||
|
|
||||||
fun newInstance(from: String): SecondFragment {
|
|
||||||
val args = bundleOf(FROM_KEY to from, SCREEN_NAME_KEY to FRAGMENT_NAME)
|
|
||||||
|
|
||||||
val fragment = SecondFragment().apply {
|
|
||||||
arguments = args
|
|
||||||
}
|
|
||||||
|
|
||||||
return fragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val binding by viewBinding { FragmentSecondBinding.bind(it) }
|
|
||||||
|
|
||||||
private val secondViewModelFactory by lazy { getSharedComponent().secondScreenViewModelFactory() }
|
|
||||||
|
|
||||||
override fun createViewModelLazy() = assistedViewModel {
|
|
||||||
secondViewModelFactory.create(
|
|
||||||
arguments?.getString(FROM_KEY) ?: "Unkown Fragment",
|
|
||||||
arguments?.getString(SCREEN_NAME_KEY) ?: "Unknown"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
with(binding) {
|
|
||||||
button.apply {
|
|
||||||
text = "Back"
|
|
||||||
setOnClickListener { onBackPressed() }
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
viewModel.state
|
|
||||||
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
|
|
||||||
.collect {
|
|
||||||
textView.text = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
package ru.touchin.template.feature.second
|
|
||||||
|
|
||||||
import com.github.terrakok.cicerone.Router
|
|
||||||
import dagger.assisted.Assisted
|
|
||||||
import dagger.assisted.AssistedFactory
|
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import ru.touchin.template.base.viewmodel.BaseViewModel
|
|
||||||
|
|
||||||
class SecondViewModel @AssistedInject constructor(
|
|
||||||
@Assisted("from") from: String,
|
|
||||||
@Assisted("screenName") screenName: String,
|
|
||||||
private val rootRouter: Router
|
|
||||||
) : BaseViewModel() {
|
|
||||||
|
|
||||||
private val _state = MutableStateFlow("$from to $screenName")
|
|
||||||
val state: StateFlow<String> = _state.asStateFlow()
|
|
||||||
|
|
||||||
@AssistedFactory
|
|
||||||
interface Factory {
|
|
||||||
fun create(
|
|
||||||
@Assisted("from") from: String,
|
|
||||||
@Assisted("screenName") screenName: String
|
|
||||||
): SecondViewModel
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackClicked(): Boolean {
|
|
||||||
rootRouter.exit()
|
|
||||||
return super.onBackClicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.touchin.template.navigation
|
||||||
|
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class MainNavigation
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
package ru.touchin.template.navigation
|
package ru.touchin.template.navigation
|
||||||
|
|
||||||
import com.github.terrakok.cicerone.androidx.FragmentScreen
|
import androidx.fragment.app.Fragment
|
||||||
import ru.touchin.template.feature.first.FirstFragment
|
import ru.terrakok.cicerone.android.support.SupportAppScreen
|
||||||
import ru.touchin.template.feature.second.SecondFragment
|
import ru.touchin.template.feature_login.presentation.LoginFragment
|
||||||
|
|
||||||
object Screens {
|
object Screens {
|
||||||
|
|
||||||
fun First(): FragmentScreen = FragmentScreen {
|
class Login : SupportAppScreen() {
|
||||||
FirstFragment()
|
override fun getFragment(): Fragment = LoginFragment()
|
||||||
}
|
|
||||||
|
|
||||||
fun Second(from: String): FragmentScreen = FragmentScreen {
|
|
||||||
SecondFragment.newInstance(from)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.touchin.template.navigation
|
||||||
|
|
||||||
|
import ru.terrakok.cicerone.Router
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class StartUpCoordinator @Inject constructor(
|
||||||
|
@MainNavigation private val router: Router
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
router.newRootScreen(Screens.Login())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun closeCurrentScreen() {
|
||||||
|
router.exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package ru.touchin.template.navigation.backpress
|
|
||||||
|
|
||||||
interface OnBackPressedListener {
|
|
||||||
|
|
||||||
fun onBackPressed(): Boolean
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package ru.touchin.template.navigation.login
|
||||||
|
|
||||||
|
import ru.terrakok.cicerone.Router
|
||||||
|
import ru.touchin.template.feature_login.navigation.LoginCoordinator
|
||||||
|
import ru.touchin.template.navigation.MainNavigation
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LoginCoordinatorImpl @Inject constructor(
|
||||||
|
@MainNavigation private val router: Router
|
||||||
|
) : LoginCoordinator {
|
||||||
|
|
||||||
|
override fun openMainScreen() {
|
||||||
|
router.exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package ru.touchin.template.navigation.router
|
|
||||||
|
|
||||||
import com.github.terrakok.cicerone.Router
|
|
||||||
|
|
||||||
interface RouterProvider {
|
|
||||||
val router: Router
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
package ru.touchin.template.utils.binding
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import androidx.viewbinding.ViewBinding
|
|
||||||
import kotlin.properties.ReadOnlyProperty
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
typealias ViewBindingFactory<T> = (View) -> T
|
|
||||||
|
|
||||||
class FragmentViewBindingDelegate<T : ViewBinding>(
|
|
||||||
val fragment: Fragment,
|
|
||||||
val viewBindingFactory: ViewBindingFactory<T>,
|
|
||||||
) : ReadOnlyProperty<Fragment, T> {
|
|
||||||
private var binding: T? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
fragment.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
|
||||||
override fun onCreate(owner: LifecycleOwner) {
|
|
||||||
fragment.viewLifecycleOwnerLiveData.observe(fragment) { lifecylelOwner ->
|
|
||||||
lifecylelOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
|
||||||
override fun onDestroy(owner: LifecycleOwner) {
|
|
||||||
binding = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
|
|
||||||
val binding = this.binding
|
|
||||||
|
|
||||||
if (binding != null) return binding
|
|
||||||
|
|
||||||
val lifecycle = fragment.viewLifecycleOwner.lifecycle
|
|
||||||
|
|
||||||
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
|
|
||||||
throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return viewBindingFactory(thisRef.requireView()).also { this.binding = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: ViewBindingFactory<T>) =
|
|
||||||
FragmentViewBindingDelegate(this, viewBindingFactory)
|
|
||||||
|
|
@ -1,22 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
android:id="@+id/fragment_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:background="@color/colorPrimaryDark">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/activityScreensContainer"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_marginTop="40dp"
|
|
||||||
android:background="@color/colorPrimary"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<?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">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/button"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<?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">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/button"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<string name="common_global_app_name">Template</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -1,16 +1,43 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
maven("https://plugins.gradle.org/m2/")
|
maven("https://plugins.gradle.org/m2/")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath(libs.android.gradle.plugin)
|
classpath("com.android.tools.build:gradle:${Version.ANDROID_PLUGIN}")
|
||||||
classpath(libs.kotlin.gradle.plugin)
|
classpath(kotlin("gradle-plugin", version = Version.KOTLIN))
|
||||||
classpath(libs.google.oss.licenses.plugin)
|
classpath("com.google.gms:google-services:${Version.GOOGLE_SERVICES_PLUGIN}")
|
||||||
|
classpath("com.google.firebase:firebase-crashlytics-gradle:${Version.FIREBASE_CRASH_PLUGIN}")
|
||||||
|
classpath("com.vanniktech:gradle-dependency-graph-generator-plugin:0.5.0")
|
||||||
|
classpath("com.google.android.gms:oss-licenses-plugin:0.10.2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id(Plugins.DEPENDENCY_GRAPH).version("0.5.0")
|
||||||
|
id("static-analysis-android")
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
maven("http://dl.bintray.com/touchin/touchin-tools")
|
||||||
|
maven("https://jitpack.io")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
apply(plugin = Plugins.DETEKT)
|
||||||
|
}
|
||||||
|
|
||||||
val buildScriptsDir = "${rootProject.projectDir}/BuildScripts"
|
val buildScriptsDir = "${rootProject.projectDir}/BuildScripts"
|
||||||
ext["buildScriptsDir"] = buildScriptsDir
|
ext["buildScriptsDir"] = buildScriptsDir
|
||||||
|
|
||||||
|
apply(plugin = Plugins.DEPENDENCY_GRAPH)
|
||||||
|
|
||||||
|
staticAnalysis {
|
||||||
|
buildScriptDir = buildScriptsDir
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`kotlin-dsl`
|
`kotlin-dsl`
|
||||||
`kotlin-dsl-precompiled-script-plugins`
|
`kotlin-dsl-precompiled-script-plugins`
|
||||||
|
kotlin("jvm") version embeddedKotlinVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// The kotlin-dsl plugin requires a repository to be declared
|
// The kotlin-dsl plugin requires a repository to be declared
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
jcenter()
|
||||||
google()
|
google()
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://plugins.gradle.org/m2/")
|
url = uri("https://plugins.gradle.org/m2/")
|
||||||
|
|
@ -13,7 +16,18 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.android.gradle.plugin)
|
// android gradle plugin, required by custom plugin
|
||||||
implementation(libs.kotlin.gradle.plugin)
|
implementation("com.android.tools.build:gradle:4.0.0")
|
||||||
|
|
||||||
|
// kotlin plugin, required by custom plugin
|
||||||
|
implementation(kotlin("gradle-plugin", embeddedKotlinVersion))
|
||||||
|
|
||||||
|
gradleKotlinDsl()
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val compileKotlin: KotlinCompile by tasks
|
||||||
|
compileKotlin.kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
dependencyResolutionManagement {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
versionCatalogs {
|
|
||||||
create("libs") {
|
|
||||||
from(files("../gradle/libs.versions.toml"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +1,29 @@
|
||||||
import com.android.build.gradle.BaseExtension
|
import com.android.build.gradle.BaseExtension
|
||||||
|
|
||||||
object AndroidConfig {
|
object AndroidConfig {
|
||||||
|
const val COMPILE_SDK_VERSION = 29
|
||||||
|
const val MIN_SDK_VERSION = 23
|
||||||
|
const val TARGET_SDK_VERSION = 29
|
||||||
|
const val BUILD_TOOLS_VERSION = "29.0.2"
|
||||||
|
|
||||||
|
val VERSION_CODE: Int = Environment.BUILD_NUMBER.getenv()?.toIntOrNull() ?: 10000
|
||||||
|
const val VERSION_NAME = "1.0.0"
|
||||||
|
|
||||||
// TODO: change test package name
|
// TODO: change test package name
|
||||||
const val TEST_APP_ID = "ru.touchin.template"
|
const val TEST_APP_ID = "com.touchin.template"
|
||||||
|
|
||||||
// TODO: change common file folder
|
// TODO: change common file folder
|
||||||
const val COMMON_FOLDER = "common-template"
|
const val COMMON_FOLDER = "Template-common"
|
||||||
|
|
||||||
|
const val RELEASE_DEBUGGABLE = false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BaseExtension.ignoreCustomerProdFlavourIfReleaseIsDebuggable() {
|
||||||
|
variantFilter {
|
||||||
|
ignore = name.contains(ApiFlavour.CustomerProd.name, ignoreCase = true) && AndroidConfig.RELEASE_DEBUGGABLE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
import com.android.build.gradle.BaseExtension
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.api.artifacts.VersionCatalog
|
|
||||||
import org.gradle.kotlin.dsl.extra
|
|
||||||
import versioncatalog.versionName
|
|
||||||
|
|
||||||
fun BaseExtension.addFlavors(dimensionName: String, vararg flavorNames: String) {
|
|
||||||
if (flavorNames.isEmpty()) return
|
|
||||||
|
|
||||||
flavorDimensions(dimensionName)
|
|
||||||
|
|
||||||
flavorNames.forEach { flavor ->
|
|
||||||
productFlavors {
|
|
||||||
create(flavor) {
|
|
||||||
dimension = dimensionName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun BaseExtension.addMobileServicesFlavor() {
|
|
||||||
addFlavors(dimensionName = "mobileServices", flavorNames = arrayOf("huawei", "google"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun BaseExtension.addBuildType(
|
|
||||||
type: BuildType,
|
|
||||||
project: Project,
|
|
||||||
) {
|
|
||||||
buildTypes {
|
|
||||||
maybeCreate(type.name)
|
|
||||||
getByName(type.name) {
|
|
||||||
|
|
||||||
isDebuggable = !type.optimizeAndObfuscate
|
|
||||||
isMinifyEnabled = type.optimizeAndObfuscate
|
|
||||||
isShrinkResources = type.optimizeAndObfuscate
|
|
||||||
setMatchingFallbacks(type.matchingFallbacks)
|
|
||||||
|
|
||||||
if (listOf(BuildType.Develop, BuildType.Debug).contains(type)) {
|
|
||||||
applicationIdSuffix = ".${type.name}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.optimizeAndObfuscate) {
|
|
||||||
setProguardFiles(
|
|
||||||
listOf(
|
|
||||||
project.file("proguard").listFiles(),
|
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt")
|
|
||||||
).filterNotNull()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
extra.set("enableCrashlytics", type.enableCrashlytics)
|
|
||||||
|
|
||||||
buildConfigField("Boolean", "ENABLE_SSL_PINNING", type.enableSslPinning.toString())
|
|
||||||
buildConfigField("Boolean", "ENABLE_LOGS", type.enabledLogs.toString())
|
|
||||||
buildConfigField("Boolean", "ENABLE_DEBUG_PANEL", type.enabledDebugPanel.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun BaseExtension.addLibBuildType(
|
|
||||||
type: BuildType,
|
|
||||||
serverType: String? = null,
|
|
||||||
enableConfig: Boolean = false,
|
|
||||||
versionCatalog: VersionCatalog
|
|
||||||
) {
|
|
||||||
buildTypes {
|
|
||||||
maybeCreate(type.name)
|
|
||||||
getByName(type.name) {
|
|
||||||
isDebuggable = !type.optimizeAndObfuscate
|
|
||||||
isMinifyEnabled = type.optimizeAndObfuscate
|
|
||||||
setMatchingFallbacks(type.matchingFallbacks)
|
|
||||||
buildConfigField("String", "VERSION_NAME", "\"${versionCatalog.versionName}\"")
|
|
||||||
if (enableConfig) {
|
|
||||||
val server = serverType ?: type.serverType
|
|
||||||
buildConfigField("ru.template.data.network.ServerUrl", "DEFAULT_SERVER", type.defaultServer)
|
|
||||||
buildConfigField("String", "DEFAULT_SERVER_TYPE", "\"$server\"")
|
|
||||||
buildConfigField("Boolean", "ENABLE_SSL_PINNING", type.enableSslPinning.toString())
|
|
||||||
buildConfigField("Boolean", "ENABLE_LOGS", type.enabledLogs.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class BuildType(
|
|
||||||
val name: String,
|
|
||||||
val optimizeAndObfuscate: Boolean,
|
|
||||||
val enableSslPinning: Boolean,
|
|
||||||
val enabledLogs: Boolean,
|
|
||||||
val enabledDebugPanel: Boolean,
|
|
||||||
val enableCrashlytics: Boolean = true,
|
|
||||||
val defaultServer: String = "ru.template.data.network.ServerUrl.CUSTOMER_TEST",
|
|
||||||
val serverType: String,
|
|
||||||
val matchingFallbacks: String = "debug",
|
|
||||||
) {
|
|
||||||
object Develop : BuildType(
|
|
||||||
name = "develop",
|
|
||||||
optimizeAndObfuscate = false,
|
|
||||||
enableSslPinning = false,
|
|
||||||
enabledLogs = true,
|
|
||||||
enabledDebugPanel = true,
|
|
||||||
enableCrashlytics = false,
|
|
||||||
serverType = "Test",
|
|
||||||
)
|
|
||||||
|
|
||||||
object Debug : BuildType(
|
|
||||||
name = "debug",
|
|
||||||
optimizeAndObfuscate = false,
|
|
||||||
enableSslPinning = false,
|
|
||||||
enabledLogs = true,
|
|
||||||
enabledDebugPanel = true,
|
|
||||||
serverType = "Test",
|
|
||||||
)
|
|
||||||
|
|
||||||
object Customer : BuildType(
|
|
||||||
name = "customer",
|
|
||||||
optimizeAndObfuscate = true,
|
|
||||||
enableSslPinning = true,
|
|
||||||
enabledLogs = false,
|
|
||||||
enabledDebugPanel = false,
|
|
||||||
defaultServer = "ru.template.data.network.ServerUrl.CUSTOMER_PROD",
|
|
||||||
serverType = "Prod",
|
|
||||||
matchingFallbacks = "release"
|
|
||||||
)
|
|
||||||
|
|
||||||
object Release : BuildType(
|
|
||||||
name = "release",
|
|
||||||
optimizeAndObfuscate = true,
|
|
||||||
enableSslPinning = true,
|
|
||||||
enabledLogs = false,
|
|
||||||
enabledDebugPanel = false,
|
|
||||||
defaultServer = "ru.template.data.network.ServerUrl.CUSTOMER_PROD",
|
|
||||||
serverType = "Prod",
|
|
||||||
matchingFallbacks = "release"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
import org.gradle.api.artifacts.Dependency
|
||||||
|
import org.gradle.api.artifacts.ProjectDependency
|
||||||
|
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||||
|
|
||||||
|
fun DependencyHandler.fragment() {
|
||||||
|
implementation(Library.ANDROIDX_FRAGMENT)
|
||||||
|
implementation(Library.ANDROIDX_FRAGMENT_KTX)
|
||||||
|
implementationModule(Module.RoboSwag.NAVIGATION_BASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.materialDesign() {
|
||||||
|
implementation(Library.ANDROID_MATERIAL)
|
||||||
|
implementation(Library.SWIPE_TO_REFRESH)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.permissionDispatcher() {
|
||||||
|
implementation(Library.PERMISSION_DISPATCHER)
|
||||||
|
kapt(Library.PERMISSION_DISPATCHER_ANNOTATION_PROCESSOR)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.constraintLayout() {
|
||||||
|
implementation(Library.ANDROIDX_CONSTRAINT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.androidX() {
|
||||||
|
implementation(Library.ANDROIDX_CORE)
|
||||||
|
implementation(Library.ANDROIDX_APPCOMPAT)
|
||||||
|
implementationModule(Module.RoboSwag.KOTLIN_EXTENSIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.recyclerView() {
|
||||||
|
implementation(Library.ANDROIDX_RECYCLER)
|
||||||
|
implementationModule(Module.RoboSwag.RECYCLER_VIEW_ADAPTERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.kotlinStd() {
|
||||||
|
implementation(Library.KOTLIN_STDLIB)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.navigation() {
|
||||||
|
implementation(Library.CICERONE)
|
||||||
|
implementationModule(Module.RoboSwag.NAVIGATION_CICERONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.featureModules() {
|
||||||
|
Module.Feature.ALL.forEach(this::implementationModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.mvi() {
|
||||||
|
implementationModule(Module.RoboSwag.MVI_ARCH)
|
||||||
|
fragment()
|
||||||
|
lifecycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.coreNetwork() {
|
||||||
|
implementationModule(Module.Core.NETWORK)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.coreStrings() {
|
||||||
|
implementationModule(Module.Core.STRINGS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.retrofit() {
|
||||||
|
implementation(Library.RETROFIT)
|
||||||
|
implementation(Library.OKHTTP_LOGGING_INTERCEPTOR)
|
||||||
|
implementation(Library.OKHTTP)
|
||||||
|
implementation(Library.MOSHI_RETROFIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.dagger(withAssistedInject: Boolean = true) {
|
||||||
|
implementation(Library.DAGGER)
|
||||||
|
kapt(Library.DAGGER_COMPILER)
|
||||||
|
implementation(Library.DAGGER_COMPONENT_MANAGER)
|
||||||
|
|
||||||
|
if (withAssistedInject) {
|
||||||
|
compileOnly(Library.DAGGER_INJECT_ASSISTED_ANNOTATIONS)
|
||||||
|
kapt(Library.DAGGER_INJECT_ASSISTED_PROCESSOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.glide() {
|
||||||
|
implementation(Library.GLIDE)
|
||||||
|
implementation(Library.GLIDE_OKHTTP_INTEGRATION)
|
||||||
|
kapt(Library.GLIDE_COMPILER)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.moshi() {
|
||||||
|
implementation(Library.MOSHI)
|
||||||
|
kapt(Library.MOSHI_CODEGEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.lifecycle() {
|
||||||
|
implementation(Library.ANDROID_LIFECYCLE_EXTENSIONS)
|
||||||
|
implementation(Library.ANDROID_LIFECYCLE_VIEW_MODEL_EXTENSIONS)
|
||||||
|
implementation(Library.ANDROID_LIFECYCLE_LIVE_DATA_EXTENSIONS)
|
||||||
|
implementationModule(Module.RoboSwag.LIFECYCLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.coroutines() {
|
||||||
|
implementation(Library.COROUTINES_CORE)
|
||||||
|
implementation(Library.COROUTINES_ANDROID)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.leakCanary() {
|
||||||
|
add("withTestPanelImplementation", Library.LEAK_CANARY)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.sharedPrefs() {
|
||||||
|
implementationModule(Module.RoboSwag.STORABLE)
|
||||||
|
implementationModule(Module.Core.PREFS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.chucker() {
|
||||||
|
add("withTestPanelImplementation", Library.CHUCKER)
|
||||||
|
add("withoutTestPanelImplementation", Library.CHUCKER_NO_OP)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DependencyHandler.implementationModule(moduleName: String) {
|
||||||
|
implementation(project(":$moduleName"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DependencyHandler.implementation(dependencyNotation: Any): Dependency? =
|
||||||
|
add("implementation", dependencyNotation)
|
||||||
|
|
||||||
|
private fun DependencyHandler.kapt(dependencyNotation: Any): Dependency? =
|
||||||
|
add("kapt", dependencyNotation)
|
||||||
|
|
||||||
|
private fun DependencyHandler.compileOnly(dependencyNotation: Any): Dependency? =
|
||||||
|
add("compileOnly", dependencyNotation)
|
||||||
|
|
||||||
|
private fun DependencyHandler.project(
|
||||||
|
path: String,
|
||||||
|
configuration: String? = null
|
||||||
|
): ProjectDependency {
|
||||||
|
val notation = if (configuration != null) {
|
||||||
|
mapOf("path" to path, "configuration" to configuration)
|
||||||
|
} else {
|
||||||
|
mapOf("path" to path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uncheckedCast(project(notation))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unchecked_cast", "nothing_to_inline", "detekt.UnsafeCast")
|
||||||
|
private inline fun <T> uncheckedCast(obj: Any?): T = obj as T
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
object Environment {
|
object Environment {
|
||||||
const val APP_ID = "BUNDLE_ID"
|
const val APP_ID = "BUNDLE_ID"
|
||||||
|
|
||||||
const val STORE_PASSWORD = "STORE_PASSWORD"
|
const val STORE_PASSWORD = "STORE_PASSWORD"
|
||||||
const val ALIAS = "ALIAS"
|
const val KEY_ALIAS = "KEY_ALIAS"
|
||||||
const val KEY_PASSWORD = "KEY_PASSWORD"
|
const val KEY_PASSWORD = "KEY_PASSWORD"
|
||||||
|
|
||||||
const val ENDPOINT = "CUSTOM_ENDPOINT"
|
const val ENDPOINT = "CUSTOM_ENDPOINT"
|
||||||
|
|
||||||
const val BUILD_NUMBER = "BUILD_NUMBER"
|
const val BUILD_NUMBER = "BUILD_NUMBER"
|
||||||
const val SERVER_ENVIRONMENT = "SERVER_ENVIRONMENT"
|
|
||||||
const val BUILD_TYPE = "BUILD_TYPE"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.getenv(): String? = System.getenv(this)
|
fun String.getenv(): String? = System.getenv(this)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
object Library {
|
||||||
|
const val KOTLIN_STDLIB = "org.jetbrains.kotlin:kotlin-stdlib:${Version.KOTLIN}"
|
||||||
|
|
||||||
|
const val ANDROIDX_APPCOMPAT = "androidx.appcompat:appcompat:${Version.ANDROIDX_APPCOMPAT}"
|
||||||
|
const val ANDROIDX_CORE = "androidx.core:core-ktx:${Version.ANDROIDX_CORE}"
|
||||||
|
const val ANDROIDX_RECYCLER = "androidx.recyclerview:recyclerview:${Version.ANDROIDX}"
|
||||||
|
const val ANDROIDX_CONSTRAINT = "androidx.constraintlayout:constraintlayout:${Version.ANDROIDX_CONSTRAINT}"
|
||||||
|
|
||||||
|
const val ANDROIDX_FRAGMENT = "androidx.fragment:fragment:${Version.ANDROIDX_FRAGMENT}"
|
||||||
|
const val ANDROIDX_FRAGMENT_KTX = "androidx.fragment:fragment-ktx:${Version.ANDROIDX_FRAGMENT}"
|
||||||
|
|
||||||
|
const val ANDROID_MATERIAL = "com.google.android.material:material:${Version.ANDROID_MATERIAL}"
|
||||||
|
const val SWIPE_TO_REFRESH = "androidx.swiperefreshlayout:swiperefreshlayout:${Version.SWIPE_TO_REFRESH}"
|
||||||
|
|
||||||
|
const val PERMISSION_DISPATCHER = "org.permissionsdispatcher:permissionsdispatcher:${Version.PERMISSION_DISPATCHER}"
|
||||||
|
const val PERMISSION_DISPATCHER_ANNOTATION_PROCESSOR = "org.permissionsdispatcher:permissionsdispatcher-processor:${Version.PERMISSION_DISPATCHER}"
|
||||||
|
|
||||||
|
const val ANDROID_LIFECYCLE_EXTENSIONS = "androidx.lifecycle:lifecycle-extensions:${Version.ANDROID_LIFECYCLE}"
|
||||||
|
const val ANDROID_LIFECYCLE_VIEW_MODEL_EXTENSIONS = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Version.ANDROID_LIFECYCLE}"
|
||||||
|
const val ANDROID_LIFECYCLE_LIVE_DATA_EXTENSIONS = "androidx.lifecycle:lifecycle-livedata-ktx:${Version.ANDROID_LIFECYCLE}"
|
||||||
|
|
||||||
|
const val DAGGER = "com.google.dagger:dagger:${Version.DAGGER}"
|
||||||
|
const val DAGGER_COMPILER = "com.google.dagger:dagger-compiler:${Version.DAGGER}"
|
||||||
|
|
||||||
|
const val DAGGER_INJECT_ASSISTED_ANNOTATIONS = "com.squareup.inject:assisted-inject-annotations-dagger2:${Version.DAGGER_INJECT_ASSISTED}"
|
||||||
|
const val DAGGER_INJECT_ASSISTED_PROCESSOR = "com.squareup.inject:assisted-inject-processor-dagger2:${Version.DAGGER_INJECT_ASSISTED}"
|
||||||
|
|
||||||
|
const val DAGGER_COMPONENT_MANAGER = "com.github.valeryponomarenko.componentsmanager:androidx:${Version.DAGGER_COMPONENT_MANAGER}"
|
||||||
|
|
||||||
|
const val GLIDE = "com.github.bumptech.glide:glide:${Version.GLIDE}"
|
||||||
|
const val GLIDE_COMPILER = "com.github.bumptech.glide:compiler:${Version.GLIDE}"
|
||||||
|
const val GLIDE_OKHTTP_INTEGRATION = "com.github.bumptech.glide:okhttp3-integration:${Version.GLIDE}"
|
||||||
|
|
||||||
|
const val RETROFIT = "com.squareup.retrofit2:retrofit:${Version.RETROFIT}"
|
||||||
|
|
||||||
|
const val OKHTTP_LOGGING_INTERCEPTOR = "com.squareup.okhttp3:logging-interceptor:${Version.OKHTTP}"
|
||||||
|
const val OKHTTP = "com.squareup.okhttp3:okhttp-urlconnection:${Version.OKHTTP}"
|
||||||
|
|
||||||
|
const val MOSHI = "com.squareup.moshi:moshi:${Version.MOSHI}"
|
||||||
|
const val MOSHI_CODEGEN = "com.squareup.moshi:moshi-kotlin-codegen:${Version.MOSHI}"
|
||||||
|
const val MOSHI_RETROFIT = "com.squareup.retrofit2:converter-moshi:${Version.RETROFIT}"
|
||||||
|
|
||||||
|
const val COROUTINES_CORE = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Version.COROUTINES}"
|
||||||
|
const val COROUTINES_ANDROID = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Version.COROUTINES}"
|
||||||
|
|
||||||
|
const val CICERONE = "ru.terrakok.cicerone:cicerone:${Version.CICERONE}"
|
||||||
|
|
||||||
|
const val LEAK_CANARY = "com.squareup.leakcanary:leakcanary-android:${Version.LEAK_CANARY}"
|
||||||
|
const val CHUCKER = "com.github.chuckerteam.chucker:library:${Version.CHUCKER}"
|
||||||
|
const val CHUCKER_NO_OP = "com.github.chuckerteam.chucker:library-no-op:${Version.CHUCKER}"
|
||||||
|
|
||||||
|
const val FIREBASE_ANAL = "com.google.firebase:firebase-analytics-ktx:${Version.FIREBASE_ANAL}"
|
||||||
|
const val FIREBASE_PERF = "com.google.firebase:firebase-perf:${Version.FIREBASE_PERF}"
|
||||||
|
const val FIREBASE_CRASH = "com.google.firebase:firebase-crashlytics:${Version.FIREBASE_CRASH}"
|
||||||
|
|
||||||
|
const val ANDROIDX_SECURE = "androidx.security:security-crypto:${Version.ANDROIDX_SECURE}"
|
||||||
|
const val ANDROIDX_BIOMETRIC = "androidx.biometric:biometric:${Version.ANDROIDX_BIOMETRIC}"
|
||||||
|
|
||||||
|
const val LICENCE_LIBRARY = "com.google.android.gms:play-services-oss-licenses:${Version.LICENCE_LIBRARY}"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
object Module {
|
||||||
|
|
||||||
|
object RoboSwag {
|
||||||
|
const val UTILS = "utils"
|
||||||
|
const val LOGGING = "logging"
|
||||||
|
const val MVI_ARCH = "mvi-arch"
|
||||||
|
const val NAVIGATION_BASE = "navigation-base"
|
||||||
|
const val NAVIGATION_CICERONE = "navigation-cicerone"
|
||||||
|
const val STORABLE = "storable"
|
||||||
|
const val LIFECYCLE = "lifecycle"
|
||||||
|
const val VIEWS = "views"
|
||||||
|
const val RECYCLER_VIEW_ADAPTERS = "recyclerview-adapters"
|
||||||
|
const val RECYCLER_VIEW_DECORATORS = "recyclerview-decorators"
|
||||||
|
const val KOTLIN_EXTENSIONS = "kotlin-extensions"
|
||||||
|
}
|
||||||
|
|
||||||
|
object Feature {
|
||||||
|
const val LOGIN = "feature_login"
|
||||||
|
|
||||||
|
val ALL = listOf(
|
||||||
|
LOGIN
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Core {
|
||||||
|
const val NETWORK = "core_network"
|
||||||
|
const val PREFS = "core_prefs"
|
||||||
|
const val STRINGS = "core_strings"
|
||||||
|
const val UTILS = "core_utils"
|
||||||
|
const val UI = "core_ui"
|
||||||
|
const val DATA = "core_data"
|
||||||
|
const val DOMAIN = "core_domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
object Plugins {
|
||||||
|
const val ANDROID_APPLICATION = "com.android.application"
|
||||||
|
const val ANDROID_LIBRARY = "com.android.library"
|
||||||
|
|
||||||
|
const val ANDROID_APP_PLUGIN_WITH_DEFAULT_CONFIG = "android_app"
|
||||||
|
const val ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG = "android_lib"
|
||||||
|
|
||||||
|
const val KOTLIN_ANDROID = "kotlin-android"
|
||||||
|
const val KOTLIN_ANDROID_EXTENSIONS = "kotlin-android-extensions"
|
||||||
|
const val KOTLIN_KAPT = "kotlin-kapt"
|
||||||
|
const val LICENCE_PLUGIN = "com.google.android.gms.oss-licenses-plugin"
|
||||||
|
|
||||||
|
const val GOOGLE_SERVICES = "com.google.gms.google-services"
|
||||||
|
const val FIREBASE_CRASH = "com.google.firebase.crashlytics"
|
||||||
|
|
||||||
|
const val DEPENDENCY_GRAPH = "com.vanniktech.dependency.graph.generator"
|
||||||
|
|
||||||
|
const val DETEKT = "io.gitlab.arturbosch.detekt"
|
||||||
|
const val CPD = "de.aaschmid.cpd"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
object Version {
|
||||||
|
|
||||||
|
const val ANDROID_PLUGIN = "4.0.0"
|
||||||
|
|
||||||
|
const val KOTLIN = "1.3.72"
|
||||||
|
|
||||||
|
const val ANDROIDX = "1.1.0"
|
||||||
|
const val ANDROIDX_CORE = "1.2.0"
|
||||||
|
const val ANDROIDX_APPCOMPAT = "1.0.2"
|
||||||
|
const val ANDROIDX_CONSTRAINT = "2.0.0-beta4"
|
||||||
|
const val ANDROIDX_FRAGMENT = "1.2.1"
|
||||||
|
const val ANDROIDX_SECURE = "1.0.0-rc02"
|
||||||
|
const val ANDROIDX_BIOMETRIC = "1.0.1"
|
||||||
|
|
||||||
|
const val ANDROID_MATERIAL = "1.2.0-rc01"
|
||||||
|
const val SWIPE_TO_REFRESH = "1.0.0"
|
||||||
|
const val ANDROID_LIFECYCLE = "2.2.0"
|
||||||
|
|
||||||
|
const val PERMISSION_DISPATCHER = "4.8.0"
|
||||||
|
|
||||||
|
const val DAGGER = "2.27"
|
||||||
|
const val DAGGER_INJECT_ASSISTED = "0.5.2"
|
||||||
|
const val DAGGER_COMPONENT_MANAGER = "2.1.0"
|
||||||
|
|
||||||
|
const val GLIDE = "4.10.0"
|
||||||
|
|
||||||
|
const val RETROFIT = "2.8.1"
|
||||||
|
const val OKHTTP = "3.14.1"
|
||||||
|
|
||||||
|
const val MOSHI = "1.9.2"
|
||||||
|
|
||||||
|
const val COROUTINES = "1.3.7"
|
||||||
|
|
||||||
|
const val CICERONE = "5.1.0"
|
||||||
|
|
||||||
|
const val FIREBASE_ANAL = "17.4.3"
|
||||||
|
const val FIREBASE_CRASH = "17.1.0"
|
||||||
|
const val FIREBASE_PERF = "19.0.7"
|
||||||
|
const val GOOGLE_SERVICES_PLUGIN = "4.3.3"
|
||||||
|
const val FIREBASE_CRASH_PLUGIN = "2.2.0"
|
||||||
|
|
||||||
|
const val LEAK_CANARY = "2.4"
|
||||||
|
const val CHUCKER = "3.2.0"
|
||||||
|
|
||||||
|
const val LICENCE_LIBRARY = "17.0.0"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import com.android.build.gradle.BaseExtension
|
||||||
|
|
||||||
|
fun BaseExtension.addBuildType(
|
||||||
|
type: BuildType,
|
||||||
|
buildScriptDir: String
|
||||||
|
) {
|
||||||
|
buildTypes {
|
||||||
|
getByName(type.name) {
|
||||||
|
isMinifyEnabled = type.optimizeAndObfuscate
|
||||||
|
isShrinkResources = type.optimizeAndObfuscate
|
||||||
|
if (type.optimizeAndObfuscate) {
|
||||||
|
val proguardFile = if (AndroidConfig.RELEASE_DEBUGGABLE) "noObfuscate.pro" else "obfuscate.pro"
|
||||||
|
setProguardFiles(listOfNotNull(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"$buildScriptDir/proguard/$proguardFile",
|
||||||
|
"proguard/projectConfig.pro"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class BuildType(
|
||||||
|
val name: String,
|
||||||
|
val optimizeAndObfuscate: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
|
object Debug : BuildType(
|
||||||
|
name = "debug",
|
||||||
|
optimizeAndObfuscate = false
|
||||||
|
)
|
||||||
|
|
||||||
|
object Release : BuildType(
|
||||||
|
name = "release",
|
||||||
|
optimizeAndObfuscate = true
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ sealed class SSLPinningFlavour(
|
||||||
|
|
||||||
object OFF : SSLPinningFlavour(
|
object OFF : SSLPinningFlavour(
|
||||||
name = "withoutSSLPinning",
|
name = "withoutSSLPinning",
|
||||||
withSslPinning = false
|
withSslPinning = true
|
||||||
)
|
)
|
||||||
|
|
||||||
object ON : SSLPinningFlavour(
|
object ON : SSLPinningFlavour(
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ fun BaseExtension.configureSigningConfig(getRelativeFile: (String) -> File) {
|
||||||
create(SigningConfig.CONFIG_NAME) {
|
create(SigningConfig.CONFIG_NAME) {
|
||||||
storeFile = getRelativeFile(SigningConfig.PATH_TO_KEYSTORE_FILE)
|
storeFile = getRelativeFile(SigningConfig.PATH_TO_KEYSTORE_FILE)
|
||||||
storePassword = Environment.STORE_PASSWORD.getenv() ?: SigningConfig.DEFAULT_STORE_PASSWORD
|
storePassword = Environment.STORE_PASSWORD.getenv() ?: SigningConfig.DEFAULT_STORE_PASSWORD
|
||||||
keyAlias = Environment.ALIAS.getenv() ?: SigningConfig.DEFAULT_KEY_ALIAS
|
keyAlias = Environment.KEY_ALIAS.getenv() ?: SigningConfig.DEFAULT_KEY_ALIAS
|
||||||
keyPassword = Environment.KEY_PASSWORD.getenv() ?: SigningConfig.DEFAULT_KEY_PASSWORD
|
keyPassword = Environment.KEY_PASSWORD.getenv() ?: SigningConfig.DEFAULT_KEY_PASSWORD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import versioncatalog.androidApplicationPlugin
|
import Plugins
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.VersionCatalog
|
|
||||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
|
||||||
import org.gradle.kotlin.dsl.getByType
|
|
||||||
|
|
||||||
class AndroidAppPlugin : BaseAndroidPlugin() {
|
class AndroidAppPlugin : BaseAndroidPlugin() {
|
||||||
|
|
||||||
override fun apply(target: Project) {
|
override fun apply(target: Project) {
|
||||||
target.plugins.apply(target.libs.androidApplicationPlugin)
|
target.plugins.apply(Plugins.ANDROID_APPLICATION)
|
||||||
super.apply(target)
|
super.apply(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
|
import Plugins
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import versioncatalog.androidLibraryPlugin
|
|
||||||
|
|
||||||
class AndroidLibPlugin : BaseAndroidPlugin() {
|
class AndroidLibPlugin : BaseAndroidPlugin() {
|
||||||
|
|
||||||
override fun apply(target: Project) {
|
override fun apply(target: Project) {
|
||||||
target.plugins.apply(target.libs.androidLibraryPlugin)
|
target.plugins.apply(Plugins.ANDROID_LIBRARY)
|
||||||
super.apply(target)
|
super.apply(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,18 @@
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
|
import AndroidConfig
|
||||||
|
import BuildType
|
||||||
|
import Plugins
|
||||||
import com.android.build.gradle.BaseExtension
|
import com.android.build.gradle.BaseExtension
|
||||||
import versioncatalog.jvmBytecode
|
import kotlinStd
|
||||||
import org.gradle.api.JavaVersion
|
import org.gradle.api.JavaVersion
|
||||||
import org.gradle.api.Plugin
|
import org.gradle.api.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.Dependency
|
import org.gradle.api.artifacts.Dependency
|
||||||
import org.gradle.api.artifacts.VersionCatalog
|
|
||||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
|
||||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||||
import org.gradle.kotlin.dsl.dependencies
|
import org.gradle.kotlin.dsl.dependencies
|
||||||
import org.gradle.kotlin.dsl.getByType
|
import org.gradle.kotlin.dsl.getByType
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import versioncatalog.compileSdk
|
|
||||||
import versioncatalog.kotlinAndroidPlugin
|
|
||||||
import versioncatalog.kotlinKaptPlugin
|
|
||||||
import versioncatalog.minSdk
|
|
||||||
import versioncatalog.targetSdk
|
|
||||||
import versioncatalog.versionCode
|
|
||||||
import versioncatalog.versionName
|
|
||||||
|
|
||||||
abstract class BaseAndroidPlugin : Plugin<Project> {
|
abstract class BaseAndroidPlugin : Plugin<Project> {
|
||||||
override fun apply(target: Project) {
|
override fun apply(target: Project) {
|
||||||
|
|
@ -28,46 +22,51 @@ abstract class BaseAndroidPlugin : Plugin<Project> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Project.configurePlugins() {
|
private fun Project.configurePlugins() {
|
||||||
plugins.apply(libs.kotlinAndroidPlugin)
|
plugins.apply(Plugins.KOTLIN_ANDROID)
|
||||||
plugins.apply(libs.kotlinKaptPlugin)
|
plugins.apply(Plugins.KOTLIN_ANDROID_EXTENSIONS)
|
||||||
|
plugins.apply(Plugins.KOTLIN_KAPT)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Project.configureAndroid() = extensions.getByType<BaseExtension>().run {
|
private fun Project.configureAndroid() = extensions.getByType<BaseExtension>().run {
|
||||||
compileSdkVersion(libs.compileSdk.toInt())
|
compileSdkVersion(AndroidConfig.COMPILE_SDK_VERSION)
|
||||||
|
buildToolsVersion = AndroidConfig.BUILD_TOOLS_VERSION
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = libs.minSdk.toInt()
|
minSdkVersion(AndroidConfig.MIN_SDK_VERSION)
|
||||||
targetSdk = libs.targetSdk.toInt()
|
targetSdkVersion(AndroidConfig.TARGET_SDK_VERSION)
|
||||||
versionCode = libs.versionCode.toInt()
|
versionCode = AndroidConfig.VERSION_CODE
|
||||||
versionName = libs.versionName
|
versionName = AndroidConfig.VERSION_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.toVersion(libs.jvmBytecode)
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility = JavaVersion.toVersion(libs.jvmBytecode)
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
isCoreLibraryDesugaringEnabled = true
|
coreLibraryDesugaringEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures.apply {
|
buildFeatures.viewBinding = true
|
||||||
buildConfig = true
|
|
||||||
viewBinding = true
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(KotlinCompile::class.java) {
|
tasks.withType(KotlinCompile::class.java) {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = libs.jvmBytecode
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AndroidConfig.RELEASE_DEBUGGABLE) {
|
||||||
|
buildTypes {
|
||||||
|
getByName(BuildType.Release.name) {
|
||||||
|
isDebuggable = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Project.configureDependencies() = dependencies {
|
private fun Project.configureDependencies() = dependencies {
|
||||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
||||||
add("coreLibraryDesugaring", "com.android.tools:desugar_jdk_libs:2.0.4")
|
kotlinStd()
|
||||||
|
add("coreLibraryDesugaring", "com.android.tools:desugar_jdk_libs:1.0.5")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DependencyHandler.implementation(dependencyNotation: Any): Dependency? =
|
private fun DependencyHandler.implementation(dependencyNotation: Any): Dependency? =
|
||||||
add("implementation", dependencyNotation)
|
add("implementation", dependencyNotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val Project.libs: VersionCatalog
|
|
||||||
get() = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package versioncatalog
|
|
||||||
|
|
||||||
import org.gradle.api.artifacts.VersionCatalog
|
|
||||||
|
|
||||||
private fun VersionCatalog.getLibrary(library: String) = findLibrary(library).get()
|
|
||||||
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package versioncatalog
|
|
||||||
|
|
||||||
import org.gradle.api.artifacts.VersionCatalog
|
|
||||||
|
|
||||||
val VersionCatalog.androidApplicationPlugin: String
|
|
||||||
get() = findPlugin("android-application").get().orNull?.pluginId.toString()
|
|
||||||
|
|
||||||
val VersionCatalog.androidLibraryPlugin: String
|
|
||||||
get() = findPlugin("android-library").get().orNull?.pluginId.toString()
|
|
||||||
|
|
||||||
val VersionCatalog.kotlinAndroidPlugin: String
|
|
||||||
get() = findPlugin("kotlin-android").get().orNull?.pluginId.toString()
|
|
||||||
|
|
||||||
val VersionCatalog.kotlinKaptPlugin: String
|
|
||||||
get() = findPlugin("kotlin-kapt").get().orNull?.pluginId.toString()
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package versioncatalog
|
|
||||||
|
|
||||||
import org.gradle.api.artifacts.VersionCatalog
|
|
||||||
|
|
||||||
val VersionCatalog.compileSdk: String
|
|
||||||
get() = findVersion("compileSdk").get().requiredVersion
|
|
||||||
|
|
||||||
val VersionCatalog.minSdk: String
|
|
||||||
get() = findVersion("minSdk").get().requiredVersion
|
|
||||||
|
|
||||||
val VersionCatalog.targetSdk: String
|
|
||||||
get() = findVersion("targetSdk").get().requiredVersion
|
|
||||||
|
|
||||||
val VersionCatalog.jvmBytecode: String
|
|
||||||
get() = findVersion("jvmBytecode").get().requiredVersion
|
|
||||||
|
|
||||||
val VersionCatalog.versionCode: String
|
|
||||||
get() = findVersion("versionCode").get().requiredVersion
|
|
||||||
|
|
||||||
val VersionCatalog.versionName: String
|
|
||||||
get() = findVersion("versionName").get().requiredVersion
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 8f595d1a472afe437a56b8ce70ec6ac8e375c3ed
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template.core_data" />
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template.core_domain" />
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
// id("api-generator-android")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: uncomment api generator
|
||||||
|
//apiGenerator {
|
||||||
|
// pathToApiSchemes = "${AndroidConfig.COMMON_FOLDER}/api"
|
||||||
|
// outputPackageName = AndroidConfig.TEST_APP_ID
|
||||||
|
// outputLanguage = apigen.OutputLanguage.KotlinAndroid(
|
||||||
|
// methodOutputType = apigen.MethodOutputType.Coroutine
|
||||||
|
// )
|
||||||
|
//}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
retrofit()
|
||||||
|
dagger()
|
||||||
|
moshi()
|
||||||
|
coroutines()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template.core_network" />
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.touchin.template.network
|
||||||
|
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
fun ResponseBody.cloneBody(): String? = source()
|
||||||
|
.also { it.request(Long.MAX_VALUE) }
|
||||||
|
.buffer
|
||||||
|
?.clone()
|
||||||
|
?.readString(Charset.forName("UTF-8"))
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.touchin.template.network.di
|
||||||
|
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class ApiUrl
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.touchin.template.network.di
|
||||||
|
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class ChuckInterceptor
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package ru.touchin.template.network.di
|
||||||
|
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import okhttp3.CertificatePinner
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||||
|
import ru.touchin.template.network.interceptor.ExceptionsInterceptor
|
||||||
|
import ru.touchin.template.core_network.BuildConfig
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class NetworkModule {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TIMEOUT = 30L
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun providePublicClient(
|
||||||
|
exceptionsInterceptor: ExceptionsInterceptor,
|
||||||
|
@ChuckInterceptor chuckerInterceptor: Interceptor,
|
||||||
|
@WithSslPinning withSslPinning: Boolean
|
||||||
|
): OkHttpClient =
|
||||||
|
buildPublicClient(exceptionsInterceptor, chuckerInterceptor, withSslPinning)
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideMoshi() = buildMoshi()
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideRetrofit(client: OkHttpClient, moshi: Moshi, @ApiUrl apiUrl: String) = buildRetrofitInstance(client, moshi, apiUrl)
|
||||||
|
|
||||||
|
private fun buildMoshi() = Moshi.Builder()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private fun buildRetrofitInstance(client: OkHttpClient, moshi: Moshi, apiUrl: String): Retrofit = Retrofit.Builder()
|
||||||
|
.baseUrl(apiUrl)
|
||||||
|
.client(client)
|
||||||
|
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private fun buildPublicClient(
|
||||||
|
exceptionsInterceptor: ExceptionsInterceptor,
|
||||||
|
chuckerInterceptor: Interceptor,
|
||||||
|
withSslPinning: Boolean
|
||||||
|
): OkHttpClient = OkHttpClient.Builder()
|
||||||
|
.apply {
|
||||||
|
connectTimeout(TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
readTimeout(TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
writeTimeout(TIMEOUT, TimeUnit.SECONDS)
|
||||||
|
addInterceptor(exceptionsInterceptor)
|
||||||
|
addInterceptor(chuckerInterceptor)
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
addNetworkInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY })
|
||||||
|
}
|
||||||
|
if (withSslPinning) {
|
||||||
|
certificatePinner(CertificatePinner.DEFAULT)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package ru.touchin.template.network.di
|
||||||
|
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class WithSslPinning
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package ru.touchin.template.network.interceptor
|
||||||
|
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import ru.touchin.template.network.cloneBody
|
||||||
|
import ru.touchin.template.network.models.ServerException
|
||||||
|
import java.io.IOException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ExceptionsInterceptor @Inject constructor() : Interceptor {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ERROR_MESSAGE_FIELD = "errorMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response = chain
|
||||||
|
.proceed(chain.request())
|
||||||
|
.also { getError(it, it.body())?.let { exception -> throw exception } }
|
||||||
|
|
||||||
|
@Suppress("detekt.NestedBlockDepth")
|
||||||
|
private fun getError(response: Response, body: ResponseBody?): IOException? = body
|
||||||
|
?.cloneBody()
|
||||||
|
?.let { responseBody ->
|
||||||
|
try {
|
||||||
|
val jsonObject = JSONObject(responseBody)
|
||||||
|
val message = jsonObject.optString(ERROR_MESSAGE_FIELD)
|
||||||
|
when {
|
||||||
|
response.code() != 200 -> ServerException(response.code(), message)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
} catch (error: JSONException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.touchin.template.network.models
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
open class ServerException(val code: Int, message: String? = null) : IOException(message) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val codeToErrorTypeMap = mapOf(
|
||||||
|
1 to TemplateApiError.VALID_RESPONSE,
|
||||||
|
2 to TemplateApiError.INVALID_PARAMETERS
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getErrorTypeByCode(code: Int) = codeToErrorTypeMap[code]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getErrorType(): TemplateApiError? = codeToErrorTypeMap[code]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package ru.touchin.template.network.models
|
||||||
|
|
||||||
|
enum class TemplateApiError {
|
||||||
|
|
||||||
|
INVALID_PARAMETERS,
|
||||||
|
|
||||||
|
VALID_RESPONSE
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">My Library</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(Library.DAGGER)
|
||||||
|
implementationModule(Module.RoboSwag.STORABLE)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template.core_prefs" />
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package ru.touchin.template.core_prefs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.preference.PreferenceManager
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import ru.touchin.roboswag.components.utils.storables.PreferenceUtils
|
||||||
|
import ru.touchin.roboswag.core.observables.storable.NonNullStorable
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class PreferencesModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDefaultSharedPreferences(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideTutorialStorable(sharedPreferences: SharedPreferences): NonNullStorable<String, Boolean, Boolean> = PreferenceUtils
|
||||||
|
.booleanStorable("TUTORIAL_STORABLE", sharedPreferences, false)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
|
android {
|
||||||
|
ext["languageMap"] = mapOf("ru" to "${AndroidConfig.COMMON_FOLDER}/strings/default_common_strings_ru.json")
|
||||||
|
ext["rootPath"] = "core/core_strings"
|
||||||
|
}
|
||||||
|
|
||||||
|
//gradle.projectsEvaluated {
|
||||||
|
// tasks.named("preBuild") {
|
||||||
|
// dependsOn("stringGenerator")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//apply(from = "${rootProject.ext["buildScriptsDir"]}/gradle/stringGenerator.gradle")
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template" />
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="common_global_yes" formatted="false">Да</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template.core_ui" />
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
plugins {
|
||||||
|
id(Plugins.ANDROID_LIB_PLUGIN_WITH_DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<manifest package="ru.touchin.template.core_utils" />
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
/build
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
plugins {
|
|
||||||
id(libs.plugins.android.lib.get().pluginId)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val serverType = Environment.SERVER_ENVIRONMENT.getenv()?.takeIf(String::isNotBlank)
|
|
||||||
private val versionCatalog: VersionCatalog
|
|
||||||
get() = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "ru.template.data"
|
|
||||||
|
|
||||||
addLibBuildType(type = BuildType.Develop, enableConfig = true, versionCatalog = versionCatalog)
|
|
||||||
addLibBuildType(type = BuildType.Debug, enableConfig = true, versionCatalog = versionCatalog)
|
|
||||||
addLibBuildType(type = BuildType.Customer, enableConfig = true, versionCatalog = versionCatalog)
|
|
||||||
addLibBuildType(type = BuildType.Release, enableConfig = true, versionCatalog = versionCatalog)
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
getByName("main") {
|
|
||||||
java.srcDirs("src/main/kotlin")
|
|
||||||
}
|
|
||||||
getByName("androidTest") {
|
|
||||||
java.srcDirs("src/androidTest/kotlin")
|
|
||||||
}
|
|
||||||
getByName("test") {
|
|
||||||
java.srcDirs("src/test/kotlin")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addMobileServicesFlavor()
|
|
||||||
|
|
||||||
testOptions {
|
|
||||||
unitTests {
|
|
||||||
isReturnDefaultValues = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(project(":domain"))
|
|
||||||
implementation(project(":mobile_services"))
|
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
|
||||||
androidTestImplementation(libs.androidx.test.ext.junit)
|
|
||||||
androidTestImplementation(libs.espresso.core)
|
|
||||||
}
|
|
||||||
|
|
||||||
val Project.buildScriptDir: String
|
|
||||||
get() = rootProject.ext["buildScriptsDir"] as String
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue