diff --git a/apps/giga-wear/client/build.gradle.kts b/apps/giga-wear/client/build.gradle.kts
index 77705e6..911969d 100644
--- a/apps/giga-wear/client/build.gradle.kts
+++ b/apps/giga-wear/client/build.gradle.kts
@@ -5,9 +5,10 @@ plugins {
alias(libs.plugins.convention.compose)
alias(libs.plugins.convention.koin)
alias(libs.plugins.convention.ktor.client)
+ alias(libs.plugins.convention.serialization)
}
-val appVersion = "1.27.1"
+val appVersion = "1.0"
android {
buildFeatures { buildConfig = true }
@@ -24,6 +25,9 @@ android {
dependencies {
implementation(platform(libs.androidx.compose.bom))
+ implementation(project(":libs:ui"))
+ implementation(project(":libs:http-client"))
+ implementation(project(":libs:base"))
implementation(libs.activity.compose)
implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.compose.material3)
diff --git a/apps/giga-wear/client/src/main/AndroidManifest.xml b/apps/giga-wear/client/src/main/AndroidManifest.xml
index 0943432..2d1e0f3 100644
--- a/apps/giga-wear/client/src/main/AndroidManifest.xml
+++ b/apps/giga-wear/client/src/main/AndroidManifest.xml
@@ -6,51 +6,21 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:required="false" />
+
-
+
@@ -68,4 +38,4 @@
-
\ No newline at end of file
+
diff --git a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/complication/MainComplicationService.kt b/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/complication/MainComplicationService.kt
deleted file mode 100644
index 39ebf81..0000000
--- a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/complication/MainComplicationService.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package ru.shadowsparky.gigawear.complication
-
-import androidx.wear.watchface.complications.data.ComplicationData
-import androidx.wear.watchface.complications.data.ComplicationType
-import androidx.wear.watchface.complications.data.PlainComplicationText
-import androidx.wear.watchface.complications.data.ShortTextComplicationData
-import androidx.wear.watchface.complications.datasource.ComplicationRequest
-import androidx.wear.watchface.complications.datasource.SuspendingComplicationDataSourceService
-import java.util.Calendar
-
-/**
- * Skeleton for complication data source that returns short text.
- */
-class MainComplicationService : SuspendingComplicationDataSourceService() {
-
- override fun getPreviewData(type: ComplicationType): ComplicationData? {
- if (type != ComplicationType.SHORT_TEXT) {
- return null
- }
- return createComplicationData("Mon", "Monday")
- }
-
- override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData {
- return when (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) {
- Calendar.SUNDAY -> createComplicationData("Sun", "Sunday")
- Calendar.MONDAY -> createComplicationData("Mon", "Monday")
- Calendar.TUESDAY -> createComplicationData("Tue", "Tuesday")
- Calendar.WEDNESDAY -> createComplicationData("Wed", "Wednesday")
- Calendar.THURSDAY -> createComplicationData("Thu", "Thursday")
- Calendar.FRIDAY -> createComplicationData("Fri", "Friday")
- Calendar.SATURDAY -> createComplicationData("Sat", "Saturday")
- else -> throw IllegalArgumentException("too many days")
- }
- }
-
- private fun createComplicationData(text: String, contentDescription: String) =
- ShortTextComplicationData.Builder(
- text = PlainComplicationText.Builder(text).build(),
- contentDescription = PlainComplicationText.Builder(contentDescription).build()
- ).build()
-}
\ No newline at end of file
diff --git a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/presentation/MainActivity.kt b/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/presentation/MainActivity.kt
deleted file mode 100644
index 07f949c..0000000
--- a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/presentation/MainActivity.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-/* While this template provides a good starting point for using Wear Compose, you can always
- * take a look at https://github.com/android/wear-os-samples/tree/main/ComposeStarter to find the
- * most up to date changes to the libraries and their usages.
- */
-
-package ru.shadowsparky.gigawear.presentation
-
-import android.app.Activity
-import android.content.Intent
-import android.os.Bundle
-import android.speech.RecognizerIntent
-import android.speech.tts.TextToSpeech
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.rememberLauncherForActivityResult
-import androidx.activity.compose.setContent
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
-import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
-import androidx.wear.compose.material3.AppScaffold
-import androidx.wear.compose.material3.Button
-import androidx.wear.compose.material3.ButtonDefaults
-import androidx.wear.compose.material3.EdgeButton
-import androidx.wear.compose.material3.ListHeader
-import androidx.wear.compose.material3.MaterialTheme
-import androidx.wear.compose.material3.ScreenScaffold
-import androidx.wear.compose.material3.SurfaceTransformation
-import androidx.wear.compose.material3.Text
-import androidx.wear.compose.material3.lazy.rememberTransformationSpec
-import androidx.wear.compose.material3.lazy.transformedHeight
-import ru.shadowsparky.gigawear.R
-import ru.shadowsparky.gigawear.presentation.theme.AndroidDevTheme
-import java.util.Locale
-
-class MainActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContent {
- WearApp("Android")
- }
- }
-}
-
-@Composable
-fun WearApp(greetingName: String) {
- val context = LocalContext.current
- var spokenText by remember { mutableStateOf("Тут будет твой текст") }
- val tts = remember { mutableStateOf(null) }
- DisposableEffect(Unit) {
- tts.value = TextToSpeech(context) { status ->
- if (status == TextToSpeech.SUCCESS) {
- tts.value?.language = Locale.getDefault()
- }
- }
- onDispose {
- tts.value?.stop()
- tts.value?.shutdown()
- }
- }
- val voiceLauncher = rememberLauncherForActivityResult(
- contract = ActivityResultContracts.StartActivityForResult()
- ) { result ->
- if (result.resultCode == Activity.RESULT_OK) {
- val results = result.data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
- val text = results?.firstOrNull()
- if (!text.isNullOrBlank()) {
- spokenText = text
- tts.value?.speak(text, TextToSpeech.QUEUE_FLUSH, null, null)
- }
- }
- }
- AndroidDevTheme {
- AppScaffold {
- val listState = rememberTransformingLazyColumnState()
- val transformationSpec = rememberTransformationSpec()
- ScreenScaffold(
- scrollState = listState,
- edgeButton = {
- EdgeButton(
- onClick = {
- val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
- putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
- putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault().toString())
- }
- try {
- voiceLauncher.launch(intent)
- } catch (e: Exception) {
- spokenText = " Ошибка: Голосовой ввод недоступен"
- }
- },
- colors = ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.primaryContainer,
- contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
- ),
- ) {
- Text(" Начать ввод")
- }
- },
- ) { contentPadding ->
- TransformingLazyColumn(contentPadding = contentPadding, state = listState) {
- item {
- ListHeader(
- modifier = Modifier.fillMaxWidth().transformedHeight(this, transformationSpec),
- transformation = SurfaceTransformation(transformationSpec),
- ) {
- Text(text = stringResource(R.string.hello_world, greetingName))
- }
- }
- item {
- Button(
- onClick = {
- tts.value?.speak(spokenText, TextToSpeech.QUEUE_FLUSH, null, null)
- },
- modifier = Modifier.fillMaxWidth().transformedHeight(this, transformationSpec),
- transformation = SurfaceTransformation(transformationSpec),
- colors = ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.secondaryContainer
- )
- ) {
- Text(text = spokenText)
- }
- }
- }
- }
- }
- }
-}
diff --git a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/presentation/theme/Theme.kt b/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/presentation/theme/Theme.kt
deleted file mode 100644
index b5d29d3..0000000
--- a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/presentation/theme/Theme.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package ru.shadowsparky.gigawear.presentation.theme
-
-import androidx.compose.runtime.Composable
-import androidx.wear.compose.material3.MaterialTheme
-
-@Composable
-fun AndroidDevTheme(
- content: @Composable () -> Unit
-) {
- /**
- * Empty theme to customize for your app.
- * See: https://developer.android.com/jetpack/compose/designsystems/custom
- */
- MaterialTheme(
- content = content
- )
-}
\ No newline at end of file
diff --git a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/tile/MainTileService.kt b/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/tile/MainTileService.kt
deleted file mode 100644
index 056eae4..0000000
--- a/apps/giga-wear/client/src/main/java/ru/shadowsparky/gigawear/tile/MainTileService.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package ru.shadowsparky.gigawear.tile
-
-import android.content.Context
-import androidx.wear.protolayout.ResourceBuilders.Resources
-import androidx.wear.protolayout.TimelineBuilders
-import androidx.wear.protolayout.material3.Typography.BODY_LARGE
-import androidx.wear.tiles.RequestBuilders
-import androidx.wear.tiles.TileBuilders
-import androidx.wear.tiles.TileService
-import com.google.common.util.concurrent.Futures
-import androidx.wear.protolayout.material3.materialScope
-import androidx.wear.protolayout.material3.primaryLayout
-import androidx.wear.protolayout.material3.text
-import androidx.wear.protolayout.types.layoutString
-import androidx.wear.tiles.RequestBuilders.ResourcesRequest
-import androidx.wear.tiles.tooling.preview.Preview
-import androidx.wear.tiles.tooling.preview.TilePreviewData
-import androidx.wear.tooling.preview.devices.WearDevices
-import ru.shadowsparky.gigawear.R
-import com.google.common.util.concurrent.ListenableFuture
-
-private const val RESOURCES_VERSION = "0"
-
-class MainTileService : TileService() {
- override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture =
- Futures.immediateFuture(tile(requestParams, this))
-
- override fun onTileResourcesRequest(requestParams: ResourcesRequest): ListenableFuture =
- Futures.immediateFuture(resources(requestParams))
-}
-
-private fun resources(requestParams: ResourcesRequest): Resources {
- return Resources.Builder()
- .setVersion(RESOURCES_VERSION)
- .build()
-}
-
-private fun tile(
- requestParams: RequestBuilders.TileRequest,
- context: Context,
-): TileBuilders.Tile {
- return TileBuilders.Tile.Builder()
- .setResourcesVersion(RESOURCES_VERSION)
- .setTileTimeline(
- TimelineBuilders.Timeline.fromLayoutElement(
- materialScope(context, requestParams.deviceConfiguration) {
- primaryLayout(
- mainSlot = {
- text(
- context.getString(R.string.hello_world, "Tile").layoutString,
- typography = BODY_LARGE
- )
- }
- )
- }
- )
- )
- .build()
-}
-
-@Preview(device = WearDevices.SMALL_ROUND)
-@Preview(device = WearDevices.LARGE_ROUND)
-fun tilePreview(context: Context) = TilePreviewData(::resources) {
- tile(it, context)
-}
\ No newline at end of file
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/GigaWearModule.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/GigaWearModule.kt
new file mode 100644
index 0000000..e736c40
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/GigaWearModule.kt
@@ -0,0 +1,10 @@
+package ru.shadowsparky.gigawear
+
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Configuration
+import org.koin.core.annotation.Module
+
+@Module
+@ComponentScan
+@Configuration
+class GigaWearModule
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/App.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/App.kt
new file mode 100644
index 0000000..4f2cd37
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/App.kt
@@ -0,0 +1,16 @@
+package ru.shadowsparky.gigawear.presentation
+
+import android.app.Application
+import org.koin.core.annotation.KoinApplication
+import org.koin.plugin.module.dsl.startKoin
+
+@KoinApplication
+annotation class GigaWearApp
+
+class App : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ startKoin()
+ }
+}
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/GigaWearRootComponent.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/GigaWearRootComponent.kt
new file mode 100644
index 0000000..acd0465
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/GigaWearRootComponent.kt
@@ -0,0 +1,24 @@
+package ru.shadowsparky.gigawear.presentation
+
+import com.arkivanov.decompose.ComponentContext
+import kotlinx.serialization.KSerializer
+import org.koin.core.Koin
+import org.koin.core.annotation.Factory
+import ru.shadowsparky.gigawear.presentation.nav.Route
+import ru.shadowsparky.ui.nav.RootComponent
+
+class GigaWearRootComponent(
+ context: ComponentContext
+) : RootComponent(context) {
+ override val initStack: List = listOf(Route.MainScreen())
+ override val serializer: KSerializer = Route.serializer()
+ override val koin: Koin = ru.shadowsparky.koin
+}
+
+@Factory
+class RootComponentFactory {
+
+ fun create(context: ComponentContext): GigaWearRootComponent {
+ return GigaWearRootComponent(context)
+ }
+}
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/MainActivity.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/MainActivity.kt
new file mode 100644
index 0000000..0a5ac91
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/MainActivity.kt
@@ -0,0 +1,26 @@
+package ru.shadowsparky.gigawear.presentation
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import com.arkivanov.decompose.retainedComponent
+import org.koin.android.ext.android.inject
+import ru.shadowsparky.gigawear.presentation.main.MainScreen
+import ru.shadowsparky.gigawear.presentation.nav.Child
+import ru.shadowsparky.ui.nav.Nav
+
+class MainActivity : ComponentActivity() {
+ private val rootFactory by inject()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val root = retainedComponent { rootFactory.create(it) }
+ setContent {
+ Nav(root) { child, _ ->
+ when (child) {
+ is Child.MainChild -> MainScreen(child.component)
+ }
+ }
+ }
+ }
+}
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/main/MainComponent.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/main/MainComponent.kt
new file mode 100644
index 0000000..d295ae6
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/main/MainComponent.kt
@@ -0,0 +1,27 @@
+package ru.shadowsparky.gigawear.presentation.main
+
+import com.arkivanov.decompose.ComponentContext
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.Named
+import ru.shadowsparky.gigawear.presentation.nav.Child
+import ru.shadowsparky.gigawear.presentation.nav.Route
+import ru.shadowsparky.ui.nav.ComponentFactory
+import ru.shadowsparky.ui.nav.RouteNavigator
+
+class MainComponent(
+ private val context: ComponentContext
+) : ComponentContext by context {
+}
+
+@Factory
+@Named(Route.MAIN)
+class MainComponentFactory : ComponentFactory {
+ override fun create(
+ route: Route.MainScreen,
+ child: ComponentContext,
+ root: RouteNavigator
+ ): Child {
+ val component = MainComponent(child)
+ return Child.MainChild(component)
+ }
+}
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/main/MainScreen.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/main/MainScreen.kt
new file mode 100644
index 0000000..55f9039
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/main/MainScreen.kt
@@ -0,0 +1,14 @@
+package ru.shadowsparky.gigawear.presentation.main
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.safeContentPadding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+
+@Composable
+fun MainScreen(component: MainComponent) {
+ Box(modifier = Modifier.safeContentPadding()) {
+ Text("MainScreen $component")
+ }
+}
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/nav/Child.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/nav/Child.kt
new file mode 100644
index 0000000..7a8132b
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/nav/Child.kt
@@ -0,0 +1,7 @@
+package ru.shadowsparky.gigawear.presentation.nav
+
+import ru.shadowsparky.gigawear.presentation.main.MainComponent
+
+sealed class Child : ru.shadowsparky.ui.nav.Child {
+ class MainChild(val component: MainComponent) : Child()
+}
diff --git a/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/nav/Route.kt b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/nav/Route.kt
new file mode 100644
index 0000000..19c0f3e
--- /dev/null
+++ b/apps/giga-wear/client/src/main/kotlin/ru/shadowsparky/gigawear/presentation/nav/Route.kt
@@ -0,0 +1,14 @@
+package ru.shadowsparky.gigawear.presentation.nav
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+sealed class Route : ru.shadowsparky.ui.nav.Route() {
+
+ @Serializable
+ data class MainScreen(override val routeId: String = MAIN) : Route()
+
+ companion object {
+ const val MAIN = "main"
+ }
+}
diff --git a/apps/giga-wear/client/src/main/res/values/styles.xml b/apps/giga-wear/client/src/main/res/values/styles.xml
index dbf9c83..a81c145 100644
--- a/apps/giga-wear/client/src/main/res/values/styles.xml
+++ b/apps/giga-wear/client/src/main/res/values/styles.xml
@@ -1,8 +1,7 @@
-
-
\ No newline at end of file
+