feat: establish Android project foundation

This commit is contained in:
KremeCN
2026-08-22 22:06:50 +08:00
parent e651f008e0
commit 117f87f735
39 changed files with 1653 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.hilt.android)
}
android {
namespace = "com.flagship.abox.manager"
compileSdk = 34
defaultConfig {
applicationId = "com.flagship.abox.manager"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "0.1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
}
kapt {
correctErrorTypes = true
}
dependencies {
implementation(project(":domain"))
implementation(project(":android:core:designsystem"))
debugImplementation(project(":testing:fakes"))
implementation(platform(libs.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.compose.material3)
implementation(libs.hilt.android)
kapt(libs.hilt.compiler)
testImplementation(libs.junit)
androidTestImplementation(platform(libs.compose.bom))
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.espresso.core)
androidTestImplementation(libs.compose.ui.test.junit4)
debugImplementation(libs.compose.ui.tooling)
debugImplementation(libs.compose.ui.test.manifest)
}
+1
View File
@@ -0,0 +1 @@
# Project-specific R8 rules belong here when release shrinking is enabled.
@@ -0,0 +1,42 @@
package com.flagship.abox.manager.di
import com.flagship.abox.manager.domain.DeviceCatalog
import com.flagship.abox.manager.domain.InfraredGateway
import com.flagship.abox.manager.domain.SessionGateway
import com.flagship.abox.manager.domain.SocketGateway
import com.flagship.abox.manager.domain.TemperatureHumidityGateway
import com.flagship.abox.manager.testing.fakes.FakeDeviceCatalog
import com.flagship.abox.manager.testing.fakes.FakeInfraredGateway
import com.flagship.abox.manager.testing.fakes.FakeSessionGateway
import com.flagship.abox.manager.testing.fakes.FakeSocketGateway
import com.flagship.abox.manager.testing.fakes.FakeTemperatureHumidityGateway
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object FoundationModule {
@Provides
@Singleton
fun provideSessionGateway(): SessionGateway = FakeSessionGateway()
@Provides
@Singleton
fun provideDeviceCatalog(): DeviceCatalog = FakeDeviceCatalog()
@Provides
@Singleton
fun provideSocketGateway(): SocketGateway = FakeSocketGateway()
@Provides
@Singleton
fun provideTemperatureHumidityGateway(): TemperatureHumidityGateway =
FakeTemperatureHumidityGateway()
@Provides
@Singleton
fun provideInfraredGateway(): InfraredGateway = FakeInfraredGateway()
}
+17
View File
@@ -0,0 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name=".ABoxManagerApplication"
android:allowBackup="false"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.ABoxManager">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,7 @@
package com.flagship.abox.manager
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class ABoxManagerApplication : Application()
@@ -0,0 +1,19 @@
package com.flagship.abox.manager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.flagship.abox.manager.ui.ABoxManagerApp
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ABoxManagerApp()
}
}
}
@@ -0,0 +1,94 @@
package com.flagship.abox.manager.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.flagship.abox.manager.R
import com.flagship.abox.manager.designsystem.ABoxButton
import com.flagship.abox.manager.designsystem.ABoxSurface
import com.flagship.abox.manager.designsystem.ABoxTheme
private const val FOUNDATION_ROUTE = "foundation"
private const val PLACEHOLDER_ROUTE = "placeholder"
@Composable
fun ABoxManagerApp() {
ABoxTheme {
ABoxSurface(modifier = Modifier.fillMaxSize()) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = FOUNDATION_ROUTE,
) {
composable(FOUNDATION_ROUTE) {
FoundationScreen(onContinue = { navController.navigate(PLACEHOLDER_ROUTE) })
}
composable(PLACEHOLDER_ROUTE) {
MessageScreen(
title = stringResource(R.string.placeholder_title),
description = stringResource(R.string.placeholder_description),
)
}
}
}
}
}
@Composable
private fun FoundationScreen(onContinue: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
MessageScreen(
title = stringResource(R.string.foundation_title),
description = stringResource(R.string.foundation_description),
)
ABoxButton(
onClick = onContinue,
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp),
) {
Text(stringResource(R.string.continue_action))
}
}
}
@Composable
private fun MessageScreen(
title: String,
description: String,
) {
Column(
modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
text = title,
style = androidx.compose.material3.MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center,
)
Text(
text = description,
style = androidx.compose.material3.MaterialTheme.typography.bodyLarge,
textAlign = TextAlign.Center,
)
}
}
@@ -0,0 +1,8 @@
<resources>
<style name="Theme.ABoxManager" parent="android:style/Theme.Material.NoActionBar">
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowActionModeOverlay">true</item>
</style>
</resources>
@@ -0,0 +1,8 @@
<resources>
<string name="app_name">ABox Manager</string>
<string name="foundation_title">工程基础已就绪</string>
<string name="foundation_description">公共领域接口和本地开发提供方已经可用。</string>
<string name="continue_action">继续</string>
<string name="placeholder_title">功能模块可以开始开发</string>
<string name="placeholder_description">设备、红外和情景页面将由对应模块负责人实现。</string>
</resources>
@@ -0,0 +1,8 @@
<resources>
<string name="app_name">ABox Manager</string>
<string name="foundation_title">Project foundation ready</string>
<string name="foundation_description">The shared domain contracts and local development providers are available.</string>
<string name="continue_action">Continue</string>
<string name="placeholder_title">Feature development can start</string>
<string name="placeholder_description">Device, infrared and scene screens will be added by their module owners.</string>
</resources>
@@ -0,0 +1,8 @@
<resources>
<style name="Theme.ABoxManager" parent="android:style/Theme.Material.Light.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowActionModeOverlay">true</item>
</style>
</resources>