diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 69c85c35..a2dd6e62 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -136,6 +136,7 @@ dependencies {
"include" to listOf("*.aar", "*.jar"),
)))
implementation(project(":gdrive"))
+ implementation("com.google.android.gms:play-services-wearable:19.0.0")
val kotlinVersion: String? by extra
val realmVersion = "2.0.0"
implementation ("androidx.appcompat:appcompat:1.7.1")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9edb2e9f..2c3996b0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -146,6 +146,10 @@
android:enabled="true"
android:exported="false" />
+
p);
+ if (paths.length > 0) {
+ var lastPart = paths[paths.length - 1];
+ var isOnlyNumber = lastPart && Array.from(lastPart).every(ch => ch >= '0' && ch <= '9');
+ if (!isOnlyNumber) paths.pop();
+ }
+ pageUrl = "/" + paths.join('/');
+
+ contentsArray.push({
+ 'chapterID': parseInt(wrNumEl.textContent.replace(/[^0-9]/g, "")),
+ 'chapterNum': parseInt(wrNumEl.textContent.replace(/[^0-9]/g, "")),
+ 'pathUrl': pageUrl,
+ 'contentsType': contentsType,
+ 'bookPageUrl': window.location.pathname,
+ 'chapterTitle': wrSubjectA.innerText.split('\n').pop().trim(),
+ 'bookTitle': bookTitle,
+ 'currentUrl' : newUrl
+ });
+ } catch (e) {}
+ }
+
+ if (contentsArray.length > 0) {
+ window.webkit.messageHandlers.ContentsRcv.postMessage(JSON.stringify({
+ 'type': 'getListResult',
+ 'contentsType': contentsType,
+ 'bookTitle': bookTitle,
+ 'bookPageUrl': window.location.pathname,
+ 'pages': contentsArray,
+ 'currentUrl' : newUrl,
+ 'nextPagingUrl': nextPagingUrl
+ }));
+ return; // 전송 성공 시 종료
+ }
+ }
+
+ // --- 2. 본문 추출 실행 ---
+ if (novelContent !== null) {
+ const titleEl = document.querySelector(".page-desc");
+ const chapterTitle = titleEl ? titleEl.innerText.trim() : "";
+ const contents = novelContent.innerText.trim();
+
+
+ if (contents.length > 100) {
+ window.webkit.messageHandlers.ContentsRcv.postMessage(JSON.stringify({
+ 'type': 'BookContents',
+ 'chapterTitle': chapterTitle,
+ 'bookContents': contents,
+ 'pageUrl' : window.location.pathname,
+ 'currentUrl' : newUrl
+ }));
+ }
+ }
+ } catch (e) {
+ console.log("Unified Script Error: " + e);
+ }
+ }
+
+ // 최초 실행
+ tryExtract();
+})();
\ No newline at end of file
diff --git a/app/src/main/kotlin/bums/lunatic/launcher/workers/WatchGestureService.kt b/app/src/main/kotlin/bums/lunatic/launcher/workers/WatchGestureService.kt
new file mode 100644
index 00000000..966e1182
--- /dev/null
+++ b/app/src/main/kotlin/bums/lunatic/launcher/workers/WatchGestureService.kt
@@ -0,0 +1,25 @@
+package bums.lunatic.launcher.workers
+
+import bums.lunatic.launcher.utils.Blog
+import com.google.android.gms.wearable.MessageEvent
+import com.google.android.gms.wearable.WearableListenerService
+
+class WatchGestureService : WearableListenerService() {
+ override fun onMessageReceived(messageEvent: MessageEvent) {
+ when (messageEvent.path) {
+ "/gesture/next" -> {
+ // 런처의 다음 페이지로 이동하거나, 이북 앱에 키 이벤트 전송
+ handleGestureAction("NEXT")
+ }
+ "/gesture/prev" -> {
+ handleGestureAction("PREV")
+ }
+ }
+ }
+
+ private fun handleGestureAction(action: String) {
+ // Broadcast를 런처 메인 Activity로 쏘거나,
+ // 직접 AccessibilityService를 호출하여 시스템 이벤트를 발생시킵니다.
+ Blog.LOGE("WatchGesture", "Gesture Received: $action")
+ }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index a5b21a41..ea1e5d07 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -17,6 +17,7 @@ plugins {
id ("com.android.library") version "8.10.1" apply false
id ("io.realm.kotlin") version "2.0.0" apply false
id("org.jetbrains.kotlin.android") version kotlinVersion apply false
+ id("org.jetbrains.kotlin.plugin.compose") version kotlinVersion apply false
}
diff --git a/lun_launcher/.gitignore b/lun_launcher/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/lun_launcher/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/lun_launcher/build.gradle.kts b/lun_launcher/build.gradle.kts
new file mode 100644
index 00000000..67db0bcf
--- /dev/null
+++ b/lun_launcher/build.gradle.kts
@@ -0,0 +1,73 @@
+plugins {
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+ id("org.jetbrains.kotlin.plugin.compose")
+}
+
+android {
+ namespace = "bums.lunatic.launcher"
+ compileSdk = 36
+
+ defaultConfig {
+ applicationId = "bums.lunatic.launcher"
+ minSdk = 30
+ targetSdk = 36
+ versionCode = 1
+ versionName = "1.0"
+
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+ buildFeatures {
+ compose = true
+ }
+ signingConfigs {
+
+ getByName("debug") {
+ storeFile = file("./bs_debug.keystore")
+ storePassword = "android"
+ keyAlias = "androiddebugkey"
+ keyPassword = "android"
+ }
+ }
+}
+
+dependencies {
+
+ implementation("com.google.android.gms:play-services-wearable:19.0.0")
+ implementation(platform("androidx.compose:compose-bom:2024.09.00"))
+ implementation("androidx.compose.ui:ui")
+ implementation("androidx.compose.ui:ui-graphics")
+ implementation("androidx.compose.ui:ui-tooling-preview")
+ implementation("androidx.wear.compose:compose-material:1.2.1")
+ implementation("androidx.wear.compose:compose-foundation:1.2.1")
+ implementation("androidx.wear:wear-tooling-preview:1.0.0")
+ implementation("androidx.activity:activity-compose:1.12.4")
+ implementation("androidx.core:core-splashscreen:1.0.1")
+ implementation("androidx.wear.tiles:tiles:1.4.0")
+ implementation("androidx.wear.tiles:tiles-material:1.4.0")
+ implementation("androidx.wear.tiles:tiles-tooling-preview:1.4.0")
+ implementation("com.google.android.horologist:horologist-compose-tools:0.6.17")
+ implementation("com.google.android.horologist:horologist-tiles:0.6.17")
+ implementation("androidx.wear.watchface:watchface-complications-data-source-ktx:1.2.1")
+ androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.00"))
+ androidTestImplementation("androidx.compose.ui:ui-test-junit4")
+ debugImplementation("androidx.compose.ui:ui-tooling")
+ debugImplementation("androidx.compose.ui:ui-test-manifest")
+ debugImplementation("androidx.wear.tiles:tiles-tooling:1.4.0")
+}
\ No newline at end of file
diff --git a/lun_launcher/lint.xml b/lun_launcher/lint.xml
new file mode 100644
index 00000000..44fac75b
--- /dev/null
+++ b/lun_launcher/lint.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lun_launcher/proguard-rules.pro b/lun_launcher/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/lun_launcher/proguard-rules.pro
@@ -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
\ No newline at end of file
diff --git a/lun_launcher/src/main/AndroidManifest.xml b/lun_launcher/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..16b10e0c
--- /dev/null
+++ b/lun_launcher/src/main/AndroidManifest.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lun_launcher/src/main/java/bums/lunatic/launcher/complication/MainComplicationService.kt b/lun_launcher/src/main/java/bums/lunatic/launcher/complication/MainComplicationService.kt
new file mode 100644
index 00000000..cd9b94a4
--- /dev/null
+++ b/lun_launcher/src/main/java/bums/lunatic/launcher/complication/MainComplicationService.kt
@@ -0,0 +1,41 @@
+package bums.lunatic.launcher.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/lun_launcher/src/main/java/bums/lunatic/launcher/presentation/MainActivity.kt b/lun_launcher/src/main/java/bums/lunatic/launcher/presentation/MainActivity.kt
new file mode 100644
index 00000000..57a8967c
--- /dev/null
+++ b/lun_launcher/src/main/java/bums/lunatic/launcher/presentation/MainActivity.kt
@@ -0,0 +1,104 @@
+/* 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 bums.lunatic.launcher.presentation
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+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.tooling.preview.Preview
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.TimeText
+import androidx.wear.tooling.preview.devices.WearDevices
+import bums.lunatic.launcher.R
+import bums.lunatic.launcher.presentation.theme.LunarLauncherTheme
+import com.google.android.gms.wearable.MessageClient
+import com.google.android.gms.wearable.Wearable
+
+class MainActivity : ComponentActivity() , SensorEventListener {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ installSplashScreen()
+
+ super.onCreate(savedInstanceState)
+
+ setTheme(android.R.style.Theme_DeviceDefault)
+
+ setContent {
+ WearApp("Android")
+ }
+ }
+
+ override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
+
+ }
+ private lateinit var messageClient: MessageClient
+ private var lastX = 0f
+ override fun onSensorChanged(p0: SensorEvent?) {
+ p0?.let { event ->
+ val x = event.values[0]
+
+ // 아주 단순한 Threshold 예시 (나중에 DTW로 교체)
+ if (x > 15f) { // 오른쪽으로 강하게 휘둘렀을 때
+ sendGestureToLauncher("/gesture/next")
+ } else if (x < -15f) {
+ sendGestureToLauncher("/gesture/prev")
+ }
+ lastX = x
+ }
+ }
+ private fun sendGestureToLauncher(path: String) {
+ // 연결된 노드(폰)를 찾아 메시지 전송
+ Wearable.getNodeClient(this).connectedNodes.addOnSuccessListener { nodes ->
+ for (node in nodes) {
+ Wearable.getMessageClient(this).sendMessage(node.id, path, null)
+ }
+ }
+ }
+}
+
+@Composable
+fun WearApp(greetingName: String) {
+ LunarLauncherTheme {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colors.background),
+ contentAlignment = Alignment.Center
+ ) {
+ TimeText()
+ Greeting(greetingName = greetingName)
+ }
+ }
+}
+
+@Composable
+fun Greeting(greetingName: String) {
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center,
+ color = MaterialTheme.colors.primary,
+ text = stringResource(R.string.hello_world, greetingName)
+ )
+}
+
+@Preview(device = WearDevices.SMALL_ROUND, showSystemUi = true)
+@Composable
+fun DefaultPreview() {
+ WearApp("Preview Android")
+}
\ No newline at end of file
diff --git a/lun_launcher/src/main/java/bums/lunatic/launcher/presentation/theme/Theme.kt b/lun_launcher/src/main/java/bums/lunatic/launcher/presentation/theme/Theme.kt
new file mode 100644
index 00000000..48879b38
--- /dev/null
+++ b/lun_launcher/src/main/java/bums/lunatic/launcher/presentation/theme/Theme.kt
@@ -0,0 +1,17 @@
+package bums.lunatic.launcher.presentation.theme
+
+import androidx.compose.runtime.Composable
+import androidx.wear.compose.material.MaterialTheme
+
+@Composable
+fun LunarLauncherTheme(
+ 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/lun_launcher/src/main/java/bums/lunatic/launcher/tile/MainTileService.kt b/lun_launcher/src/main/java/bums/lunatic/launcher/tile/MainTileService.kt
new file mode 100644
index 00000000..81073f64
--- /dev/null
+++ b/lun_launcher/src/main/java/bums/lunatic/launcher/tile/MainTileService.kt
@@ -0,0 +1,85 @@
+package bums.lunatic.launcher.tile
+
+import android.content.Context
+import androidx.wear.protolayout.ColorBuilders.argb
+import androidx.wear.protolayout.LayoutElementBuilders
+import androidx.wear.protolayout.ResourceBuilders
+import androidx.wear.protolayout.TimelineBuilders
+import androidx.wear.protolayout.material.Colors
+import androidx.wear.protolayout.material.Text
+import androidx.wear.protolayout.material.Typography
+import androidx.wear.protolayout.material.layouts.PrimaryLayout
+import androidx.wear.tiles.RequestBuilders
+import androidx.wear.tiles.TileBuilders
+import androidx.wear.tiles.tooling.preview.Preview
+import androidx.wear.tiles.tooling.preview.TilePreviewData
+import androidx.wear.tooling.preview.devices.WearDevices
+import com.google.android.horologist.annotations.ExperimentalHorologistApi
+import com.google.android.horologist.tiles.SuspendingTileService
+
+private const val RESOURCES_VERSION = "0"
+
+/**
+ * Skeleton for a tile with no images.
+ */
+@OptIn(ExperimentalHorologistApi::class)
+class MainTileService : SuspendingTileService() {
+
+ override suspend fun resourcesRequest(
+ requestParams: RequestBuilders.ResourcesRequest
+ ) = resources(requestParams)
+
+ override suspend fun tileRequest(
+ requestParams: RequestBuilders.TileRequest
+ ) = tile(requestParams, this)
+}
+
+private fun resources(
+ requestParams: RequestBuilders.ResourcesRequest
+): ResourceBuilders.Resources {
+ return ResourceBuilders.Resources.Builder()
+ .setVersion(RESOURCES_VERSION)
+ .build()
+}
+
+private fun tile(
+ requestParams: RequestBuilders.TileRequest,
+ context: Context,
+): TileBuilders.Tile {
+ val singleTileTimeline = TimelineBuilders.Timeline.Builder()
+ .addTimelineEntry(
+ TimelineBuilders.TimelineEntry.Builder()
+ .setLayout(
+ LayoutElementBuilders.Layout.Builder()
+ .setRoot(tileLayout(requestParams, context))
+ .build()
+ )
+ .build()
+ )
+ .build()
+
+ return TileBuilders.Tile.Builder()
+ .setResourcesVersion(RESOURCES_VERSION)
+ .setTileTimeline(singleTileTimeline)
+ .build()
+}
+
+private fun tileLayout(
+ requestParams: RequestBuilders.TileRequest,
+ context: Context,
+): LayoutElementBuilders.LayoutElement {
+ return PrimaryLayout.Builder(requestParams.deviceConfiguration)
+ .setResponsiveContentInsetEnabled(true)
+ .setContent(
+ Text.Builder(context, "Hello World!")
+ .setColor(argb(Colors.DEFAULT.onSurface))
+ .setTypography(Typography.TYPOGRAPHY_CAPTION1)
+ .build()
+ ).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/lun_launcher/src/main/res/drawable-round/tile_preview.png b/lun_launcher/src/main/res/drawable-round/tile_preview.png
new file mode 100644
index 00000000..474fac4d
Binary files /dev/null and b/lun_launcher/src/main/res/drawable-round/tile_preview.png differ
diff --git a/lun_launcher/src/main/res/drawable/ic_launcher_background.xml b/lun_launcher/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..07d5da9c
--- /dev/null
+++ b/lun_launcher/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lun_launcher/src/main/res/drawable/ic_launcher_foreground.xml b/lun_launcher/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 00000000..2b068d11
--- /dev/null
+++ b/lun_launcher/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lun_launcher/src/main/res/drawable/splash_icon.xml b/lun_launcher/src/main/res/drawable/splash_icon.xml
new file mode 100644
index 00000000..7874e83f
--- /dev/null
+++ b/lun_launcher/src/main/res/drawable/splash_icon.xml
@@ -0,0 +1,27 @@
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
diff --git a/lun_launcher/src/main/res/drawable/tile_preview.png b/lun_launcher/src/main/res/drawable/tile_preview.png
new file mode 100644
index 00000000..8cbe3ed5
Binary files /dev/null and b/lun_launcher/src/main/res/drawable/tile_preview.png differ
diff --git a/lun_launcher/src/main/res/mipmap-anydpi/ic_launcher.xml b/lun_launcher/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 00000000..6f3b755b
--- /dev/null
+++ b/lun_launcher/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lun_launcher/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/lun_launcher/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 00000000..6f3b755b
--- /dev/null
+++ b/lun_launcher/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lun_launcher/src/main/res/mipmap-hdpi/ic_launcher.webp b/lun_launcher/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 00000000..c209e78e
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/lun_launcher/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..b2dfe3d1
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-mdpi/ic_launcher.webp b/lun_launcher/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 00000000..4f0f1d64
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/lun_launcher/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..62b611da
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-xhdpi/ic_launcher.webp b/lun_launcher/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 00000000..948a3070
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/lun_launcher/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..1b9a6956
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/lun_launcher/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..28d4b77f
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/lun_launcher/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..9287f508
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/lun_launcher/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..aa7d6427
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/lun_launcher/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/lun_launcher/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..9126ae37
Binary files /dev/null and b/lun_launcher/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/lun_launcher/src/main/res/values-round/strings.xml b/lun_launcher/src/main/res/values-round/strings.xml
new file mode 100644
index 00000000..42f12297
--- /dev/null
+++ b/lun_launcher/src/main/res/values-round/strings.xml
@@ -0,0 +1,3 @@
+
+ From the Round world,\nHello, %1$s!
+
\ No newline at end of file
diff --git a/lun_launcher/src/main/res/values/strings.xml b/lun_launcher/src/main/res/values/strings.xml
new file mode 100644
index 00000000..2a665b0b
--- /dev/null
+++ b/lun_launcher/src/main/res/values/strings.xml
@@ -0,0 +1,10 @@
+
+ lunLauncher
+
+ From the Square world,\nHello, %1$s!
+ Example tile
+ Example complication
+
\ No newline at end of file
diff --git a/lun_launcher/src/main/res/values/styles.xml b/lun_launcher/src/main/res/values/styles.xml
new file mode 100644
index 00000000..dbf9c83a
--- /dev/null
+++ b/lun_launcher/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index ca960754..8f5643da 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -24,3 +24,4 @@ dependencyResolutionManagement {
rootProject.name = "LunarLauncher"
include ("app","library","utils")
include(":gdrive")
+include(":lun_launcher")