diff --git a/app-service-hilt/.gitignore b/app-service-hilt/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app-service-hilt/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app-service-hilt/Readme.md b/app-service-hilt/Readme.md
new file mode 100644
index 0000000..e91400a
--- /dev/null
+++ b/app-service-hilt/Readme.md
@@ -0,0 +1,31 @@
+# Service
+
+## Initial Setup
+
+This is a sample project on how to use `compose-floating-window` on a service for long running operations
+
+1. Create a new service. Like [this](src/main/java/com/github/only52607/compose/window/service/MyService.kt) for example
+
+2. Add the permission to the manifest file
+
+ ```xml
+
+ ```
+
+3. Declare the service in the manifest file
+
+ ```xml
+
+ ```
+
+4. Follow the `MyService` sample on how to use it on a service.
+
+## Usage
+
+Do not follow the `build.gradle.kts` setup as it was done for the sample project
+
+Note:
+- Be sure to `AppCompatActivity` instead of `ComponentActivity` in order to change the theme of the app
+
+This is mostly just a sample project on how to incorporate hilt into viewmodels and services.
+
diff --git a/app-service-hilt/build.gradle.kts b/app-service-hilt/build.gradle.kts
new file mode 100644
index 0000000..9ad022e
--- /dev/null
+++ b/app-service-hilt/build.gradle.kts
@@ -0,0 +1,89 @@
+buildscript {
+ dependencies {
+ classpath(libs.ksp.gradle)
+ classpath(libs.hilt.android.gradle.plugin)
+ }
+}
+hilt {
+ enableAggregatingTask = false
+}
+
+plugins {
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+ alias(libs.plugins.compose.compiler)
+
+ alias(libs.plugins.hilt.android)
+ alias(libs.plugins.ksp)
+}
+
+android {
+ namespace = "com.github.only52607.compose.window.hilt"
+ compileSdk = libs.versions.compile.sdk.get().toInt()
+
+ defaultConfig {
+ applicationId = "com.github.only52607.compose.window"
+ minSdk = libs.versions.min.sdk.get().toInt()
+ targetSdk = libs.versions.target.sdk.get().toInt()
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ vectorDrawables {
+ useSupportLibrary = true
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ signingConfig = signingConfigs.getByName("debug")
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+ buildFeatures {
+ compose = true
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+}
+
+dependencies {
+ implementation(project(":library"))
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.lifecycle.runtime.ktx)
+ implementation(libs.androidx.lifecycle.viewmodel.compose)
+ implementation(libs.activity.compose)
+ implementation(platform(libs.compose.bom))
+ implementation(libs.compose.ui)
+ implementation(libs.compose.ui.graphics)
+ implementation(libs.compose.ui.tooling.preview)
+ implementation(libs.compose.material3)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.test.junit)
+ androidTestImplementation(libs.androidx.test.espresso)
+ androidTestImplementation(platform(libs.compose.bom))
+ androidTestImplementation(libs.compose.ui.test.junit4)
+ debugImplementation(libs.compose.ui.tooling)
+ debugImplementation(libs.compose.ui.test.manifest)
+ debugImplementation(libs.leak.canary)
+
+ implementation(libs.dagger.hilt.android)
+ ksp(libs.dagger.hilt.compiler)
+
+ implementation(libs.appcompat)
+ implementation(libs.bundles.datastore)
+}
\ No newline at end of file
diff --git a/app-service-hilt/proguard-rules.pro b/app-service-hilt/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app-service-hilt/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/app-service-hilt/src/androidTest/java/com/github/only52607/compose/window/hilt/ExampleInstrumentedTest.kt b/app-service-hilt/src/androidTest/java/com/github/only52607/compose/window/hilt/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..b75aa46
--- /dev/null
+++ b/app-service-hilt/src/androidTest/java/com/github/only52607/compose/window/hilt/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.github.only52607.compose.window
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.github.only52607.compose.window", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/AndroidManifest.xml b/app-service-hilt/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..51f513c
--- /dev/null
+++ b/app-service-hilt/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/FloatingApplication.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/FloatingApplication.kt
new file mode 100644
index 0000000..4188296
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/FloatingApplication.kt
@@ -0,0 +1,7 @@
+package com.github.only52607.compose.window.hilt
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class FloatingApplication: Application()
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/MainActivity.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/MainActivity.kt
new file mode 100644
index 0000000..8e8f531
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/MainActivity.kt
@@ -0,0 +1,96 @@
+package com.github.only52607.compose.window.hilt
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatDelegate
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.github.only52607.compose.window.hilt.repository.UserPreferencesRepository
+import com.github.only52607.compose.window.hilt.ui.DialogPermission
+import com.github.only52607.compose.window.hilt.ui.theme.ComposeFloatingWindowTheme
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class MainActivity : AppCompatActivity() {
+
+ @Inject
+ lateinit var userPreferencesRepository: UserPreferencesRepository
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ ComposeFloatingWindowTheme {
+ LaunchedEffect(userPreferencesRepository.darkModeFlow) {
+ userPreferencesRepository
+ .darkModeFlow
+ .distinctUntilChanged()
+ .collect { darkMode ->
+ AppCompatDelegate.setDefaultNightMode(
+ if (darkMode) AppCompatDelegate.MODE_NIGHT_YES
+ else AppCompatDelegate.MODE_NIGHT_NO
+ )
+ }
+ }
+
+ val showDialogPermission = remember { mutableStateOf(false) }
+
+ val context = LocalContext.current
+
+ val isShowing by MyService.serviceStarted.collectAsStateWithLifecycle(false)
+
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ ) {
+ Column(
+ Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Button(
+ onClick = {
+ MyService.start(context)
+ },
+ enabled = !isShowing
+ ) {
+ Text("Show")
+ }
+ Spacer(modifier = Modifier.height(10.dp))
+ Button(
+ onClick = {
+ MyService.stop(context)
+ },
+ enabled = isShowing
+ ) {
+ Text("Hide")
+ }
+ }
+ DialogPermission(showDialogState = showDialogPermission)
+ }
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/MyService.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/MyService.kt
new file mode 100644
index 0000000..19f47cb
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/MyService.kt
@@ -0,0 +1,68 @@
+package com.github.only52607.compose.window.hilt
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.IBinder
+import com.github.only52607.compose.window.ComposeFloatingWindow
+import com.github.only52607.compose.window.hilt.repository.UserPreferencesRepository
+import com.github.only52607.compose.window.hilt.ui.FloatingWindowContent
+import com.github.only52607.compose.window.hilt.ui.FloatingWindowViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class MyService : Service() {
+ companion object {
+ private var _serviceStarted = MutableStateFlow(false)
+ val serviceStarted: StateFlow
+ get() = _serviceStarted.asStateFlow()
+
+ fun start(context: Context) {
+ val intent = Intent(context, MyService::class.java)
+ context.startService(intent)
+ }
+
+ fun stop(context: Context) {
+ val intent = Intent(context, MyService::class.java)
+ context.stopService(intent)
+ }
+ }
+
+ @Inject
+ lateinit var userPreferencesRepository: UserPreferencesRepository
+
+ private val viewModel by lazy {
+ FloatingWindowViewModel(userPreferencesRepository)
+ }
+
+ private val floatingWindow by lazy {
+ createFloatingWindow()
+ }
+
+ private fun createFloatingWindow(): ComposeFloatingWindow =
+ ComposeFloatingWindow(this).apply {
+ setContent {
+ FloatingWindowContent(viewModel)
+ }
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ _serviceStarted.update { true }
+ floatingWindow.show()
+ }
+
+ override fun onBind(intent: Intent?): IBinder? = null
+
+ override fun onDestroy() {
+ _serviceStarted.update { false }
+ // Call close for cleanup and it will hide it in the process
+ floatingWindow.close()
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/module/AppModule.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/module/AppModule.kt
new file mode 100644
index 0000000..cff2284
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/module/AppModule.kt
@@ -0,0 +1,28 @@
+package com.github.only52607.compose.window.hilt.module
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.preferencesDataStore
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+private const val DATASTORE_NAME = "user_prefs"
+
+val Context.dataStore: DataStore by preferencesDataStore(name = DATASTORE_NAME)
+
+
+@Module
+@InstallIn(SingletonComponent::class)
+object AppModule {
+
+ @Provides
+ @Singleton
+ fun provideDataStore(@ApplicationContext context: Context): DataStore {
+ return context.dataStore
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/repository/UserPreferencesRepository.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/repository/UserPreferencesRepository.kt
new file mode 100644
index 0000000..ad620b2
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/repository/UserPreferencesRepository.kt
@@ -0,0 +1,32 @@
+package com.github.only52607.compose.window.hilt.repository
+
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class UserPreferencesRepository @Inject constructor(
+ private val dataStore: DataStore,
+) {
+ companion object {
+ private val DARK_MODE_KEY = booleanPreferencesKey("dark_mode")
+ }
+
+ val darkModeFlow: Flow = dataStore
+ .data
+ .map { preferences ->
+ preferences[DARK_MODE_KEY] ?: false
+ }
+
+ suspend fun setDarkMode(enabled: Boolean) {
+ dataStore.edit { preferences ->
+ preferences[DARK_MODE_KEY] = enabled
+ }
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/DialogPermission.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/DialogPermission.kt
new file mode 100644
index 0000000..2110104
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/DialogPermission.kt
@@ -0,0 +1,73 @@
+package com.github.only52607.compose.window.hilt.ui
+
+import android.content.Context
+import android.content.Intent
+import android.provider.Settings
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Warning
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import com.github.only52607.compose.window.hilt.R
+import androidx.core.net.toUri
+
+@Composable
+fun DialogPermission(
+ showDialogState: MutableState = mutableStateOf(false),
+ permission: String = Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ onDismiss: () -> Unit = { },
+) {
+ var showDialogPermission by remember { showDialogState }
+ val context = LocalContext.current
+ if(showDialogPermission.not()) return
+ AlertDialog(
+ icon = {
+ Icon(Icons.Default.Warning, contentDescription = stringResource(R.string.permission_required))
+ },
+ title = {
+ Text(text = stringResource(id = R.string.permission_required))
+ },
+ text = {
+ Text(text = stringResource(R.string.message_permission_to_draw_on_top_others_apps))
+ },
+ onDismissRequest = onDismiss,
+ confirmButton = {
+ TextButton(
+ onClick = {
+ showDialogPermission = false
+ context.requestPermission(permission)
+ }
+ ) {
+ Text(stringResource(R.string.grant_permission))
+ }
+ },
+ dismissButton = {
+ TextButton(
+ onClick = {
+ showDialogPermission = false
+ }
+ ) {
+ Text(stringResource(R.string.cancel))
+ }
+ }
+ )
+}
+
+private fun Context.requestPermission(permission: String) {
+ startActivity(
+ Intent(
+ permission,
+ "package:$packageName".toUri()
+ ).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ })
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/FloatingWindowContent.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/FloatingWindowContent.kt
new file mode 100644
index 0000000..54fcb05
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/FloatingWindowContent.kt
@@ -0,0 +1,54 @@
+package com.github.only52607.compose.window.hilt.ui
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Call
+import androidx.compose.material3.FloatingActionButton
+import androidx.compose.material3.FloatingActionButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.SystemAlertDialog
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.github.only52607.compose.window.LocalFloatingWindow
+import com.github.only52607.compose.window.dragFloatingWindow
+
+@Composable
+fun FloatingWindowContent(
+ model: FloatingWindowViewModel
+) {
+ val floatingWindow = LocalFloatingWindow.current
+
+ val darkMode by model.darkMode.collectAsStateWithLifecycle(false)
+
+ if (model.dialogVisible) {
+ SystemAlertDialog(
+ onDismissRequest = { model.dismissDialog() },
+ confirmButton = {
+ TextButton(onClick = { model.dismissDialog() }) {
+ Text(text = "OK")
+ }
+ },
+ text = {
+ Text(
+ text = "This is now ${if (darkMode) "Dark" else "Light"} mode",
+ )
+ }
+ )
+ }
+ FloatingActionButton(
+ modifier = Modifier.dragFloatingWindow(),
+ onClick = {
+ model.showDialog(!darkMode)
+ },
+ elevation = FloatingActionButtonDefaults.elevation(
+ defaultElevation = 0.dp
+ )
+ ) {
+ Icon(Icons.Filled.Call, "Call")
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/FloatingWindowViewModel.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/FloatingWindowViewModel.kt
new file mode 100644
index 0000000..2bc0568
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/FloatingWindowViewModel.kt
@@ -0,0 +1,33 @@
+package com.github.only52607.compose.window.hilt.ui
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.github.only52607.compose.window.hilt.repository.UserPreferencesRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+class FloatingWindowViewModel(
+ private val userPreferencesRepository: UserPreferencesRepository,
+) : ViewModel() {
+
+ val darkMode: Flow
+ get() = userPreferencesRepository.darkModeFlow
+
+ private var _dialogVisible by mutableStateOf(false)
+ val dialogVisible: Boolean get() = _dialogVisible
+
+ fun showDialog(value: Boolean) = viewModelScope.launch {
+ _dialogVisible = true
+
+ userPreferencesRepository.setDarkMode(value)
+ }
+
+ fun dismissDialog() {
+ _dialogVisible = false
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Color.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Color.kt
new file mode 100644
index 0000000..1b37c44
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.github.only52607.compose.window.hilt.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)
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Theme.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Theme.kt
new file mode 100644
index 0000000..fdf5aee
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Theme.kt
@@ -0,0 +1,90 @@
+package com.github.only52607.compose.window.hilt.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+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
+import androidx.compose.ui.graphics.Color
+
+private val surfaceDark = Color(0xFF101417)
+private val onSurfaceDark = Color(0xFFE0E3E8)
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80,
+ surface = surfaceDark,
+ onSurface = onSurfaceDark,
+ background = surfaceDark,
+ onBackground = onSurfaceDark,
+)
+
+private val surfaceLight = Color(0xFFF7F9FF)
+private val onSurfaceLight = Color(0xFF181C20)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40,
+ surface = surfaceLight,
+ onSurface = onSurfaceLight,
+ background = surfaceLight,
+ onBackground = surfaceLight
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun ComposeFloatingWindowTheme(
+ 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
+ ) {
+ Surface(
+ color = MaterialTheme.colorScheme.surface,
+ ) {
+ content()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Type.kt b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Type.kt
new file mode 100644
index 0000000..106603d
--- /dev/null
+++ b/app-service-hilt/src/main/java/com/github/only52607/compose/window/hilt/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.github.only52607.compose.window.hilt.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
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/drawable/ic_launcher_background.xml b/app-service-hilt/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app-service-hilt/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app-service-hilt/src/main/res/drawable/ic_launcher_foreground.xml b/app-service-hilt/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app-service-hilt/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app-service-hilt/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app-service-hilt/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app-service-hilt/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app-service-hilt/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/mipmap-hdpi/ic_launcher.webp b/app-service-hilt/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app-service-hilt/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-mdpi/ic_launcher.webp b/app-service-hilt/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app-service-hilt/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app-service-hilt/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app-service-hilt/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app-service-hilt/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app-service-hilt/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app-service-hilt/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app-service-hilt/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app-service-hilt/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/app-service-hilt/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app-service-hilt/src/main/res/values/colors.xml b/app-service-hilt/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/app-service-hilt/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/values/strings.xml b/app-service-hilt/src/main/res/values/strings.xml
new file mode 100644
index 0000000..eec8e67
--- /dev/null
+++ b/app-service-hilt/src/main/res/values/strings.xml
@@ -0,0 +1,7 @@
+
+ ComposeFloatingWindow
+ Permission required
+ Grant permission
+ Cancel
+ …to show floating windows the app needs permissions to draw on top of other apps
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/values/themes.xml b/app-service-hilt/src/main/res/values/themes.xml
new file mode 100644
index 0000000..fc7f172
--- /dev/null
+++ b/app-service-hilt/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/xml/backup_rules.xml b/app-service-hilt/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/app-service-hilt/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/main/res/xml/data_extraction_rules.xml b/app-service-hilt/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/app-service-hilt/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app-service-hilt/src/test/java/com/github/only52607/compose/window/hilt/ExampleUnitTest.kt b/app-service-hilt/src/test/java/com/github/only52607/compose/window/hilt/ExampleUnitTest.kt
new file mode 100644
index 0000000..4ed8f46
--- /dev/null
+++ b/app-service-hilt/src/test/java/com/github/only52607/compose/window/hilt/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.github.only52607.compose.window
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index a266bf1..2a23d6e 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -7,7 +7,7 @@ agp = "8.9.1"
kotlin = "2.1.20"
android-core-ktx = "1.15.0"
-appcompat = "1.6.1"
+appcompat = "1.7.0"
lifecycle = "2.8.7"
activity-compose = "1.10.1"
@@ -22,6 +22,11 @@ google-material = "1.12.0"
leakcanary = "2.14"
+hilt = "2.56.1"
+ksp = "2.1.20-1.0.32"
+
+datastore = "1.1.4"
+
[libraries]
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "android-core-ktx" }
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
@@ -49,9 +54,23 @@ google-material = { module = "com.google.android.material:material", version.ref
leak-canary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }
+ksp-gradle = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
+hilt-android-gradle-plugin = { group = "com.google.dagger", name = "hilt-android-gradle-plugin", version.ref = "hilt" }
+
+dagger-hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
+dagger-hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
+
+datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
+datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" }
+
[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
agp = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
\ No newline at end of file
+compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
+hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
+
+[bundles]
+datastore = ["datastore", "datastore-preferences"]
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 11d2964..e28a792 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -17,4 +17,5 @@ dependencyResolutionManagement {
rootProject.name = "ComposeFloatingWindow"
include(":app")
include(":app-service")
+include(":app-service-hilt")
include(":library")