This commit is contained in:
2026-03-16 15:22:49 +09:00
parent a9fdf9ac9f
commit 1383781dc6
35 changed files with 830 additions and 0 deletions
+1
View File
@@ -136,6 +136,7 @@ dependencies {
"include" to listOf("*.aar", "*.jar"), "include" to listOf("*.aar", "*.jar"),
))) )))
implementation(project(":gdrive")) implementation(project(":gdrive"))
implementation("com.google.android.gms:play-services-wearable:19.0.0")
val kotlinVersion: String? by extra val kotlinVersion: String? by extra
val realmVersion = "2.0.0" val realmVersion = "2.0.0"
implementation ("androidx.appcompat:appcompat:1.7.1") implementation ("androidx.appcompat:appcompat:1.7.1")
+4
View File
@@ -146,6 +146,10 @@
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<service
android:name=".workers.WatchGestureService"
android:enabled="true"
android:exported="false" />
<service <service
android:name=".workers.TorrentService" android:name=".workers.TorrentService"
@@ -0,0 +1,120 @@
(function() {
var retryCount = 0;
var maxRetries = 2;
function tryExtract() {
try {
const newUrl = window.location.origin + window.location.pathname;
const hostname = window.location.hostname;
const contentsType = hostname.includes("book") ? "booktoki" :
hostname.includes("mana") ? "manatoki" :
hostname.includes("new") ? "newtoki" : "web";
// 1. 목차(List) 감지 로직
const listBody = document.querySelector(".list-body");
const novelContent = document.querySelector("#novel_content");
// [중요] 두 핵심 요소가 모두 없으면 재시도 결정
if (!listBody && !novelContent) {
if (retryCount < maxRetries) {
retryCount++;
console.log("DEBUG_LOG: [JS] 요소를 찾지 못해 재시도 중... (" + retryCount + ")");
setTimeout(tryExtract, 500); // 0.5초 후 다시 실행
return;
} else {
console.log("DEBUG_LOG: [JS] 최대 재시도 횟수 초과");
window.webkit.messageHandlers.ContentsRcv.postMessage(JSON.stringify({
'type': 'JP',
'currentUrl' : newUrl
}));
}
return;
}
// --- 1. 목차 추출 실행 ---
if (listBody !== null) {
const contentsArray = [];
const children = listBody.children;
const bookTitleEl = document.querySelector('.view-title span');
const bookTitle = bookTitleEl ? bookTitleEl.innerText.trim() : "Unknown";
const pagination = document.querySelector(".pagination");
let nextPagingUrl = null;
if (pagination) {
const activeLi = pagination.querySelector("li.active");
if (activeLi && activeLi.nextElementSibling) {
const nextA = activeLi.nextElementSibling.querySelector("a");
// 다음 엘리먼트가 존재하고, 'disabled' 클래스가 없으며, href가 있는 경우
if (nextA && nextA.href && !activeLi.nextElementSibling.classList.contains("disabled")) {
nextPagingUrl = nextA.href;
}
}
}
for (let i = 0; i < children.length; i++) {
try {
const wrNumEl = children[i].getElementsByClassName('wr-num')[0];
const wrSubjectA = children[i].getElementsByClassName('wr-subject')[0]?.getElementsByTagName('a')[0];
if (!wrNumEl || !wrSubjectA) continue;
let pageUrl = new URL(wrSubjectA.href, window.location.origin).pathname;
let paths = pageUrl.split('/').filter(p => 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();
})();
@@ -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")
}
}
+1
View File
@@ -17,6 +17,7 @@ plugins {
id ("com.android.library") version "8.10.1" apply false id ("com.android.library") version "8.10.1" apply false
id ("io.realm.kotlin") version "2.0.0" 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.android") version kotlinVersion apply false
id("org.jetbrains.kotlin.plugin.compose") version kotlinVersion apply false
} }
+1
View File
@@ -0,0 +1 @@
/build
+73
View File
@@ -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")
}
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Ignore the IconLocation for the Tile preview images -->
<issue id="IconLocation">
<ignore path="res/drawable/tile_preview.png" />
<ignore path="res/drawable-round/tile_preview.png" />
</issue>
</lint>
+21
View 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
+68
View File
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.type.watch" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.DeviceDefault">
<service
android:name=".complication.MainComplicationService"
android:exported="true"
android:label="@string/complication_label"
android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
<intent-filter>
<action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST" />
</intent-filter>
<meta-data
android:name="android.support.wearable.complications.SUPPORTED_TYPES"
android:value="SHORT_TEXT" />
<meta-data
android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
android:value="0" />
</service>
<service
android:name=".tile.MainTileService"
android:exported="true"
android:label="@string/tile_label"
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
<intent-filter>
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
</intent-filter>
<meta-data
android:name="androidx.wear.tiles.PREVIEW"
android:resource="@drawable/tile_preview" />
</service>
<uses-library
android:name="com.google.android.wearable"
android:required="true" />
<!--
Set to true if your app is Standalone, that is, it does not require the handheld
app to run.
-->
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
<activity
android:name=".presentation.MainActivity"
android:exported="true"
android:taskAffinity=""
android:theme="@style/MainActivityTheme.Starting">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -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()
}
@@ -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")
}
@@ -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
)
}
@@ -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)
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -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:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
@@ -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:viewportWidth="108"
android:viewportHeight="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:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="48dp"
android:height="48dp"
android:gravity="center">
<shape android:shape="oval">
<solid android:color="#FFFFFF" />
</shape>
</item>
<item
android:width="40dp"
android:height="40dp"
android:gravity="center">
<vector
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M17.6,11.48 L19.44,8.3a0.63,0.63 0,0 0,-1.09 -0.63l-1.88,3.24a11.43,11.43 0,0 0,-8.94 0L5.65,7.67a0.63,0.63 0,0 0,-1.09 0.63L6.4,11.48A10.81,10.81 0,0 0,1 20L23,20A10.81,10.81 0,0 0,17.6 11.48ZM7,17.25A1.25,1.25 0,1 1,8.25 16,1.25 1.25,0 0,1 7,17.25ZM17,17.25A1.25,1.25 0,1 1,18.25 16,1.25 1.25,0 0,1 17,17.25Z" />
</vector>
</item>
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

@@ -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>
@@ -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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

@@ -0,0 +1,3 @@
<resources>
<string name="hello_world">From the Round world,\nHello, %1$s!</string>
</resources>
@@ -0,0 +1,10 @@
<resources>
<string name="app_name">lunLauncher</string>
<!--
This string is used for square devices and overridden by hello_world in
values-round/strings.xml for round devices.
-->
<string name="hello_world">From the Square world,\nHello, %1$s!</string>
<string name="tile_label">Example tile</string>
<string name="complication_label">Example complication</string>
</resources>
@@ -0,0 +1,8 @@
<resources>
<style name="MainActivityTheme.Starting" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@android:color/black</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="postSplashScreenTheme">@android:style/Theme.DeviceDefault</item>
</style>
</resources>
+1
View File
@@ -24,3 +24,4 @@ dependencyResolutionManagement {
rootProject.name = "LunarLauncher" rootProject.name = "LunarLauncher"
include ("app","library","utils") include ("app","library","utils")
include(":gdrive") include(":gdrive")
include(":lun_launcher")