Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#259, 위젯 기능 추가] #260

Merged
merged 3 commits into from
Sep 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ dependencies {
implementation(projects.feature.home)

implementation(projects.core.designsystem)

implementation(projects.widget)
}
2 changes: 2 additions & 0 deletions core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ dependencies {
implementation(libs.landscapist.bom)
implementation(libs.landscapist.coil)
implementation(libs.landscapist.placeholder)

implementation(libs.androidx.glance)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import androidx.glance.GlanceTheme
import androidx.glance.color.ColorProvider
import androidx.glance.color.colorProviders

private val DarkColorScheme = darkColorScheme(
primary = White,
Expand Down Expand Up @@ -86,7 +89,8 @@ fun KnightsTheme(
SideEffect {
val window = (view.context as Activity).window
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars = !darkTheme
WindowCompat.getInsetsController(window, view).isAppearanceLightNavigationBars =
!darkTheme
}
}

Expand All @@ -106,3 +110,69 @@ object KnightsTheme {
@Composable
get() = LocalTypography.current
}

private val WidgetColorProviers = colorProviders(
primary = ColorProvider(LightColorScheme.primary, DarkColorScheme.primary),
onPrimary = ColorProvider(LightColorScheme.onPrimary, DarkColorScheme.onPrimary),
primaryContainer = ColorProvider(
LightColorScheme.primaryContainer,
DarkColorScheme.primaryContainer
),
onPrimaryContainer = ColorProvider(
LightColorScheme.onPrimaryContainer,
DarkColorScheme.onPrimaryContainer
),
inversePrimary = ColorProvider(LightColorScheme.inversePrimary, DarkColorScheme.inversePrimary),
secondary = ColorProvider(LightColorScheme.secondary, DarkColorScheme.secondary),
onSecondary = ColorProvider(LightColorScheme.onSecondary, DarkColorScheme.onSecondary),
secondaryContainer = ColorProvider(
LightColorScheme.secondaryContainer,
DarkColorScheme.secondaryContainer
),
onSecondaryContainer = ColorProvider(
LightColorScheme.onSecondaryContainer,
DarkColorScheme.onSecondaryContainer
),
tertiary = ColorProvider(LightColorScheme.tertiary, DarkColorScheme.tertiary),
onTertiary = ColorProvider(LightColorScheme.onTertiary, DarkColorScheme.onTertiary),
tertiaryContainer = ColorProvider(
LightColorScheme.tertiaryContainer,
DarkColorScheme.tertiaryContainer
),
onTertiaryContainer = ColorProvider(
LightColorScheme.onTertiaryContainer,
DarkColorScheme.onTertiaryContainer
),
error = ColorProvider(LightColorScheme.error, DarkColorScheme.error),
onError = ColorProvider(LightColorScheme.onError, DarkColorScheme.onError),
errorContainer = ColorProvider(LightColorScheme.errorContainer, DarkColorScheme.errorContainer),
onErrorContainer = ColorProvider(
LightColorScheme.onErrorContainer,
DarkColorScheme.onErrorContainer
),
surface = ColorProvider(LightColorScheme.surface, DarkColorScheme.surface),
onSurface = ColorProvider(LightColorScheme.onSurface, DarkColorScheme.onSurface),
inverseSurface = ColorProvider(LightColorScheme.inverseSurface, DarkColorScheme.inverseSurface),
inverseOnSurface = ColorProvider(
LightColorScheme.inverseOnSurface,
DarkColorScheme.inverseOnSurface
),
outline = ColorProvider(LightColorScheme.outline, DarkColorScheme.outline),
background = ColorProvider(LightColorScheme.background, DarkColorScheme.background),
onBackground = ColorProvider(LightColorScheme.onBackground, DarkColorScheme.onBackground),
surfaceVariant = ColorProvider(LightColorScheme.surfaceVariant, DarkColorScheme.surfaceVariant),
onSurfaceVariant = ColorProvider(
LightColorScheme.onSurfaceVariant,
DarkColorScheme.onSurfaceVariant
)
)

@Composable
fun KnightsGlanceTheme(
content: @Composable () -> Unit,
) {
GlanceTheme(
colors = WidgetColorProviers,
content = content
)
}
2 changes: 2 additions & 0 deletions feature/main/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ dependencies {
implementation(projects.feature.session)
implementation(projects.feature.bookmark)

implementation(projects.widget)

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.activity.compose)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,45 @@ import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.core.view.WindowCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.droidknights.app2023.widget.DroidKnightsWidget.Companion.KEY_SESSION_ID
import com.droidknights.app2023.core.designsystem.theme.KnightsTheme
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.MutableStateFlow

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
private val sessionIdFromWidget: MutableStateFlow<String?> = MutableStateFlow(null)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

intent.getStringExtra(KEY_SESSION_ID)?.let {
sessionIdFromWidget.value = it
intent.removeExtra(KEY_SESSION_ID)
}

WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
val isDarkTheme by viewModel.isDarkTheme.collectAsStateWithLifecycle(false, this)

val navigator: MainNavigator = rememberMainNavigator()
val sessionId = sessionIdFromWidget.collectAsStateWithLifecycle().value

LaunchedEffect(sessionId) {
sessionId?.let {
navigator.navigateSessionDetail(it)
}
}

KnightsTheme(darkTheme = isDarkTheme) {
MainScreen(
navigator = navigator,
onChangeDarkTheme = { isDarkTheme -> viewModel.updateIsDarkTheme(isDarkTheme) }
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package com.droidknights.app2023.feature.main

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.droidknights.app2023.core.data.repository.SettingsRepository
import com.droidknights.app2023.widget.sendWidgetUpdateCommand
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class MainViewModel @Inject constructor(
private val application: Application,
private val settingsRepository: SettingsRepository,
) : ViewModel() {
val isDarkTheme = settingsRepository.getIsDarkTheme()

init {
sendWidgetUpdateCommand(application)
}

fun updateIsDarkTheme(isDarkTheme: Boolean) = viewModelScope.launch {
settingsRepository.updateIsDarkTheme(isDarkTheme)
}
Expand Down
1 change: 1 addition & 0 deletions feature/session/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ android {

dependencies {
implementation(libs.kotlinx.immutable)
implementation(projects.widget)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
Expand All @@ -50,6 +51,7 @@ import com.droidknights.app2023.core.model.Room
import com.droidknights.app2023.core.model.Session
import com.droidknights.app2023.core.model.Speaker
import com.droidknights.app2023.core.model.Tag
import com.droidknights.app2023.widget.sendWidgetUpdateCommand
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.delay
Expand All @@ -64,6 +66,14 @@ internal fun SessionDetailScreen(
val scrollState = rememberScrollState()
val sessionUiState by viewModel.sessionUiState.collectAsStateWithLifecycle()
val effect by viewModel.sessionUiEffect.collectAsStateWithLifecycle()

val context = LocalContext.current

LaunchedEffect(effect) {
if (effect is SessionDetailEffect.ShowToastForBookmarkState) {
sendWidgetUpdateCommand(context)
}
}
Column(
modifier = Modifier
.fillMaxSize()
Expand Down
9 changes: 8 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ androidxDatastore = "1.0.0"
ossLicenses = "17.0.1"
ossLicensesPlugin = "0.10.6"

androidxGlance = "1.0.0-beta01"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glance Library 추가 (targetSDK 버전 제한으로 beta01 버전 적용)

베타를 적용함으로써 이 작업에서 처음 의도한 것과 달리 기능을 모두 드러내지 못한 부분이 있었나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의도했던 부분을 드러내지 못한 것은 없습니다.
실제 제가 개발하고 운영중인 서비스에도 beta01 버전이 적용되어 있습니다.

glanceExperimentalTools = "0.2.2"

[libraries]
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" }
Expand Down Expand Up @@ -83,7 +86,7 @@ landscapist-coil = { group = "com.github.skydoves", name = "landscapist-coil" }
landscapist-placeholder = { group = "com.github.skydoves", name = "landscapist-placeholder" }
landscapist-animation = { group = "com.github.skydoves", name = "landscapist-animation" }

compose-shimmer = { group = "com.valentinilk.shimmer", name = "compose-shimmer", version.ref = "composeShimmer"}
compose-shimmer = { group = "com.valentinilk.shimmer", name = "compose-shimmer", version.ref = "composeShimmer" }

junit4 = { group = "junit", name = "junit", version.ref = "junit4" }
junit-vintage-engine = { group = "org.junit.vintage", name = "junit-vintage-engine", version.ref = "junitVintageEngine" }
Expand All @@ -110,6 +113,10 @@ verify-detektPlugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plug
androidx-datastore = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidxDatastore" }
oss-licenses-plugin = { group = "com.google.android.gms", name = "oss-licenses-plugin", version.ref = "ossLicensesPlugin" }

androidx-glance = { group = "androidx.glance", name = "glance", version.ref = "androidxGlance" }
androidx-glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "androidxGlance" }
glance-tools-appwidget-host = { group = "com.google.android.glance.tools", name = "appwidget-host", version.ref = "glanceExperimentalTools"}

[bundles]

[plugins]
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ include(
":feature:setting",
":feature:contributor",
":feature:bookmark",

":widget"
)
1 change: 1 addition & 0 deletions widget/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
19 changes: 19 additions & 0 deletions widget/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
plugins {
id("droidknights.android.library")
id("droidknights.android.compose")
}

android {
namespace = "com.droidknights.app2023.widget"
}

dependencies {
implementation(libs.androidx.glance)
implementation(libs.androidx.glance.appwidget)
implementation(libs.glance.tools.appwidget.host)

implementation(projects.core.designsystem)

implementation(projects.core.domain)
implementation(project(mapOf("path" to ":core:model")))
}
19 changes: 19 additions & 0 deletions widget/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application tools:targetApi="31">

<receiver
android:name=".DroidKnightsWidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>

</application>

</manifest>
24 changes: 24 additions & 0 deletions widget/src/main/kotlin/com/droidknights/app2023/widget/Action.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.droidknights.app2023.widget

import android.content.Context
import android.content.Intent
import androidx.glance.action.Action
import androidx.glance.appwidget.action.actionStartActivity

internal fun actionStartActivityWithSessionId(context: Context, sessionId: String): Action =
actionStartActivity(
Intent(
context.packageManager.getLaunchIntentForPackage(
context.packageName
)
).putExtra(DroidKnightsWidget.KEY_SESSION_ID, sessionId)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
)

internal fun actionLaunchIntentForPackage(context: Context): Action = actionStartActivity(
Intent(
context.packageManager.getLaunchIntentForPackage(
context.packageName
)
)
)
16 changes: 16 additions & 0 deletions widget/src/main/kotlin/com/droidknights/app2023/widget/Command.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.droidknights.app2023.widget

import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent

fun sendWidgetUpdateCommand(context: Context) {
context.sendBroadcast(
Intent(
context,
DroidKnightsWidgetReceiver::class.java
).setAction(
AppWidgetManager.ACTION_APPWIDGET_UPDATE
)
)
}
Loading