initial commit
This commit is contained in:
99
app/build.gradle.kts
Normal file
99
app/build.gradle.kts
Normal file
@@ -0,0 +1,99 @@
|
||||
// [FILE] app/build.gradle.kts
|
||||
// [PURPOSE] Build script for the app module.
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("com.google.dagger.hilt.android")
|
||||
id("kotlin-kapt")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.homebox.lens"
|
||||
compileSdk = Versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.homebox.lens"
|
||||
minSdk = Versions.minSdk
|
||||
targetSdk = Versions.targetSdk
|
||||
versionCode = Versions.versionCode
|
||||
versionName = Versions.versionName
|
||||
|
||||
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
|
||||
buildConfig = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = Versions.composeCompiler
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// [MODULE_DEPENDENCY] Data module
|
||||
implementation(project(":data"))
|
||||
// [MODULE_DEPENDENCY] Domain module (transitively included via data, but explicit for clarity)
|
||||
implementation(project(":domain"))
|
||||
|
||||
// [DEPENDENCY] AndroidX
|
||||
implementation(Libs.coreKtx)
|
||||
implementation(Libs.lifecycleRuntime)
|
||||
implementation(Libs.activityCompose)
|
||||
|
||||
// [DEPENDENCY] Compose
|
||||
implementation(platform(Libs.composeBom))
|
||||
implementation(Libs.composeUi)
|
||||
implementation(Libs.composeUiGraphics)
|
||||
implementation(Libs.composeUiToolingPreview)
|
||||
implementation(Libs.composeMaterial3)
|
||||
implementation(Libs.navigationCompose)
|
||||
implementation(Libs.hiltNavigationCompose)
|
||||
|
||||
// [DEPENDENCY] DI (Hilt)
|
||||
implementation(Libs.hiltAndroid)
|
||||
kapt(Libs.hiltCompiler)
|
||||
|
||||
// [DEPENDENCY] Logging
|
||||
implementation(Libs.timber)
|
||||
|
||||
// [DEPENDENCY] Testing
|
||||
testImplementation(Libs.junit)
|
||||
androidTestImplementation(Libs.extJunit)
|
||||
androidTestImplementation(Libs.espressoCore)
|
||||
androidTestImplementation(platform(Libs.composeBom))
|
||||
androidTestImplementation(Libs.composeUiTestJunit4)
|
||||
debugImplementation(Libs.composeUiTooling)
|
||||
debugImplementation(Libs.composeUiTestManifest)
|
||||
}
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
}
|
||||
|
||||
// [END_FILE_app/build.gradle.kts]
|
||||
22
app/src/main/AndroidManifest.xml
Normal file
22
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.homebox.lens">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Homeboxlens">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Homeboxlens">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
62
app/src/main/java/com/homebox/lens/MainActivity.kt
Normal file
62
app/src/main/java/com/homebox/lens/MainActivity.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
// [PACKAGE] com.homebox.lens
|
||||
// [FILE] MainActivity.kt
|
||||
|
||||
package com.homebox.lens
|
||||
|
||||
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.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.homebox.lens.navigation.NavGraph
|
||||
import com.homebox.lens.ui.theme.HomeboxLensTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
// [CONTRACT]
|
||||
/**
|
||||
* [ENTITY: Activity('MainActivity')]
|
||||
* [PURPOSE] Главная и единственная Activity в приложении.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
// [LIFECYCLE]
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
HomeboxLensTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
NavGraph()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [HELPER]
|
||||
@Composable
|
||||
fun Greeting(name: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = "Hello $name!",
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
// [PREVIEW]
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview() {
|
||||
HomeboxLensTheme {
|
||||
Greeting("Android")
|
||||
}
|
||||
}
|
||||
|
||||
// [END_FILE_MainActivity.kt]
|
||||
28
app/src/main/java/com/homebox/lens/MainApplication.kt
Normal file
28
app/src/main/java/com/homebox/lens/MainApplication.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
// [PACKAGE] com.homebox.lens
|
||||
// [FILE] MainApplication.kt
|
||||
|
||||
package com.homebox.lens
|
||||
|
||||
import android.app.Application
|
||||
import com.homebox.lens.BuildConfig
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import timber.log.Timber
|
||||
|
||||
// [CONTRACT]
|
||||
/**
|
||||
* [ENTITY: Application('MainApplication')]
|
||||
* [PURPOSE] Точка входа в приложение. Инициализирует Hilt и Timber.
|
||||
*/
|
||||
@HiltAndroidApp
|
||||
class MainApplication : Application() {
|
||||
// [LIFECYCLE]
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// [ACTION] Initialize Timber for logging
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [END_FILE_MainApplication.kt]
|
||||
63
app/src/main/java/com/homebox/lens/di/AppModule.kt
Normal file
63
app/src/main/java/com/homebox/lens/di/AppModule.kt
Normal file
@@ -0,0 +1,63 @@
|
||||
// [PACKAGE] com.homebox.lens.di
|
||||
// [FILE] AppModule.kt
|
||||
// [SEMANTICS] dependency_injection, hilt, configuration
|
||||
|
||||
// [IMPORTS]
|
||||
import com.homebox.lens.data.api.HomeboxApiService
|
||||
import com.homebox.lens.data.repository.ItemRepositoryImpl
|
||||
import com.homebox.lens.domain.repository.ItemRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import javax.inject.Singleton
|
||||
|
||||
// [CORE-LOGIC]
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AppModule {
|
||||
|
||||
private const val BASE_URL = "https://homebox.fly.dev/api/" // Заглушка, заменить на реальный URL
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Предоставляет синглтон-экземпляр Retrofit.
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRetrofit(): Retrofit {
|
||||
// [PRECONDITION] BASE_URL должен быть валидным URL.
|
||||
require(BASE_URL.startsWith("https://") || BASE_URL.startsWith("http://")) {
|
||||
"[PRECONDITION_FAILED] BASE_URL must be a valid URL."
|
||||
}
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Предоставляет синглтон-экземпляр HomeboxApiService.
|
||||
* @param retrofit Экземпляр Retrofit.
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideHomeboxApiService(retrofit: Retrofit): HomeboxApiService {
|
||||
return retrofit.create(HomeboxApiService::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Предоставляет реализацию ItemRepository.
|
||||
* @param apiService Экземпляр HomeboxApiService.
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideItemRepository(apiService: HomeboxApiService): ItemRepository {
|
||||
return ItemRepositoryImpl(apiService)
|
||||
}
|
||||
}
|
||||
// [END_FILE_AppModule.kt]
|
||||
30
app/src/main/java/com/homebox/lens/navigation/NavGraph.kt
Normal file
30
app/src/main/java/com/homebox/lens/navigation/NavGraph.kt
Normal file
@@ -0,0 +1,30 @@
|
||||
// [PACKAGE] com.homebox.lens.navigation
|
||||
// [FILE] NavGraph.kt
|
||||
// [SEMANTICS] navigation, compose, nav_host
|
||||
|
||||
// [IMPORTS]
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.homebox.lens.ui.screen.dashboard.DashboardScreen
|
||||
|
||||
// [CORE-LOGIC]
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Определяет граф навигации для приложения.
|
||||
*/
|
||||
@Composable
|
||||
fun NavGraph() {
|
||||
val navController = rememberNavController()
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Screen.Dashboard.route
|
||||
) {
|
||||
composable(route = Screen.Dashboard.route) {
|
||||
DashboardScreen()
|
||||
}
|
||||
// TODO: Добавить остальные экраны в граф навигации
|
||||
}
|
||||
}
|
||||
// [END_FILE_NavGraph.kt]
|
||||
15
app/src/main/java/com/homebox/lens/navigation/Screen.kt
Normal file
15
app/src/main/java/com/homebox/lens/navigation/Screen.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
// [PACKAGE] com.homebox.lens.navigation
|
||||
// [FILE] Screen.kt
|
||||
// [SEMANTICS] navigation, routes, constants
|
||||
|
||||
// [CORE-LOGIC]
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Запечатанный класс для определения навигационных маршрутов в приложении.
|
||||
* @property route Строковый идентификатор маршрута.
|
||||
*/
|
||||
sealed class Screen(val route: String) {
|
||||
object Dashboard : Screen("dashboard_screen")
|
||||
// TODO: Добавить остальные экраны по мере их создания
|
||||
}
|
||||
// [END_FILE_Screen.kt]
|
||||
@@ -0,0 +1,94 @@
|
||||
// [PACKAGE] com.homebox.lens.ui.screen.dashboard
|
||||
// [FILE] DashboardScreen.kt
|
||||
// [SEMANTICS] ui, screen, dashboard, compose
|
||||
|
||||
// [IMPORTS]
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
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.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
||||
// [CORE-LOGIC]
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Главный Composable для экрана "Дэшборд".
|
||||
* @param viewModel ViewModel для этого экрана.
|
||||
*/
|
||||
@Composable
|
||||
fun DashboardScreen(
|
||||
viewModel: DashboardViewModel = hiltViewModel()
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
|
||||
Scaffold { paddingValues ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
when (val state = uiState) {
|
||||
is DashboardUiState.Loading -> {
|
||||
// [UI-ACTION] Показываем индикатор загрузки
|
||||
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
is DashboardUiState.Error -> {
|
||||
// [UI-ACTION] Показываем сообщение об ошибке
|
||||
Text(
|
||||
text = "Error: ${state.message}",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
is DashboardUiState.Success -> {
|
||||
// [UI-ACTION] Отображаем основной контент
|
||||
DashboardContent(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Composable для отображения успешного состояния дэшборда.
|
||||
* @param state Состояние UI с данными.
|
||||
*/
|
||||
@Composable
|
||||
fun DashboardContent(state: DashboardUiState.Success) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// [UI-COMPONENT] Статистика
|
||||
Text(text = "Statistics:")
|
||||
Text(text = " Items: ${state.statistics.items}")
|
||||
Text(text = " Locations: ${state.statistics.locations}")
|
||||
Text(text = " Labels: ${state.statistics.labels}")
|
||||
Text(text = " Total Value: ${state.statistics.totalValue}")
|
||||
|
||||
// [UI-COMPONENT] Локации
|
||||
Text(text = "Locations:")
|
||||
state.locations.forEach { location ->
|
||||
Text(text = " - ${location.name} (${location.itemCount})")
|
||||
}
|
||||
|
||||
// [UI-COMPONENT] Метки
|
||||
Text(text = "Labels:")
|
||||
state.labels.forEach { label ->
|
||||
Text(text = " - ${label.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
// [END_FILE_DashboardScreen.kt]
|
||||
@@ -0,0 +1,83 @@
|
||||
// [PACKAGE] com.homebox.lens.ui.screen.dashboard
|
||||
// [FILE] DashboardViewModel.kt
|
||||
// [SEMANTICS] view_model, dashboard, state_management
|
||||
|
||||
// [IMPORTS]
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.homebox.lens.domain.model.GroupStatistics
|
||||
import com.homebox.lens.domain.model.LabelOut
|
||||
import com.homebox.lens.domain.model.LocationOutCount
|
||||
import com.homebox.lens.domain.usecase.GetAllLabelsUseCase
|
||||
import com.homebox.lens.domain.usecase.GetAllLocationsUseCase
|
||||
import com.homebox.lens.domain.usecase.GetStatisticsUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
// [CORE-LOGIC]
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* ViewModel для экрана "Дэшборд".
|
||||
* @param getStatisticsUseCase Use case для получения статистики.
|
||||
* @param getAllLocationsUseCase Use case для получения местоположений.
|
||||
* @param getAllLabelsUseCase Use case для получения меток.
|
||||
*/
|
||||
@HiltViewModel
|
||||
class DashboardViewModel @Inject constructor(
|
||||
private val getStatisticsUseCase: GetStatisticsUseCase,
|
||||
private val getAllLocationsUseCase: GetAllLocationsUseCase,
|
||||
private val getAllLabelsUseCase: GetAllLabelsUseCase
|
||||
) : ViewModel() {
|
||||
|
||||
// [STATE] UI State
|
||||
private val _uiState = MutableStateFlow<DashboardUiState>(DashboardUiState.Loading)
|
||||
val uiState: StateFlow<DashboardUiState> = _uiState.asStateFlow()
|
||||
|
||||
init {
|
||||
// [ACTION] Загрузка всех данных при инициализации.
|
||||
loadDashboardData()
|
||||
}
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Загружает все необходимые для экрана данные.
|
||||
* @sideeffect Обновляет _uiState.
|
||||
*/
|
||||
fun loadDashboardData() {
|
||||
viewModelScope.launch {
|
||||
_uiState.value = DashboardUiState.Loading
|
||||
try {
|
||||
val statistics = getStatisticsUseCase()
|
||||
val locations = getAllLocationsUseCase()
|
||||
val labels = getAllLabelsUseCase()
|
||||
|
||||
_uiState.value = DashboardUiState.Success(
|
||||
statistics = statistics,
|
||||
locations = locations,
|
||||
labels = labels
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
_uiState.value = DashboardUiState.Error(e.message ?: "Unknown error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Запечатанный интерфейс для представления состояний UI дэшборда.
|
||||
*/
|
||||
sealed interface DashboardUiState {
|
||||
data class Success(
|
||||
val statistics: GroupStatistics,
|
||||
val locations: List<LocationOutCount>,
|
||||
val labels: List<LabelOut>
|
||||
) : DashboardUiState
|
||||
data class Error(val message: String) : DashboardUiState
|
||||
object Loading : DashboardUiState
|
||||
}
|
||||
// [END_FILE_DashboardViewModel.kt]
|
||||
16
app/src/main/java/com/homebox/lens/ui/theme/Color.kt
Normal file
16
app/src/main/java/com/homebox/lens/ui/theme/Color.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
// [PACKAGE] com.homebox.lens.ui.theme
|
||||
// [FILE] Color.kt
|
||||
|
||||
package com.homebox.lens.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)
|
||||
|
||||
// [END_FILE_Color.kt]
|
||||
64
app/src/main/java/com/homebox/lens/ui/theme/Theme.kt
Normal file
64
app/src/main/java/com/homebox/lens/ui/theme/Theme.kt
Normal file
@@ -0,0 +1,64 @@
|
||||
// [PACKAGE] com.homebox.lens.ui.theme
|
||||
// [FILE] Theme.kt
|
||||
|
||||
package com.homebox.lens.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 HomeboxLensTheme(
|
||||
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
|
||||
)
|
||||
}
|
||||
// [END_FILE_Theme.kt]
|
||||
23
app/src/main/java/com/homebox/lens/ui/theme/Typography.kt
Normal file
23
app/src/main/java/com/homebox/lens/ui/theme/Typography.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
// [PACKAGE] com.homebox.lens.ui.theme
|
||||
// [FILE] Typography.kt
|
||||
|
||||
package com.homebox.lens.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
|
||||
)
|
||||
)
|
||||
|
||||
// [END_FILE_Typography.kt]
|
||||
4
app/src/main/res/values/colors.xml
Normal file
4
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
</resources>
|
||||
3
app/src/main/res/values/strings.xml
Normal file
3
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Homebox Lens</string>
|
||||
</resources>
|
||||
7
app/src/main/res/values/themes.xml
Normal file
7
app/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Homeboxlens" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:statusBarColor">@color/purple_700</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user