Initial commit
							
								
								
									
										15
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | |||||||
|  | *.iml | ||||||
|  | .gradle | ||||||
|  | /local.properties | ||||||
|  | /.idea/caches | ||||||
|  | /.idea/libraries | ||||||
|  | /.idea/modules.xml | ||||||
|  | /.idea/workspace.xml | ||||||
|  | /.idea/navEditor.xml | ||||||
|  | /.idea/assetWizardSettings.xml | ||||||
|  | .DS_Store | ||||||
|  | /build | ||||||
|  | /captures | ||||||
|  | .externalNativeBuild | ||||||
|  | .cxx | ||||||
|  | local.properties | ||||||
							
								
								
									
										2
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,2 @@ | |||||||
|  | /build | ||||||
|  | /.idea | ||||||
							
								
								
									
										81
									
								
								app/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,81 @@ | |||||||
|  | plugins { | ||||||
|  |     id("com.android.application") | ||||||
|  |     id("org.jetbrains.kotlin.android") | ||||||
|  |     id("com.google.devtools.ksp") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Не изменяйте ничего при сборки. Все изменения будут проигнорированы | ||||||
|  |  **/ | ||||||
|  | android { | ||||||
|  |     namespace = "ru.samsung.smartintercom" | ||||||
|  |     compileSdk = 34 | ||||||
|  |  | ||||||
|  |     defaultConfig { | ||||||
|  |         applicationId = "ru.samsung.smartintercom" | ||||||
|  |         minSdk = 24 | ||||||
|  |         targetSdk = 33 | ||||||
|  |         versionCode = 1 | ||||||
|  |         versionName = "1.0" | ||||||
|  |  | ||||||
|  |         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||||
|  |         vectorDrawables { | ||||||
|  |             useSupportLibrary = true | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     buildTypes { | ||||||
|  |         release { | ||||||
|  |             isMinifyEnabled = false | ||||||
|  |             proguardFiles( | ||||||
|  |                 getDefaultProguardFile("proguard-android-optimize.txt"), | ||||||
|  |                 "proguard-rules.pro" | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     compileOptions { | ||||||
|  |         sourceCompatibility = JavaVersion.VERSION_1_8 | ||||||
|  |         targetCompatibility = JavaVersion.VERSION_1_8 | ||||||
|  |     } | ||||||
|  |     kotlinOptions { | ||||||
|  |         jvmTarget = "1.8" | ||||||
|  |     } | ||||||
|  |     buildFeatures { | ||||||
|  |         compose = true | ||||||
|  |     } | ||||||
|  |     composeOptions { | ||||||
|  |         kotlinCompilerExtensionVersion = "1.5.2" | ||||||
|  |     } | ||||||
|  |     packaging { | ||||||
|  |         resources { | ||||||
|  |             excludes += "/META-INF/{AL2.0,LGPL2.1}" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Используйте только разрешённые библиотеки | ||||||
|  |  **/ | ||||||
|  | dependencies { | ||||||
|  |     implementation("androidx.core:core-ktx:1.12.0") | ||||||
|  |     implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") | ||||||
|  |     implementation("androidx.activity:activity-compose:1.7.0") | ||||||
|  |     implementation(platform("androidx.compose:compose-bom:2023.03.00")) | ||||||
|  |     implementation("androidx.compose.ui:ui") | ||||||
|  |     implementation("androidx.compose.ui:ui-graphics") | ||||||
|  |     implementation("androidx.compose.ui:ui-tooling-preview") | ||||||
|  |     implementation("androidx.compose.material3:material3") | ||||||
|  |     implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2") | ||||||
|  |     implementation("androidx.navigation:navigation-compose:2.7.4") | ||||||
|  |  | ||||||
|  |     implementation("com.squareup.retrofit2:retrofit:2.9.0") | ||||||
|  |     implementation("com.squareup.retrofit2:converter-gson:2.9.0") | ||||||
|  |  | ||||||
|  |     implementation("com.google.dagger:dagger:2.48") | ||||||
|  |     ksp("com.google.dagger:dagger-compiler:2.48") | ||||||
|  |  | ||||||
|  |     implementation("io.coil-kt:coil-compose:2.4.0") | ||||||
|  |  | ||||||
|  |     implementation("io.ktor:ktor-network:2.3.5") | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | |||||||
|  | # Add project specific ProGuard rules here. | ||||||
|  | # You can control the set of applied configuration files using the | ||||||
|  | # proguardFiles setting in build.gradle. | ||||||
|  | # | ||||||
|  | # For more details, see | ||||||
|  | #   http://developer.android.com/guide/developing/tools/proguard.html | ||||||
|  |  | ||||||
|  | # If your project uses WebView with JS, uncomment the following | ||||||
|  | # and specify the fully qualified class name to the JavaScript interface | ||||||
|  | # class: | ||||||
|  | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||||||
|  | #   public *; | ||||||
|  | #} | ||||||
|  |  | ||||||
|  | # Uncomment this to preserve the line number information for | ||||||
|  | # debugging stack traces. | ||||||
|  | #-keepattributes SourceFile,LineNumberTable | ||||||
|  |  | ||||||
|  | # If you keep the line number information, uncomment this to | ||||||
|  | # hide the original source file name. | ||||||
|  | #-renamesourcefileattribute SourceFile | ||||||
							
								
								
									
										35
									
								
								app/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     xmlns:tools="http://schemas.android.com/tools"> | ||||||
|  |  | ||||||
|  |     <uses-permission android:name="android.permission.INTERNET" /> | ||||||
|  |  | ||||||
|  |     <application | ||||||
|  |         android:name=".App" | ||||||
|  |         android:allowBackup="true" | ||||||
|  |         android:dataExtractionRules="@xml/data_extraction_rules" | ||||||
|  |         android:fullBackupContent="@xml/backup_rules" | ||||||
|  |         android:icon="@mipmap/ic_launcher" | ||||||
|  |         android:label="@string/app_name" | ||||||
|  |         android:roundIcon="@mipmap/ic_launcher_round" | ||||||
|  |         android:supportsRtl="true" | ||||||
|  |         android:theme="@style/Theme.SmartIntercom" | ||||||
|  |         android:usesCleartextTraffic="true" | ||||||
|  |         tools:targetApi="33"> | ||||||
|  |         <!-- НЕ ИЗМЕНЯЙТЕ ПАКЕТ И АКТИВИТИ ДЛЯ ЗАПУСКА --> | ||||||
|  |         <!-- ДОБАВЛЯТЬ НОВЫЕ - МОЖНО --> | ||||||
|  |         <activity | ||||||
|  |             android:name=".ui.activity.MainActivity" | ||||||
|  |             android:exported="true" | ||||||
|  |             android:label="@string/app_name" | ||||||
|  |             android:theme="@style/Theme.SmartIntercom" | ||||||
|  |             android:windowSoftInputMode="adjustResize"> | ||||||
|  |             <intent-filter> | ||||||
|  |                 <action android:name="android.intent.action.MAIN" /> | ||||||
|  |  | ||||||
|  |                 <category android:name="android.intent.category.LAUNCHER" /> | ||||||
|  |             </intent-filter> | ||||||
|  |         </activity> | ||||||
|  |     </application> | ||||||
|  |  | ||||||
|  | </manifest> | ||||||
							
								
								
									
										11
									
								
								app/src/main/java/ru/samsung/smartintercom/App.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | |||||||
|  | package ru.samsung.smartintercom | ||||||
|  |  | ||||||
|  | import android.app.Application | ||||||
|  | import ru.samsung.smartintercom.di.ContextModule | ||||||
|  | import ru.samsung.smartintercom.di.DaggerAppComponent | ||||||
|  |  | ||||||
|  | class App : Application() { | ||||||
|  |     val appComponent = DaggerAppComponent.builder() | ||||||
|  |         .contextModule(ContextModule(this)) | ||||||
|  |         .build() | ||||||
|  | } | ||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | /* НЕ ИЗМЕНЯЙТЕ ФАЙЛ! */ | ||||||
|  | /* ВСЕ ИЗМЕНЕНИЯ ПРИ ТЕСТИРОВАНИИ БУДУТ ОТМЕНЕНЫ */ | ||||||
|  | package ru.samsung.smartintercom.core | ||||||
|  |  | ||||||
|  | typealias ComposeIds = String | ||||||
|  |  | ||||||
|  | object MainScreenId { | ||||||
|  |     const val screenId: ComposeIds = "main_screen" | ||||||
|  |     const val buttonStart: ComposeIds = "button_start" | ||||||
|  |     const val buttonRetry: ComposeIds = "button_retry" | ||||||
|  |     const val textIntercomModel: ComposeIds = "text_intercom_model" | ||||||
|  |     const val buttonTakePhoto: ComposeIds = "button_take_photo" | ||||||
|  |     const val imageIntercom: ComposeIds = "image_intercom" | ||||||
|  |     const val textError: ComposeIds = "text_error" | ||||||
|  |     const val buttonSettings: ComposeIds = "button_settings" | ||||||
|  |     const val buttonHistory: ComposeIds = "button_history" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | object SettingScreenId { | ||||||
|  |     const val screenId: ComposeIds = "setting_screen" | ||||||
|  |     const val inputHouse: ComposeIds = "input_house" | ||||||
|  |     const val inputFlat: ComposeIds = "input_flat" | ||||||
|  |     const val buttonSave: ComposeIds = "button_save" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | object CallScreenId { | ||||||
|  |     const val screenId: ComposeIds = "call_screen" | ||||||
|  |     const val buttonOpen: ComposeIds = "button_open" | ||||||
|  |     const val buttonClose: ComposeIds = "button_close" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | object CallHistoryId { | ||||||
|  |     const val screenId: ComposeIds = "history_screen" | ||||||
|  |     const val recycler: ComposeIds = "recycler" | ||||||
|  |     const val textDate: ComposeIds = "text_date" | ||||||
|  |     const val textStatus: ComposeIds = "text_status" | ||||||
|  | } | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | /* НЕ ИЗМЕНЯЙТЕ ФАЙЛ! */ | ||||||
|  | /* ВСЕ ИЗМЕНЕНИЯ ПРИ ТЕСТИРОВАНИИ БУДУТ ОТМЕНЕНЫ */ | ||||||
|  | package ru.samsung.smartintercom.core | ||||||
|  |  | ||||||
|  | object CoreConstants { | ||||||
|  |     const val HOST = "http://89.208.220.227:82/" | ||||||
|  |     const val HEADER_FLAT = "flat" | ||||||
|  |     const val HEADER_HOUSE = "house" | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package ru.samsung.smartintercom.data.auth.dto | ||||||
|  |  | ||||||
|  | import com.google.gson.annotations.SerializedName | ||||||
|  |  | ||||||
|  | data class AuthDto( | ||||||
|  |     @SerializedName("model") | ||||||
|  |     val model: String | ||||||
|  | ) | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | package ru.samsung.smartintercom.data.auth.repo | ||||||
|  |  | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.flow | ||||||
|  | import ru.samsung.smartintercom.domain.auth.AuthRepository | ||||||
|  | import ru.samsung.smartintercom.domain.auth.model.AuthEntity | ||||||
|  | import javax.inject.Inject | ||||||
|  | import javax.inject.Singleton | ||||||
|  |  | ||||||
|  | @Singleton | ||||||
|  | class AuthRepositoryImpl @Inject constructor() : AuthRepository { | ||||||
|  |  | ||||||
|  |     // TODO: Необходимо переопределить праивильно функцию | ||||||
|  |     override val authData: Flow<AuthEntity?> get() = flow { emit(null) } | ||||||
|  | } | ||||||
| @@ -0,0 +1,102 @@ | |||||||
|  | /* НЕ ИЗМЕНЯЙТЕ ФАЙЛ! */ | ||||||
|  | /* ВСЕ ИЗМЕНЕНИЯ ПРИ ТЕСТИРОВАНИИ БУДУТ ОТМЕНЕНЫ */ | ||||||
|  | package ru.samsung.smartintercom.data.call | ||||||
|  |  | ||||||
|  | import android.util.Log | ||||||
|  | import com.google.gson.Gson | ||||||
|  | import io.ktor.network.selector.SelectorManager | ||||||
|  | import io.ktor.network.sockets.Socket | ||||||
|  | import io.ktor.network.sockets.aSocket | ||||||
|  | import io.ktor.network.sockets.isClosed | ||||||
|  | import io.ktor.network.sockets.openReadChannel | ||||||
|  | import io.ktor.network.sockets.openWriteChannel | ||||||
|  | import io.ktor.utils.io.writeStringUtf8 | ||||||
|  | import kotlinx.coroutines.CoroutineScope | ||||||
|  | import kotlinx.coroutines.Dispatchers | ||||||
|  | import kotlinx.coroutines.delay | ||||||
|  | import kotlinx.coroutines.flow.MutableSharedFlow | ||||||
|  | import kotlinx.coroutines.flow.asSharedFlow | ||||||
|  | import kotlinx.coroutines.launch | ||||||
|  | import kotlinx.coroutines.withContext | ||||||
|  | import javax.inject.Inject | ||||||
|  | import javax.inject.Singleton | ||||||
|  |  | ||||||
|  | @Singleton | ||||||
|  | class CallDataSource @Inject constructor( | ||||||
|  |     private val gson: Gson | ||||||
|  | ) { | ||||||
|  |     private val _status = MutableSharedFlow<Status>(replay = 1) | ||||||
|  |     val status get() = _status.asSharedFlow() | ||||||
|  |  | ||||||
|  |     private var socketInfo: SocketInfo? = null | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     suspend fun connect(authDto: SocketAuthDto) { | ||||||
|  |         if (socketInfo != null) return | ||||||
|  |  | ||||||
|  |         CoroutineScope(Dispatchers.IO).launch { | ||||||
|  |             try { | ||||||
|  |                 val selectorManager = SelectorManager(Dispatchers.IO) | ||||||
|  |                 val socket = aSocket(selectorManager).tcp().connect(HOSTNAME, PORT) | ||||||
|  |                 socketInfo = SocketInfo( | ||||||
|  |                     socket = socket, | ||||||
|  |                     selectorManager = selectorManager, | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |                 val receiveChannel = socket.openReadChannel() | ||||||
|  |                 val sendChannel = socket.openWriteChannel(autoFlush = true) | ||||||
|  |                 sendChannel.writeStringUtf8("${gson.toJson(authDto)}\n") | ||||||
|  |                 _status.emit(Status.Connect) | ||||||
|  |                 while (!socket.isClosed) { | ||||||
|  |                     val message = receiveChannel.readUTF8Line(limit = 100) | ||||||
|  |                     if (message != null) { | ||||||
|  |                         _status.emit(Status.Message(body = message)) | ||||||
|  |                     } else { | ||||||
|  |                         Log.d("Socket", "Server closed a connection") | ||||||
|  |                         close(socket = socket, selectorManager = selectorManager) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 e.printStackTrace() | ||||||
|  |                 delay(TIMEOUT) | ||||||
|  |                 socketInfo = null | ||||||
|  |                 _status.emit(Status.Close) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     suspend fun close() { | ||||||
|  |         val data = socketInfo ?: return | ||||||
|  |         close(socket = data.socket, selectorManager = data.selectorManager) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private suspend fun close( | ||||||
|  |         socket: Socket, | ||||||
|  |         selectorManager: SelectorManager | ||||||
|  |     ) { | ||||||
|  |         withContext(Dispatchers.IO) { | ||||||
|  |             socket.close() | ||||||
|  |             selectorManager.close() | ||||||
|  |             socketInfo = null | ||||||
|  |             _status.emit(Status.Close) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     sealed interface Status { | ||||||
|  |         data object Connect : Status | ||||||
|  |         data class Message(val body: String) : Status | ||||||
|  |         data object Close : Status | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private data class SocketInfo( | ||||||
|  |         val socket: Socket, | ||||||
|  |         val selectorManager: SelectorManager, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     private companion object { | ||||||
|  |         const val HOSTNAME = "89.208.220.227" | ||||||
|  |         const val PORT = 9202 | ||||||
|  |         const val TIMEOUT = 5000L | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,63 @@ | |||||||
|  | /* НЕ ИЗМЕНЯЙТЕ ФАЙЛ! */ | ||||||
|  | /* ВСЕ ИЗМЕНЕНИЯ ПРИ ТЕСТИРОВАНИИ БУДУТ ОТМЕНЕНЫ */ | ||||||
|  | package ru.samsung.smartintercom.data.call | ||||||
|  |  | ||||||
|  | import android.util.Log | ||||||
|  | import dagger.Reusable | ||||||
|  | import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||||
|  | import kotlinx.coroutines.channels.BufferOverflow | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.buffer | ||||||
|  | import kotlinx.coroutines.flow.flatMapLatest | ||||||
|  | import kotlinx.coroutines.flow.map | ||||||
|  | import kotlinx.coroutines.flow.mapNotNull | ||||||
|  | import ru.samsung.smartintercom.domain.auth.AuthRepository | ||||||
|  | import ru.samsung.smartintercom.domain.auth.model.AuthEntity | ||||||
|  | import ru.samsung.smartintercom.domain.call.CallRepository | ||||||
|  | import javax.inject.Inject | ||||||
|  |  | ||||||
|  | @OptIn(ExperimentalCoroutinesApi::class) | ||||||
|  | @Reusable | ||||||
|  | class CallRepositoryImpl @Inject constructor( | ||||||
|  |     authRepo: AuthRepository, | ||||||
|  |     private val callDataSource: CallDataSource, | ||||||
|  | ) : CallRepository { | ||||||
|  |     override val intercomCallStart: Flow<Unit> = authRepo.authData | ||||||
|  |         .flatMapLatest { data -> | ||||||
|  |             if (data == null) { | ||||||
|  |                 callDataSource.close() | ||||||
|  |             } else { | ||||||
|  |                 reconnectSocket(data) | ||||||
|  |             } | ||||||
|  |             callDataSource.status.map { status -> status to data } | ||||||
|  |         } | ||||||
|  |         .mapNotNull { (status, authData) -> | ||||||
|  |             when (status) { | ||||||
|  |                 is CallDataSource.Status.Close -> { | ||||||
|  |                     Log.d(TAG, "Close") | ||||||
|  |                     if (authData != null) reconnectSocket(authData) | ||||||
|  |                     null | ||||||
|  |                 } | ||||||
|  |                 is CallDataSource.Status.Connect -> { | ||||||
|  |                     Log.d(TAG, "Connect") | ||||||
|  |                     null | ||||||
|  |                 } | ||||||
|  |                 is CallDataSource.Status.Message -> { | ||||||
|  |                     Log.d(TAG, "Message") | ||||||
|  |                     Unit | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         .buffer( | ||||||
|  |             capacity = 0, | ||||||
|  |             BufferOverflow.DROP_OLDEST | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     private suspend fun reconnectSocket(authEntity: AuthEntity) { | ||||||
|  |         callDataSource.connect(SocketAuthDto(house = authEntity.house, room = authEntity.room)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private companion object { | ||||||
|  |         const val TAG = "SOCKET" | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | package ru.samsung.smartintercom.data.call | ||||||
|  |  | ||||||
|  | data class SocketAuthDto( | ||||||
|  |     val house: String, | ||||||
|  |     val room: String, | ||||||
|  | ) | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | package ru.samsung.smartintercom.di | ||||||
|  |  | ||||||
|  | import dagger.Component | ||||||
|  | import javax.inject.Singleton | ||||||
|  |  | ||||||
|  | @Component( | ||||||
|  |     modules = [ | ||||||
|  |         AppModule::class, | ||||||
|  |         ContextModule::class, | ||||||
|  |     ] | ||||||
|  | ) | ||||||
|  | @Singleton | ||||||
|  | interface AppComponent : AppProvides | ||||||
							
								
								
									
										25
									
								
								app/src/main/java/ru/samsung/smartintercom/di/AppModule.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,25 @@ | |||||||
|  | package ru.samsung.smartintercom.di | ||||||
|  |  | ||||||
|  | import android.content.Context | ||||||
|  | import android.content.SharedPreferences | ||||||
|  | import dagger.Binds | ||||||
|  | import dagger.Module | ||||||
|  | import dagger.Provides | ||||||
|  | import ru.samsung.smartintercom.data.auth.repo.AuthRepositoryImpl | ||||||
|  | import ru.samsung.smartintercom.data.call.CallRepositoryImpl | ||||||
|  | import ru.samsung.smartintercom.domain.auth.AuthRepository | ||||||
|  | import ru.samsung.smartintercom.domain.call.CallRepository | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Module | ||||||
|  | interface AppModule { | ||||||
|  |     @Binds | ||||||
|  |     fun authRepo(authRepositoryImpl: AuthRepositoryImpl): AuthRepository | ||||||
|  |     @Binds | ||||||
|  |     fun callRepo(callRepositoryImpl: CallRepositoryImpl): CallRepository | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         @Provides | ||||||
|  |         fun provideSharedPrefs(context: Context): SharedPreferences = context.getSharedPreferences("PREFS", Context.MODE_PRIVATE) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | package ru.samsung.smartintercom.di | ||||||
|  |  | ||||||
|  | import ru.samsung.smartintercom.domain.auth.AuthRepository | ||||||
|  | import ru.samsung.smartintercom.domain.call.CallRepository | ||||||
|  |  | ||||||
|  | interface AppProvides { | ||||||
|  |     fun authRepo(): AuthRepository | ||||||
|  |     fun callRepo(): CallRepository | ||||||
|  | } | ||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | package ru.samsung.smartintercom.di | ||||||
|  |  | ||||||
|  | import android.content.Context | ||||||
|  | import com.google.gson.Gson | ||||||
|  | import dagger.Module | ||||||
|  | import dagger.Provides | ||||||
|  | import javax.inject.Singleton | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Module | ||||||
|  | class ContextModule(val context: Context) { | ||||||
|  |  | ||||||
|  |     @Singleton | ||||||
|  |     @Provides | ||||||
|  |     fun provideContext() = context | ||||||
|  |  | ||||||
|  |     @Singleton | ||||||
|  |     @Provides | ||||||
|  |     fun provideGson() = Gson() | ||||||
|  | } | ||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | package ru.samsung.smartintercom.domain.auth | ||||||
|  |  | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import ru.samsung.smartintercom.domain.auth.model.AuthEntity | ||||||
|  |  | ||||||
|  | interface AuthRepository { | ||||||
|  |     /** | ||||||
|  |      * Данное значение передаёт при каждом изменении новое значение сущности авторизации | ||||||
|  |      * в случае, если пользователь неавторизован - необходимо передать null | ||||||
|  |      */ | ||||||
|  |     val authData: Flow<AuthEntity?> | ||||||
|  | } | ||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | package ru.samsung.smartintercom.domain.auth.model | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Информация о пользователе, необходимой для похода в API | ||||||
|  |  * | ||||||
|  |  * @param house номер дома | ||||||
|  |  * @param room номер комнаты | ||||||
|  |  */ | ||||||
|  | data class AuthEntity( | ||||||
|  |     val house: String, | ||||||
|  |     val room: String, | ||||||
|  | ) | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | package ru.samsung.smartintercom.domain.call | ||||||
|  |  | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
|  | interface CallRepository { | ||||||
|  |     val intercomCallStart: Flow<Unit> | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | package ru.samsung.smartintercom.domain.call | ||||||
|  |  | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import javax.inject.Inject | ||||||
|  |  | ||||||
|  | class GetCallNeededUseCase @Inject constructor( | ||||||
|  |     private val callRepository: CallRepository | ||||||
|  | ) { | ||||||
|  |     fun execute(): Flow<Unit> = callRepository.intercomCallStart | ||||||
|  | } | ||||||
| @@ -0,0 +1,51 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.activity | ||||||
|  |  | ||||||
|  | import android.os.Bundle | ||||||
|  | import androidx.activity.ComponentActivity | ||||||
|  | import androidx.activity.compose.setContent | ||||||
|  | import androidx.compose.foundation.layout.fillMaxSize | ||||||
|  | import androidx.compose.material3.MaterialTheme | ||||||
|  | import androidx.compose.material3.Surface | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.navigation.compose.rememberNavController | ||||||
|  | import ru.samsung.smartintercom.ui.activity.di.MainActivityComponent | ||||||
|  | import ru.samsung.smartintercom.ui.nav.Navigation | ||||||
|  | import ru.samsung.smartintercom.ui.nav.Screen | ||||||
|  | import ru.samsung.smartintercom.ui.nav.navigate | ||||||
|  | import ru.samsung.smartintercom.ui.screen.main.MainScreen | ||||||
|  | import ru.samsung.smartintercom.ui.theme.SmartIntercomTheme | ||||||
|  | import ru.samsung.smartintercom.utils.collectAsEffect | ||||||
|  | import ru.samsung.smartintercom.utils.daggerViewModel | ||||||
|  |  | ||||||
|  | class MainActivity : ComponentActivity() { | ||||||
|  |     override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|  |         super.onCreate(savedInstanceState) | ||||||
|  |         setContent { | ||||||
|  |             SmartIntercomTheme { | ||||||
|  |                 // A surface container using the 'background' color from the theme | ||||||
|  |                 Surface( | ||||||
|  |                     modifier = Modifier.fillMaxSize(), | ||||||
|  |                     color = MaterialTheme.colorScheme.background | ||||||
|  |                 ) { | ||||||
|  |                     val navController = rememberNavController() | ||||||
|  |                     Navigation(navController = navController) | ||||||
|  |                     val component = MainActivityComponent.build() | ||||||
|  |                     val viewModel = daggerViewModel { component.viewModel } | ||||||
|  |                     viewModel.openCallScreen.collectAsEffect { | ||||||
|  |                         navController.navigate(Screen.CALL) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Preview(showBackground = true, device = "spec:width=1080px,height=1920px,dpi=320") | ||||||
|  | @Composable | ||||||
|  | fun GreetingPreview() { | ||||||
|  |     SmartIntercomTheme { | ||||||
|  |         MainScreen.Render(rememberNavController()) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.activity | ||||||
|  |  | ||||||
|  | import androidx.lifecycle.ViewModel | ||||||
|  | import androidx.lifecycle.viewModelScope | ||||||
|  | import kotlinx.coroutines.flow.SharedFlow | ||||||
|  | import kotlinx.coroutines.flow.asSharedFlow | ||||||
|  | import kotlinx.coroutines.launch | ||||||
|  | import ru.samsung.smartintercom.domain.call.GetCallNeededUseCase | ||||||
|  | import ru.samsung.smartintercom.utils.MutablePublishFlow | ||||||
|  | import javax.inject.Inject | ||||||
|  |  | ||||||
|  | class MainActivityViewModel @Inject constructor( | ||||||
|  |     private val getCallNeededUseCase: GetCallNeededUseCase | ||||||
|  | ) : ViewModel() { | ||||||
|  |     val openCallScreen: SharedFlow<Unit> get() = _openCallScreen.asSharedFlow() | ||||||
|  |     private val _openCallScreen = MutablePublishFlow<Unit>() | ||||||
|  |  | ||||||
|  |     init { | ||||||
|  |         viewModelScope.launch { | ||||||
|  |             getCallNeededUseCase.execute().collect { | ||||||
|  |                 _openCallScreen.emit(Unit) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.activity.di | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.platform.LocalContext | ||||||
|  | import dagger.Component | ||||||
|  | import ru.samsung.smartintercom.App | ||||||
|  | import ru.samsung.smartintercom.di.AppComponent | ||||||
|  | import ru.samsung.smartintercom.ui.activity.MainActivityViewModel | ||||||
|  |  | ||||||
|  | @Component(dependencies = [AppComponent::class]) | ||||||
|  | @MainActivityScope | ||||||
|  | interface MainActivityComponent { | ||||||
|  |  | ||||||
|  |     @Component.Factory | ||||||
|  |     interface Factory { | ||||||
|  |         fun create(appComponent: AppComponent): MainActivityComponent | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val viewModel: MainActivityViewModel | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         @Composable | ||||||
|  |         fun build(): MainActivityComponent { | ||||||
|  |             return DaggerMainActivityComponent.factory().create( | ||||||
|  |                 (LocalContext.current.applicationContext as App).appComponent | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.activity.di | ||||||
|  |  | ||||||
|  | import javax.inject.Scope | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Scope | ||||||
|  | @Retention(AnnotationRetention.RUNTIME) | ||||||
|  | annotation class MainActivityScope | ||||||
| @@ -0,0 +1,34 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.nav | ||||||
|  |  | ||||||
|  | import androidx.compose.animation.EnterTransition | ||||||
|  | import androidx.compose.animation.ExitTransition | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.navigation.NavController | ||||||
|  | import androidx.navigation.NavHostController | ||||||
|  | import androidx.navigation.compose.NavHost | ||||||
|  | import androidx.navigation.compose.composable | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Данная функция инициализирует граф инициализации | ||||||
|  |  */ | ||||||
|  | @Composable | ||||||
|  | fun Navigation(navController: NavHostController) { | ||||||
|  |     NavHost( | ||||||
|  |         navController = navController, | ||||||
|  |         startDestination = Screen.MAIN.route, | ||||||
|  |         enterTransition = { EnterTransition.None }, | ||||||
|  |         exitTransition = { ExitTransition.None } | ||||||
|  |     ) | ||||||
|  |     { | ||||||
|  |         // Здесь происходит перебор функций для инициализации всех возможных экранов | ||||||
|  |         Screen.entries.forEach { screen -> | ||||||
|  |             composable(route = screen.route) { | ||||||
|  |                 screen.baseScreen.Render(navController) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fun NavController.navigate(screen: Screen) { | ||||||
|  |     navigate(route = screen.route) | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								app/src/main/java/ru/samsung/smartintercom/ui/nav/Screen.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.nav | ||||||
|  |  | ||||||
|  | import ru.samsung.smartintercom.ui.screen.ScreenBaseData | ||||||
|  | import ru.samsung.smartintercom.ui.screen.call.CallScreen | ||||||
|  | import ru.samsung.smartintercom.ui.screen.main.MainScreen | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Класс, в котором перечислены все экраны | ||||||
|  |  * | ||||||
|  |  * @param route путь до экрана | ||||||
|  |  * @param baseScreen сущность экрана, которая будет отрендерена при открытии | ||||||
|  |  */ | ||||||
|  | enum class Screen(val route: String, internal val baseScreen: ScreenBaseData) { | ||||||
|  |     MAIN("main", MainScreen), | ||||||
|  |     CALL("call", CallScreen), | ||||||
|  | } | ||||||
| @@ -0,0 +1,22 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.navigation.NavController | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Базовый интерфейс экрана | ||||||
|  |  */ | ||||||
|  | interface ScreenBaseData { | ||||||
|  |     /** | ||||||
|  |      * Название экрана | ||||||
|  |      */ | ||||||
|  |     val name: String | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Функция, вызываемая при отрисовки экрана | ||||||
|  |      * | ||||||
|  |      * @param navController контроллер, который необходим для открытия других экранов | ||||||
|  |      */ | ||||||
|  |     @Composable | ||||||
|  |     fun Render(navController: NavController) | ||||||
|  | } | ||||||
| @@ -0,0 +1,135 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.call | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.Arrangement | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.RowScope | ||||||
|  | import androidx.compose.foundation.layout.Spacer | ||||||
|  | import androidx.compose.foundation.layout.fillMaxWidth | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.foundation.layout.width | ||||||
|  | import androidx.compose.foundation.layout.wrapContentHeight | ||||||
|  | import androidx.compose.material3.Button | ||||||
|  | import androidx.compose.material3.ButtonDefaults | ||||||
|  | import androidx.compose.material3.ExperimentalMaterial3Api | ||||||
|  | import androidx.compose.material3.MaterialTheme | ||||||
|  | import androidx.compose.material3.Scaffold | ||||||
|  | import androidx.compose.material3.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import androidx.compose.ui.platform.testTag | ||||||
|  | import androidx.compose.ui.res.colorResource | ||||||
|  | import androidx.compose.ui.res.stringResource | ||||||
|  | import androidx.compose.ui.text.style.TextAlign | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import androidx.navigation.NavController | ||||||
|  | import androidx.navigation.NavDestination.Companion.hierarchy | ||||||
|  | import androidx.navigation.compose.rememberNavController | ||||||
|  | import ru.samsung.smartintercom.R | ||||||
|  | import ru.samsung.smartintercom.core.CallScreenId | ||||||
|  | import ru.samsung.smartintercom.ui.nav.Screen | ||||||
|  | import ru.samsung.smartintercom.ui.nav.navigate | ||||||
|  | import ru.samsung.smartintercom.ui.screen.ScreenBaseData | ||||||
|  | import ru.samsung.smartintercom.ui.screen.call.di.CallScreenComponent | ||||||
|  | import ru.samsung.smartintercom.ui.theme.SmartIntercomTheme | ||||||
|  | import ru.samsung.smartintercom.ui.theme.button | ||||||
|  | import ru.samsung.smartintercom.utils.collectAsEffect | ||||||
|  | import ru.samsung.smartintercom.utils.daggerViewModel | ||||||
|  | import ru.samsung.smartintercom.utils.setupScreenData | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Экран вызова | ||||||
|  |  * | ||||||
|  |  * ВНИМАНИЕ! | ||||||
|  |  * Данный экран приведён для примера. | ||||||
|  |  * Вы можете его модифицировать любыми удобными способами и дорабатывать его. | ||||||
|  |  */ | ||||||
|  | object CallScreen : ScreenBaseData { | ||||||
|  |     override val name = CallScreenId.screenId | ||||||
|  |  | ||||||
|  |     @OptIn(ExperimentalMaterial3Api::class) | ||||||
|  |     @Composable | ||||||
|  |     override fun Render(navController: NavController) { | ||||||
|  |         val component = CallScreenComponent.build() | ||||||
|  |         val viewModel = daggerViewModel { component.viewModel } | ||||||
|  |         viewModel.goBackOrOpenMainScreen.collectAsEffect { | ||||||
|  |             if (navController.graph.hierarchy.count() > 0) { | ||||||
|  |                 navController.popBackStack() | ||||||
|  |             } else { | ||||||
|  |                 navController.navigate(Screen.MAIN) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Scaffold( | ||||||
|  |             modifier = Modifier.setupScreenData(CallScreen), | ||||||
|  |             content = { paddingValues -> | ||||||
|  |                 Column( | ||||||
|  |                     modifier = Modifier | ||||||
|  |                         .padding(paddingValues = paddingValues) | ||||||
|  |                         .padding(16.dp), | ||||||
|  |                 ) { | ||||||
|  |                     Text( | ||||||
|  |                         modifier = Modifier | ||||||
|  |                             .weight(1f) | ||||||
|  |                             .fillMaxWidth() | ||||||
|  |                             .wrapContentHeight(align = Alignment.CenterVertically), | ||||||
|  |                         text = stringResource(R.string.call_screen_title), | ||||||
|  |                         style = MaterialTheme.typography.displayLarge, | ||||||
|  |                         textAlign = TextAlign.Center, | ||||||
|  |                     ) | ||||||
|  |                     Row( | ||||||
|  |                         modifier = Modifier | ||||||
|  |                             .fillMaxWidth(), | ||||||
|  |                         horizontalArrangement = Arrangement.SpaceEvenly, | ||||||
|  |                     ) { | ||||||
|  |                         Button( | ||||||
|  |                             id = CallScreenId.buttonOpen, | ||||||
|  |                             text = stringResource(R.string.open_intercom), | ||||||
|  |                             color = colorResource(R.color.call_open), | ||||||
|  |                             onClick = viewModel::clickOpen, | ||||||
|  |                         ) | ||||||
|  |                         Spacer(modifier = Modifier.width(16.dp)) | ||||||
|  |                         Button( | ||||||
|  |                             id = CallScreenId.buttonClose, | ||||||
|  |                             text = stringResource(R.string.decline_intercom), | ||||||
|  |                             color = colorResource(R.color.call_close), | ||||||
|  |                             onClick = viewModel::clickDecline, | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Composable | ||||||
|  |     fun RowScope.Button( | ||||||
|  |         id: String, | ||||||
|  |         text: String, | ||||||
|  |         color: Color, | ||||||
|  |         onClick: () -> Unit | ||||||
|  |     ) { | ||||||
|  |         Button( | ||||||
|  |             modifier = Modifier | ||||||
|  |                 .testTag(id) | ||||||
|  |                 .weight(1.0f, true), | ||||||
|  |             colors = ButtonDefaults.buttonColors(containerColor = color), | ||||||
|  |             onClick = onClick, | ||||||
|  |         ) { | ||||||
|  |             Text( | ||||||
|  |                 style = MaterialTheme.typography.button.large, | ||||||
|  |                 text = text, | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Preview(showBackground = true, device = "spec:width=1080px,height=1920px,dpi=320") | ||||||
|  | @Composable | ||||||
|  | fun CallScreenPreview() { | ||||||
|  |     SmartIntercomTheme { | ||||||
|  |         CallScreen.Render(rememberNavController()) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.call | ||||||
|  |  | ||||||
|  | import androidx.lifecycle.ViewModel | ||||||
|  | import androidx.lifecycle.viewModelScope | ||||||
|  | import kotlinx.coroutines.flow.SharedFlow | ||||||
|  | import kotlinx.coroutines.flow.asSharedFlow | ||||||
|  | import kotlinx.coroutines.launch | ||||||
|  | import ru.samsung.smartintercom.utils.MutablePublishFlow | ||||||
|  | import javax.inject.Inject | ||||||
|  |  | ||||||
|  | class CallViewModel @Inject constructor() : ViewModel() { | ||||||
|  |     val goBackOrOpenMainScreen: SharedFlow<Unit> get() = _goBackOrOpenMainScreen.asSharedFlow() | ||||||
|  |     private val _goBackOrOpenMainScreen = MutablePublishFlow<Unit>() | ||||||
|  |     fun clickOpen() { | ||||||
|  |         viewModelScope.launch { | ||||||
|  |             // TODO: необходимо добавить обработку нажатия на кнопку открытия | ||||||
|  |             _goBackOrOpenMainScreen.emit(Unit) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun clickDecline() { | ||||||
|  |         viewModelScope.launch { | ||||||
|  |             // TODO: необходимо добавить обработку нажатия на кнопку закрытия | ||||||
|  |             _goBackOrOpenMainScreen.emit(Unit) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.call.di | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.platform.LocalContext | ||||||
|  | import dagger.Component | ||||||
|  | import ru.samsung.smartintercom.App | ||||||
|  | import ru.samsung.smartintercom.di.AppComponent | ||||||
|  | import ru.samsung.smartintercom.ui.screen.call.CallViewModel | ||||||
|  |  | ||||||
|  | @Component(dependencies = [AppComponent::class]) | ||||||
|  | @CallScreenScope | ||||||
|  | interface CallScreenComponent { | ||||||
|  |  | ||||||
|  |     @Component.Factory | ||||||
|  |     interface Factory { | ||||||
|  |         fun create(appComponent: AppComponent): CallScreenComponent | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val viewModel: CallViewModel | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         @Composable | ||||||
|  |         fun build(): CallScreenComponent { | ||||||
|  |             return DaggerCallScreenComponent.factory().create( | ||||||
|  |                 (LocalContext.current.applicationContext as App).appComponent | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.call.di | ||||||
|  |  | ||||||
|  | import javax.inject.Scope | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Scope | ||||||
|  | @Retention(AnnotationRetention.RUNTIME) | ||||||
|  | annotation class CallScreenScope | ||||||
| @@ -0,0 +1,131 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.main | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.Arrangement | ||||||
|  | import androidx.compose.foundation.layout.Box | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.Spacer | ||||||
|  | import androidx.compose.foundation.layout.fillMaxSize | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.foundation.layout.width | ||||||
|  | import androidx.compose.material3.Button | ||||||
|  | import androidx.compose.material3.ExperimentalMaterial3Api | ||||||
|  | import androidx.compose.material3.MaterialTheme | ||||||
|  | import androidx.compose.material3.Scaffold | ||||||
|  | import androidx.compose.material3.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.collectAsState | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.platform.testTag | ||||||
|  | import androidx.compose.ui.res.stringResource | ||||||
|  | import androidx.compose.ui.text.style.TextAlign | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import androidx.navigation.NavController | ||||||
|  | import ru.samsung.smartintercom.R | ||||||
|  | import ru.samsung.smartintercom.core.MainScreenId | ||||||
|  | import ru.samsung.smartintercom.ui.screen.ScreenBaseData | ||||||
|  | import ru.samsung.smartintercom.ui.screen.main.di.MainScreenComponent | ||||||
|  | import ru.samsung.smartintercom.ui.theme.SmartIntercomTheme | ||||||
|  | import ru.samsung.smartintercom.ui.theme.button | ||||||
|  | import ru.samsung.smartintercom.utils.daggerViewModel | ||||||
|  | import ru.samsung.smartintercom.utils.setupScreenData | ||||||
|  |  | ||||||
|  | object MainScreen : ScreenBaseData { | ||||||
|  |     override val name = MainScreenId.screenId | ||||||
|  |  | ||||||
|  |     @Composable | ||||||
|  |     override fun Render(navController: NavController) { | ||||||
|  |         val component = MainScreenComponent.build() | ||||||
|  |         val viewModel = daggerViewModel { component.viewModel } | ||||||
|  |         val state by viewModel.uiState.collectAsState() | ||||||
|  |         RenderState( | ||||||
|  |             state = state, | ||||||
|  |             openSettingClick = {}, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(ExperimentalMaterial3Api::class) | ||||||
|  |     @Composable | ||||||
|  |     internal fun RenderState( | ||||||
|  |         state: MainState, | ||||||
|  |         openSettingClick: () -> Unit, | ||||||
|  |     ) { | ||||||
|  |         Scaffold( | ||||||
|  |             modifier = Modifier.setupScreenData(this), | ||||||
|  |             content = { paddingValues -> | ||||||
|  |                 Box( | ||||||
|  |                     modifier = Modifier | ||||||
|  |                         .fillMaxSize() | ||||||
|  |                         .padding(paddingValues) | ||||||
|  |                 ) { | ||||||
|  |                     when (state) { | ||||||
|  |                         is MainState.Intro -> { | ||||||
|  |                             IntroState( | ||||||
|  |                                 openSettingClick = openSettingClick | ||||||
|  |                             ) | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         is MainState.Loading -> TODO("Добавить состояние загрузки") | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Composable | ||||||
|  |     private fun IntroState( | ||||||
|  |         openSettingClick: () -> Unit, | ||||||
|  |     ) { | ||||||
|  |         Column( | ||||||
|  |             modifier = Modifier | ||||||
|  |                 .fillMaxSize() | ||||||
|  |                 .padding(16.dp), | ||||||
|  |             horizontalAlignment = Alignment.CenterHorizontally, | ||||||
|  |         ) { | ||||||
|  |             Column( | ||||||
|  |                 modifier = Modifier | ||||||
|  |                     .weight(1f), | ||||||
|  |                 horizontalAlignment = Alignment.CenterHorizontally, | ||||||
|  |                 verticalArrangement = Arrangement.Center | ||||||
|  |             ) { | ||||||
|  |                 Text( | ||||||
|  |                     text = stringResource(R.string.main_screen_intro_title), | ||||||
|  |                     style = MaterialTheme.typography.displayLarge, | ||||||
|  |                     textAlign = TextAlign.Center, | ||||||
|  |                 ) | ||||||
|  |                 Spacer(modifier = Modifier.width(8.dp)) | ||||||
|  |                 Text( | ||||||
|  |                     text = stringResource(R.string.main_screen_intro_text), | ||||||
|  |                     style = MaterialTheme.typography.headlineLarge, | ||||||
|  |                     textAlign = TextAlign.Center, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             Button( | ||||||
|  |                 modifier = Modifier.testTag(MainScreenId.buttonStart), | ||||||
|  |                 onClick = openSettingClick | ||||||
|  |             ) { | ||||||
|  |                 Text( | ||||||
|  |                     text = stringResource(id = R.string.main_screen_intro_button), | ||||||
|  |                     style = MaterialTheme.typography.button.normal | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Preview(showBackground = true, device = "spec:width=1080px,height=1920px,dpi=320") | ||||||
|  | @Composable | ||||||
|  | fun RenderPreview() { | ||||||
|  |     val mockAction = {} | ||||||
|  |     SmartIntercomTheme { | ||||||
|  |         Row { | ||||||
|  |             MainScreen.RenderState( | ||||||
|  |                 state = MainState.Intro, | ||||||
|  |                 openSettingClick = mockAction, | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.main | ||||||
|  |  | ||||||
|  | sealed interface MainState { | ||||||
|  |     data object Intro: MainState | ||||||
|  |     data object Loading: MainState | ||||||
|  |     // TODO: необходимо добавить состояние ошибки и отображения | ||||||
|  | } | ||||||
| @@ -0,0 +1,22 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.main | ||||||
|  |  | ||||||
|  | import androidx.lifecycle.ViewModel | ||||||
|  | import androidx.lifecycle.viewModelScope | ||||||
|  | import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||||
|  | import kotlinx.coroutines.flow.MutableStateFlow | ||||||
|  | import kotlinx.coroutines.flow.StateFlow | ||||||
|  | import kotlinx.coroutines.flow.asStateFlow | ||||||
|  | import kotlinx.coroutines.launch | ||||||
|  | import javax.inject.Inject | ||||||
|  |  | ||||||
|  | @OptIn(ExperimentalCoroutinesApi::class) | ||||||
|  | class MainViewModel @Inject constructor() : ViewModel() { | ||||||
|  |     val uiState: StateFlow<MainState> get() = _uiState.asStateFlow() | ||||||
|  |     private val _uiState = MutableStateFlow<MainState>(MainState.Loading) | ||||||
|  |  | ||||||
|  |     init { | ||||||
|  |         viewModelScope.launch { | ||||||
|  |             _uiState.emit(MainState.Intro) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.main.di | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.platform.LocalContext | ||||||
|  | import dagger.Component | ||||||
|  | import ru.samsung.smartintercom.App | ||||||
|  | import ru.samsung.smartintercom.di.AppComponent | ||||||
|  | import ru.samsung.smartintercom.ui.screen.main.MainViewModel | ||||||
|  |  | ||||||
|  | @Component(dependencies = [AppComponent::class]) | ||||||
|  | @MainScreenScope | ||||||
|  | interface MainScreenComponent { | ||||||
|  |  | ||||||
|  |     @Component.Factory | ||||||
|  |     interface Factory { | ||||||
|  |         fun create(appComponent: AppComponent): MainScreenComponent | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val viewModel: MainViewModel | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         @Composable | ||||||
|  |         fun build(): MainScreenComponent { | ||||||
|  |             return DaggerMainScreenComponent.factory().create( | ||||||
|  |                 (LocalContext.current.applicationContext as App).appComponent | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.screen.main.di | ||||||
|  |  | ||||||
|  | import javax.inject.Scope | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Scope | ||||||
|  | @Retention(AnnotationRetention.RUNTIME) | ||||||
|  | annotation class MainScreenScope | ||||||
							
								
								
									
										11
									
								
								app/src/main/java/ru/samsung/smartintercom/ui/theme/Color.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.theme | ||||||
|  |  | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  |  | ||||||
|  | val Purple80 = Color(0xFFD0BCFF) | ||||||
|  | val PurpleGrey80 = Color(0xFFCCC2DC) | ||||||
|  | val Pink80 = Color(0xFFEFB8C8) | ||||||
|  |  | ||||||
|  | val Purple40 = Color(0xFF6650a4) | ||||||
|  | val PurpleGrey40 = Color(0xFF625b71) | ||||||
|  | val Pink40 = Color(0xFF7D5260) | ||||||
							
								
								
									
										60
									
								
								app/src/main/java/ru/samsung/smartintercom/ui/theme/Theme.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,60 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.theme | ||||||
|  |  | ||||||
|  | import android.app.Activity | ||||||
|  | import android.os.Build | ||||||
|  | import androidx.compose.foundation.isSystemInDarkTheme | ||||||
|  | import androidx.compose.material3.MaterialTheme | ||||||
|  | import androidx.compose.material3.darkColorScheme | ||||||
|  | import androidx.compose.material3.dynamicDarkColorScheme | ||||||
|  | import androidx.compose.material3.dynamicLightColorScheme | ||||||
|  | import androidx.compose.material3.lightColorScheme | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.SideEffect | ||||||
|  | import androidx.compose.ui.graphics.toArgb | ||||||
|  | import androidx.compose.ui.platform.LocalContext | ||||||
|  | import androidx.compose.ui.platform.LocalView | ||||||
|  | import androidx.core.view.WindowCompat | ||||||
|  |  | ||||||
|  | private val DarkColorScheme = darkColorScheme( | ||||||
|  |     primary = Purple80, | ||||||
|  |     secondary = PurpleGrey80, | ||||||
|  |     tertiary = Pink80 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | private val LightColorScheme = lightColorScheme( | ||||||
|  |     primary = Purple40, | ||||||
|  |     secondary = PurpleGrey40, | ||||||
|  |     tertiary = Pink40 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | fun SmartIntercomTheme( | ||||||
|  |     darkTheme: Boolean = isSystemInDarkTheme(), | ||||||
|  |     // Dynamic color is available on Android 12+ | ||||||
|  |     dynamicColor: Boolean = true, | ||||||
|  |     content: @Composable () -> Unit | ||||||
|  | ) { | ||||||
|  |     val colorScheme = when { | ||||||
|  |         dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { | ||||||
|  |             val context = LocalContext.current | ||||||
|  |             if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         darkTheme -> DarkColorScheme | ||||||
|  |         else -> LightColorScheme | ||||||
|  |     } | ||||||
|  |     val view = LocalView.current | ||||||
|  |     if (!view.isInEditMode) { | ||||||
|  |         SideEffect { | ||||||
|  |             val window = (view.context as Activity).window | ||||||
|  |             window.statusBarColor = colorScheme.primary.toArgb() | ||||||
|  |             WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     MaterialTheme( | ||||||
|  |         colorScheme = colorScheme, | ||||||
|  |         typography = Typography, | ||||||
|  |         content = content | ||||||
|  |     ) | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								app/src/main/java/ru/samsung/smartintercom/ui/theme/Type.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,37 @@ | |||||||
|  | package ru.samsung.smartintercom.ui.theme | ||||||
|  |  | ||||||
|  | import androidx.compose.material3.Typography | ||||||
|  | import androidx.compose.ui.text.TextStyle | ||||||
|  | import androidx.compose.ui.text.font.FontFamily | ||||||
|  | import androidx.compose.ui.text.font.FontWeight | ||||||
|  | import androidx.compose.ui.unit.sp | ||||||
|  |  | ||||||
|  | // Set of Material typography styles to start with | ||||||
|  | val Typography = Typography( | ||||||
|  |     bodyLarge = TextStyle( | ||||||
|  |         fontFamily = FontFamily.Default, | ||||||
|  |         fontWeight = FontWeight.Normal, | ||||||
|  |         fontSize = 16.sp, | ||||||
|  |         lineHeight = 24.sp, | ||||||
|  |         letterSpacing = 0.5.sp | ||||||
|  |     ) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | val Typography.button get() = Button | ||||||
|  |  | ||||||
|  | object Button { | ||||||
|  |     val large = base.copy( | ||||||
|  |         fontSize = 32.sp, | ||||||
|  |         lineHeight = 36.sp, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     val normal = base.copy( | ||||||
|  |         fontSize = 16.sp, | ||||||
|  |         lineHeight = 24.sp, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     private val base get() = TextStyle( | ||||||
|  |         fontFamily = FontFamily.Default, | ||||||
|  |         fontWeight = FontWeight.Medium, | ||||||
|  |     ) | ||||||
|  | } | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | package ru.samsung.smartintercom.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.LaunchedEffect | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.flowOn | ||||||
|  | import kotlinx.coroutines.flow.launchIn | ||||||
|  | import kotlinx.coroutines.flow.onEach | ||||||
|  | import kotlin.coroutines.CoroutineContext | ||||||
|  | import kotlin.coroutines.EmptyCoroutineContext | ||||||
|  |  | ||||||
|  | @Suppress("ComposableNaming", "StateFlowValueCalledInComposition") | ||||||
|  | @Composable | ||||||
|  | fun <T> Flow<T>.collectAsEffect( | ||||||
|  |     context: CoroutineContext = EmptyCoroutineContext, | ||||||
|  |     block: (T) -> Unit | ||||||
|  | ) { | ||||||
|  |     LaunchedEffect(key1 = Unit) { | ||||||
|  |         onEach(block).flowOn(context).launchIn(this) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | package ru.samsung.smartintercom.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.lifecycle.ViewModel | ||||||
|  | import androidx.lifecycle.ViewModelProvider | ||||||
|  | import androidx.lifecycle.viewmodel.compose.viewModel | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | inline fun <reified T : ViewModel> daggerViewModel( | ||||||
|  |     key: String? = null, | ||||||
|  |     crossinline viewModelInstanceCreator: () -> T | ||||||
|  | ): T { | ||||||
|  |     return viewModel( | ||||||
|  |         modelClass = T::class.java, | ||||||
|  |         key = key, | ||||||
|  |         factory = object : ViewModelProvider.Factory { | ||||||
|  |             override fun <T : ViewModel> create(modelClass: Class<T>): T { | ||||||
|  |                 return viewModelInstanceCreator() as T | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  | } | ||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | package ru.samsung.smartintercom.utils | ||||||
|  |  | ||||||
|  | import kotlinx.coroutines.channels.BufferOverflow | ||||||
|  | import kotlinx.coroutines.flow.MutableSharedFlow | ||||||
|  |  | ||||||
|  | fun <T> MutablePublishFlow() = MutableSharedFlow<T>( | ||||||
|  |     replay = 0, | ||||||
|  |     extraBufferCapacity = 1, | ||||||
|  |     BufferOverflow.DROP_OLDEST | ||||||
|  | ) | ||||||
| @@ -0,0 +1,17 @@ | |||||||
|  | package ru.samsung.smartintercom.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Stable | ||||||
|  | import androidx.compose.ui.ExperimentalComposeUiApi | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.platform.testTag | ||||||
|  | import androidx.compose.ui.semantics.semantics | ||||||
|  | import androidx.compose.ui.semantics.testTagsAsResourceId | ||||||
|  | import ru.samsung.smartintercom.ui.screen.ScreenBaseData | ||||||
|  |  | ||||||
|  | @OptIn(ExperimentalComposeUiApi::class) | ||||||
|  | @Stable | ||||||
|  | fun Modifier.setupScreenData(screenBaseData: ScreenBaseData) = semantics { | ||||||
|  |     testTagsAsResourceId = true | ||||||
|  | } | ||||||
|  |     .testTag(tag = screenBaseData.name) | ||||||
|  |  | ||||||
							
								
								
									
										170
									
								
								app/src/main/res/drawable/ic_launcher_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,170 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:width="108dp" | ||||||
|  |     android:height="108dp" | ||||||
|  |     android:viewportHeight="108" | ||||||
|  |     android:viewportWidth="108"> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#3DDC84" | ||||||
|  |         android:pathData="M0,0h108v108h-108z" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M9,0L9,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,0L19,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M29,0L29,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M39,0L39,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M49,0L49,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M59,0L59,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M69,0L69,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M79,0L79,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M89,0L89,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M99,0L99,108" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,9L108,9" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,19L108,19" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,29L108,29" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,39L108,39" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,49L108,49" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,59L108,59" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,69L108,69" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,79L108,79" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,89L108,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M0,99L108,99" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,29L89,29" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,39L89,39" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,49L89,49" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,59L89,59" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,69L89,69" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M19,79L89,79" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M29,19L29,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M39,19L39,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M49,19L49,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M59,19L59,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M69,19L69,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#00000000" | ||||||
|  |         android:pathData="M79,19L79,89" | ||||||
|  |         android:strokeColor="#33FFFFFF" | ||||||
|  |         android:strokeWidth="0.8" /> | ||||||
|  | </vector> | ||||||
							
								
								
									
										30
									
								
								app/src/main/res/drawable/ic_launcher_foreground.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,30 @@ | |||||||
|  | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     xmlns:aapt="http://schemas.android.com/aapt" | ||||||
|  |     android:width="108dp" | ||||||
|  |     android:height="108dp" | ||||||
|  |     android:viewportHeight="108" | ||||||
|  |     android:viewportWidth="108"> | ||||||
|  |     <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> | ||||||
|  |         <aapt:attr name="android:fillColor"> | ||||||
|  |             <gradient | ||||||
|  |                 android:endX="85.84757" | ||||||
|  |                 android:endY="92.4963" | ||||||
|  |                 android:startX="42.9492" | ||||||
|  |                 android:startY="49.59793" | ||||||
|  |                 android:type="linear"> | ||||||
|  |                 <item | ||||||
|  |                     android:color="#44000000" | ||||||
|  |                     android:offset="0.0" /> | ||||||
|  |                 <item | ||||||
|  |                     android:color="#00000000" | ||||||
|  |                     android:offset="1.0" /> | ||||||
|  |             </gradient> | ||||||
|  |         </aapt:attr> | ||||||
|  |     </path> | ||||||
|  |     <path | ||||||
|  |         android:fillColor="#FFFFFF" | ||||||
|  |         android:fillType="nonZero" | ||||||
|  |         android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" | ||||||
|  |         android:strokeColor="#00000000" | ||||||
|  |         android:strokeWidth="1" /> | ||||||
|  | </vector> | ||||||
							
								
								
									
										6
									
								
								app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <background android:drawable="@drawable/ic_launcher_background" /> | ||||||
|  |     <foreground android:drawable="@drawable/ic_launcher_foreground" /> | ||||||
|  |     <monochrome android:drawable="@drawable/ic_launcher_foreground" /> | ||||||
|  | </adaptive-icon> | ||||||
							
								
								
									
										6
									
								
								app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <background android:drawable="@drawable/ic_launcher_background" /> | ||||||
|  |     <foreground android:drawable="@drawable/ic_launcher_foreground" /> | ||||||
|  |     <monochrome android:drawable="@drawable/ic_launcher_foreground" /> | ||||||
|  | </adaptive-icon> | ||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-hdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-mdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 982 B | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xhdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.6 KiB | 
							
								
								
									
										12
									
								
								app/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <color name="purple_200">#FFBB86FC</color> | ||||||
|  |     <color name="purple_500">#FF6200EE</color> | ||||||
|  |     <color name="purple_700">#FF3700B3</color> | ||||||
|  |     <color name="teal_200">#FF03DAC5</color> | ||||||
|  |     <color name="teal_700">#FF018786</color> | ||||||
|  |     <color name="black">#FF000000</color> | ||||||
|  |     <color name="white">#FFFFFFFF</color> | ||||||
|  |     <color name="call_open">#43A047</color> | ||||||
|  |     <color name="call_close">#E53935</color> | ||||||
|  | </resources> | ||||||
							
								
								
									
										28
									
								
								app/src/main/res/values/ids.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- НЕ ИЗМЕНЯЙТЕ ДАННЫЙ ФАЙЛ --> | ||||||
|  | <!-- ПРИ ТЕСТИРОВАНИИ ФАЙЛ БУДЕТ ВОЗВРАЩЁН В ИСХОДНОЕ СОСТОЯНИЕ --> | ||||||
|  | <resources> | ||||||
|  |     <!-- Main Screen --> | ||||||
|  |     <item name="button_start" type="id"/> | ||||||
|  |     <item name="button_retry" type="id"/> | ||||||
|  |     <item name="text_intercom_model" type="id"/> | ||||||
|  |     <item name="button_take_photo" type="id"/> | ||||||
|  |     <item name="image_intercom" type="id"/> | ||||||
|  |     <item name="text_error" type="id"/> | ||||||
|  |     <item name="button_settings" type="id"/> | ||||||
|  |     <item name="button_history" type="id"/> | ||||||
|  |  | ||||||
|  |     <!-- Setting Screen --> | ||||||
|  |     <item name="input_house" type="id"/> | ||||||
|  |     <item name="input_flat" type="id"/> | ||||||
|  |     <item name="button_save" type="id"/> | ||||||
|  |  | ||||||
|  |     <!-- Call Screen --> | ||||||
|  |     <item name="button_open" type="id"/> | ||||||
|  |     <item name="button_close" type="id"/> | ||||||
|  |  | ||||||
|  |     <!-- Call History --> | ||||||
|  |     <item name="recycler" type="id"/> | ||||||
|  |     <item name="text_date" type="id"/> | ||||||
|  |     <item name="text_status" type="id"/> | ||||||
|  | </resources> | ||||||
							
								
								
									
										13
									
								
								app/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,13 @@ | |||||||
|  | <resources> | ||||||
|  |     <string name="app_name">SmartIntercom</string> | ||||||
|  |  | ||||||
|  |     <!-- Call Screen --> | ||||||
|  |     <string name="call_screen_title">Incoming call</string> | ||||||
|  |     <string name="open_intercom">Open</string> | ||||||
|  |     <string name="decline_intercom">Decline</string> | ||||||
|  |  | ||||||
|  |     <!-- Main Screen --> | ||||||
|  |     <string name="main_screen_intro_title">Welcome</string> | ||||||
|  |     <string name="main_screen_intro_text">Setup your intercom for working app</string> | ||||||
|  |     <string name="main_screen_intro_button">Go to setting</string> | ||||||
|  | </resources> | ||||||
							
								
								
									
										4
									
								
								app/src/main/res/values/themes.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <style name="Theme.SmartIntercom" parent="android:Theme.Material.Light.NoActionBar" /> | ||||||
|  | </resources> | ||||||
							
								
								
									
										13
									
								
								app/src/main/res/xml/backup_rules.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,13 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?><!-- | ||||||
|  |    Sample backup rules file; uncomment and customize as necessary. | ||||||
|  |    See https://developer.android.com/guide/topics/data/autobackup | ||||||
|  |    for details. | ||||||
|  |    Note: This file is ignored for devices older that API 31 | ||||||
|  |    See https://developer.android.com/about/versions/12/backup-restore | ||||||
|  | --> | ||||||
|  | <full-backup-content> | ||||||
|  |     <!-- | ||||||
|  |    <include domain="sharedpref" path="."/> | ||||||
|  |    <exclude domain="sharedpref" path="device.xml"/> | ||||||
|  | --> | ||||||
|  | </full-backup-content> | ||||||
							
								
								
									
										19
									
								
								app/src/main/res/xml/data_extraction_rules.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?><!-- | ||||||
|  |    Sample data extraction rules file; uncomment and customize as necessary. | ||||||
|  |    See https://developer.android.com/about/versions/12/backup-restore#xml-changes | ||||||
|  |    for details. | ||||||
|  | --> | ||||||
|  | <data-extraction-rules> | ||||||
|  |     <cloud-backup> | ||||||
|  |         <!-- TODO: Use <include> and <exclude> to control what is backed up. | ||||||
|  |         <include .../> | ||||||
|  |         <exclude .../> | ||||||
|  |         --> | ||||||
|  |     </cloud-backup> | ||||||
|  |     <!-- | ||||||
|  |     <device-transfer> | ||||||
|  |         <include .../> | ||||||
|  |         <exclude .../> | ||||||
|  |     </device-transfer> | ||||||
|  |     --> | ||||||
|  | </data-extraction-rules> | ||||||
							
								
								
									
										9
									
								
								build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,9 @@ | |||||||
|  | buildscript { | ||||||
|  |     val agp_version by extra("8.1.2") | ||||||
|  | } | ||||||
|  | // Top-level build file where you can add configuration options common to all sub-projects/modules. | ||||||
|  | plugins { | ||||||
|  |     id("com.android.application") version "8.1.2" apply false | ||||||
|  |     id("org.jetbrains.kotlin.android") version "1.9.0" apply false | ||||||
|  |     id("com.google.devtools.ksp") version "1.9.0-1.0.12" apply false | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | |||||||
|  | # Project-wide Gradle settings. | ||||||
|  | # IDE (e.g. Android Studio) users: | ||||||
|  | # Gradle settings configured through the IDE *will override* | ||||||
|  | # any settings specified in this file. | ||||||
|  | # For more details on how to configure your build environment visit | ||||||
|  | # http://www.gradle.org/docs/current/userguide/build_environment.html | ||||||
|  | # Specifies the JVM arguments used for the daemon process. | ||||||
|  | # The setting is particularly useful for tweaking memory settings. | ||||||
|  | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 | ||||||
|  | # When configured, Gradle will run in incubating parallel mode. | ||||||
|  | # This option should only be used with decoupled projects. More details, visit | ||||||
|  | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | ||||||
|  | # org.gradle.parallel=true | ||||||
|  | # AndroidX package structure to make it clearer which packages are bundled with the | ||||||
|  | # Android operating system, and which are packaged with your app's APK | ||||||
|  | # https://developer.android.com/topic/libraries/support-library/androidx-rn | ||||||
|  | android.useAndroidX=true | ||||||
|  | # Kotlin code style for this project: "official" or "obsolete": | ||||||
|  | kotlin.code.style=official | ||||||
|  | # Enables namespacing of each library's R class so that its R class includes only the | ||||||
|  | # resources declared in the library itself and none from the library's dependencies, | ||||||
|  | # thereby reducing the size of the R class for that library | ||||||
|  | android.nonTransitiveRClass=true | ||||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | |||||||
|  | #Mon Oct 16 23:49:02 NOVT 2023 | ||||||
|  | distributionBase=GRADLE_USER_HOME | ||||||
|  | distributionPath=wrapper/dists | ||||||
|  | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip | ||||||
|  | zipStoreBase=GRADLE_USER_HOME | ||||||
|  | zipStorePath=wrapper/dists | ||||||
							
								
								
									
										185
									
								
								gradlew
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,185 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  |  | ||||||
|  | # | ||||||
|  | # Copyright 2015 the original author or authors. | ||||||
|  | # | ||||||
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | # you may not use this file except in compliance with the License. | ||||||
|  | # You may obtain a copy of the License at | ||||||
|  | # | ||||||
|  | #      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | # | ||||||
|  | # Unless required by applicable law or agreed to in writing, software | ||||||
|  | # distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | # See the License for the specific language governing permissions and | ||||||
|  | # limitations under the License. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | ############################################################################## | ||||||
|  | ## | ||||||
|  | ##  Gradle start up script for UN*X | ||||||
|  | ## | ||||||
|  | ############################################################################## | ||||||
|  |  | ||||||
|  | # Attempt to set APP_HOME | ||||||
|  | # Resolve links: $0 may be a link | ||||||
|  | PRG="$0" | ||||||
|  | # Need this for relative symlinks. | ||||||
|  | while [ -h "$PRG" ] ; do | ||||||
|  |     ls=`ls -ld "$PRG"` | ||||||
|  |     link=`expr "$ls" : '.*-> \(.*\)$'` | ||||||
|  |     if expr "$link" : '/.*' > /dev/null; then | ||||||
|  |         PRG="$link" | ||||||
|  |     else | ||||||
|  |         PRG=`dirname "$PRG"`"/$link" | ||||||
|  |     fi | ||||||
|  | done | ||||||
|  | SAVED="`pwd`" | ||||||
|  | cd "`dirname \"$PRG\"`/" >/dev/null | ||||||
|  | APP_HOME="`pwd -P`" | ||||||
|  | cd "$SAVED" >/dev/null | ||||||
|  |  | ||||||
|  | APP_NAME="Gradle" | ||||||
|  | APP_BASE_NAME=`basename "$0"` | ||||||
|  |  | ||||||
|  | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||||
|  | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | ||||||
|  |  | ||||||
|  | # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||||
|  | MAX_FD="maximum" | ||||||
|  |  | ||||||
|  | warn () { | ||||||
|  |     echo "$*" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | die () { | ||||||
|  |     echo | ||||||
|  |     echo "$*" | ||||||
|  |     echo | ||||||
|  |     exit 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # OS specific support (must be 'true' or 'false'). | ||||||
|  | cygwin=false | ||||||
|  | msys=false | ||||||
|  | darwin=false | ||||||
|  | nonstop=false | ||||||
|  | case "`uname`" in | ||||||
|  |   CYGWIN* ) | ||||||
|  |     cygwin=true | ||||||
|  |     ;; | ||||||
|  |   Darwin* ) | ||||||
|  |     darwin=true | ||||||
|  |     ;; | ||||||
|  |   MINGW* ) | ||||||
|  |     msys=true | ||||||
|  |     ;; | ||||||
|  |   NONSTOP* ) | ||||||
|  |     nonstop=true | ||||||
|  |     ;; | ||||||
|  | esac | ||||||
|  |  | ||||||
|  | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Determine the Java command to use to start the JVM. | ||||||
|  | if [ -n "$JAVA_HOME" ] ; then | ||||||
|  |     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||||||
|  |         # IBM's JDK on AIX uses strange locations for the executables | ||||||
|  |         JAVACMD="$JAVA_HOME/jre/sh/java" | ||||||
|  |     else | ||||||
|  |         JAVACMD="$JAVA_HOME/bin/java" | ||||||
|  |     fi | ||||||
|  |     if [ ! -x "$JAVACMD" ] ; then | ||||||
|  |         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||||||
|  |  | ||||||
|  | Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | location of your Java installation." | ||||||
|  |     fi | ||||||
|  | else | ||||||
|  |     JAVACMD="java" | ||||||
|  |     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||||
|  |  | ||||||
|  | Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | location of your Java installation." | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Increase the maximum file descriptors if we can. | ||||||
|  | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | ||||||
|  |     MAX_FD_LIMIT=`ulimit -H -n` | ||||||
|  |     if [ $? -eq 0 ] ; then | ||||||
|  |         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||||||
|  |             MAX_FD="$MAX_FD_LIMIT" | ||||||
|  |         fi | ||||||
|  |         ulimit -n $MAX_FD | ||||||
|  |         if [ $? -ne 0 ] ; then | ||||||
|  |             warn "Could not set maximum file descriptor limit: $MAX_FD" | ||||||
|  |         fi | ||||||
|  |     else | ||||||
|  |         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||||||
|  |     fi | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # For Darwin, add options to specify how the application appears in the dock | ||||||
|  | if $darwin; then | ||||||
|  |     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # For Cygwin or MSYS, switch paths to Windows format before running java | ||||||
|  | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then | ||||||
|  |     APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||||||
|  |     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||||||
|  |  | ||||||
|  |     JAVACMD=`cygpath --unix "$JAVACMD"` | ||||||
|  |  | ||||||
|  |     # We build the pattern for arguments to be converted via cygpath | ||||||
|  |     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||||||
|  |     SEP="" | ||||||
|  |     for dir in $ROOTDIRSRAW ; do | ||||||
|  |         ROOTDIRS="$ROOTDIRS$SEP$dir" | ||||||
|  |         SEP="|" | ||||||
|  |     done | ||||||
|  |     OURCYGPATTERN="(^($ROOTDIRS))" | ||||||
|  |     # Add a user-defined pattern to the cygpath arguments | ||||||
|  |     if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||||||
|  |         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||||||
|  |     fi | ||||||
|  |     # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||||||
|  |     i=0 | ||||||
|  |     for arg in "$@" ; do | ||||||
|  |         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||||||
|  |         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option | ||||||
|  |  | ||||||
|  |         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition | ||||||
|  |             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||||||
|  |         else | ||||||
|  |             eval `echo args$i`="\"$arg\"" | ||||||
|  |         fi | ||||||
|  |         i=`expr $i + 1` | ||||||
|  |     done | ||||||
|  |     case $i in | ||||||
|  |         0) set -- ;; | ||||||
|  |         1) set -- "$args0" ;; | ||||||
|  |         2) set -- "$args0" "$args1" ;; | ||||||
|  |         3) set -- "$args0" "$args1" "$args2" ;; | ||||||
|  |         4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||||||
|  |         5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||||||
|  |         6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||||||
|  |         7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||||||
|  |         8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||||||
|  |         9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||||||
|  |     esac | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Escape application args | ||||||
|  | save () { | ||||||
|  |     for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | ||||||
|  |     echo " " | ||||||
|  | } | ||||||
|  | APP_ARGS=`save "$@"` | ||||||
|  |  | ||||||
|  | # Collect all arguments for the java command, following the shell quoting and substitution rules | ||||||
|  | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | ||||||
|  |  | ||||||
|  | exec "$JAVACMD" "$@" | ||||||
							
								
								
									
										89
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,89 @@ | |||||||
|  | @rem | ||||||
|  | @rem Copyright 2015 the original author or authors. | ||||||
|  | @rem | ||||||
|  | @rem Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | @rem you may not use this file except in compliance with the License. | ||||||
|  | @rem You may obtain a copy of the License at | ||||||
|  | @rem | ||||||
|  | @rem      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | @rem | ||||||
|  | @rem Unless required by applicable law or agreed to in writing, software | ||||||
|  | @rem distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | @rem See the License for the specific language governing permissions and | ||||||
|  | @rem limitations under the License. | ||||||
|  | @rem | ||||||
|  |  | ||||||
|  | @if "%DEBUG%" == "" @echo off | ||||||
|  | @rem ########################################################################## | ||||||
|  | @rem | ||||||
|  | @rem  Gradle startup script for Windows | ||||||
|  | @rem | ||||||
|  | @rem ########################################################################## | ||||||
|  |  | ||||||
|  | @rem Set local scope for the variables with windows NT shell | ||||||
|  | if "%OS%"=="Windows_NT" setlocal | ||||||
|  |  | ||||||
|  | set DIRNAME=%~dp0 | ||||||
|  | if "%DIRNAME%" == "" set DIRNAME=. | ||||||
|  | set APP_BASE_NAME=%~n0 | ||||||
|  | set APP_HOME=%DIRNAME% | ||||||
|  |  | ||||||
|  | @rem Resolve any "." and ".." in APP_HOME to make it shorter. | ||||||
|  | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi | ||||||
|  |  | ||||||
|  | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||||
|  | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" | ||||||
|  |  | ||||||
|  | @rem Find java.exe | ||||||
|  | if defined JAVA_HOME goto findJavaFromJavaHome | ||||||
|  |  | ||||||
|  | set JAVA_EXE=java.exe | ||||||
|  | %JAVA_EXE% -version >NUL 2>&1 | ||||||
|  | if "%ERRORLEVEL%" == "0" goto execute | ||||||
|  |  | ||||||
|  | echo. | ||||||
|  | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||||
|  | echo. | ||||||
|  | echo Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | echo location of your Java installation. | ||||||
|  |  | ||||||
|  | goto fail | ||||||
|  |  | ||||||
|  | :findJavaFromJavaHome | ||||||
|  | set JAVA_HOME=%JAVA_HOME:"=% | ||||||
|  | set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||||
|  |  | ||||||
|  | if exist "%JAVA_EXE%" goto execute | ||||||
|  |  | ||||||
|  | echo. | ||||||
|  | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||||
|  | echo. | ||||||
|  | echo Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | echo location of your Java installation. | ||||||
|  |  | ||||||
|  | goto fail | ||||||
|  |  | ||||||
|  | :execute | ||||||
|  | @rem Setup the command line | ||||||
|  |  | ||||||
|  | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @rem Execute Gradle | ||||||
|  | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* | ||||||
|  |  | ||||||
|  | :end | ||||||
|  | @rem End local scope for the variables with windows NT shell | ||||||
|  | if "%ERRORLEVEL%"=="0" goto mainEnd | ||||||
|  |  | ||||||
|  | :fail | ||||||
|  | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||||
|  | rem the _cmd.exe /c_ return code! | ||||||
|  | if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||||
|  | exit /b 1 | ||||||
|  |  | ||||||
|  | :mainEnd | ||||||
|  | if "%OS%"=="Windows_NT" endlocal | ||||||
|  |  | ||||||
|  | :omega | ||||||
							
								
								
									
										18
									
								
								settings.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | |||||||
|  | pluginManagement { | ||||||
|  |     repositories { | ||||||
|  |         google() | ||||||
|  |         mavenCentral() | ||||||
|  |         gradlePluginPortal() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | dependencyResolutionManagement { | ||||||
|  |     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) | ||||||
|  |     repositories { | ||||||
|  |         google() | ||||||
|  |         mavenCentral() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | rootProject.name = "SmartIntercom" | ||||||
|  | include(":app") | ||||||
|  |   | ||||||