diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 209bffdc6..be5ea1dbc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { implementation(project(":features:login")) implementation(project(":features:search")) implementation(project(":features:series")) + implementation(project(":features:serieswidget")) implementation(project(":features:settings")) implementation(project(":libraries:core")) implementation(project(":libraries:database")) @@ -89,6 +90,7 @@ dependencies { implementation(libs.androidx.constraintlayout) implementation(libs.androidx.core) implementation(libs.androidx.fragment) + implementation(libs.androidx.glance.appwidget) implementation(libs.androidx.hilt.work) implementation(libs.androidx.lifecycle.extensions) implementation(libs.androidx.lifecycle.livedata) diff --git a/app/src/main/java/com/chesire/nekome/App.kt b/app/src/main/java/com/chesire/nekome/App.kt index 9fa9c27b3..5022b74db 100644 --- a/app/src/main/java/com/chesire/nekome/App.kt +++ b/app/src/main/java/com/chesire/nekome/App.kt @@ -7,9 +7,13 @@ import androidx.work.Configuration import com.chesire.lifecyklelog.LifecykleLog import com.chesire.lifecyklelog.LogHandler import com.chesire.nekome.core.preferences.ApplicationPreferences +import com.chesire.nekome.services.DataRefreshNotifier import com.chesire.nekome.services.WorkerQueue import dagger.hilt.android.HiltAndroidApp import javax.inject.Inject +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import timber.log.Timber /** @@ -27,6 +31,10 @@ class App : Application(), Configuration.Provider { @Inject lateinit var workerQueue: WorkerQueue + @Inject + lateinit var dataRefreshNotifier: DataRefreshNotifier + + @OptIn(DelicateCoroutinesApi::class) override fun onCreate() { super.onCreate() @@ -46,6 +54,9 @@ class App : Application(), Configuration.Provider { workerQueue.enqueueAuthRefresh() workerQueue.enqueueSeriesRefresh() workerQueue.enqueueUserRefresh() + GlobalScope.launch { + dataRefreshNotifier.initialize() + } } override fun getWorkManagerConfiguration() = diff --git a/app/src/main/java/com/chesire/nekome/services/DataRefreshNotifier.kt b/app/src/main/java/com/chesire/nekome/services/DataRefreshNotifier.kt new file mode 100644 index 000000000..856f73de3 --- /dev/null +++ b/app/src/main/java/com/chesire/nekome/services/DataRefreshNotifier.kt @@ -0,0 +1,35 @@ +package com.chesire.nekome.services + +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import com.chesire.nekome.datasource.series.SeriesRepository +import javax.inject.Inject +import javax.inject.Singleton + +private const val WIDGET_DATA_NOTIFY_TAG = "WidgetData" +private const val WIDGET_DATA_UNIQUE_NAME = "WidgetSync" + +@Singleton +class DataRefreshNotifier @Inject constructor( + private val workManager: WorkManager, + private val seriesRepository: SeriesRepository +) { + + /** + * Initialize the notifier and listen to any data updates. + */ + suspend fun initialize() { + seriesRepository.getSeries().collect { + val request = OneTimeWorkRequestBuilder() + .addTag(WIDGET_DATA_NOTIFY_TAG) + .build() + + workManager.enqueueUniqueWork( + WIDGET_DATA_UNIQUE_NAME, + ExistingWorkPolicy.REPLACE, + request + ) + } + } +} diff --git a/app/src/main/java/com/chesire/nekome/services/WidgetDataWorker.kt b/app/src/main/java/com/chesire/nekome/services/WidgetDataWorker.kt new file mode 100644 index 000000000..bac4987bd --- /dev/null +++ b/app/src/main/java/com/chesire/nekome/services/WidgetDataWorker.kt @@ -0,0 +1,18 @@ +package com.chesire.nekome.services + +import android.content.Context +import androidx.glance.appwidget.updateAll +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import com.chesire.nekome.feature.serieswidget.ui.SeriesWidget + +class WidgetDataWorker( + private val context: Context, + params: WorkerParameters +) : CoroutineWorker(context, params) { + + override suspend fun doWork(): Result { + SeriesWidget().updateAll(context) + return Result.success() + } +} diff --git a/core/compose/src/main/java/com/chesire/nekome/core/compose/theme/Color.kt b/core/compose/src/main/java/com/chesire/nekome/core/compose/theme/Color.kt index d55e759c3..708744e89 100644 --- a/core/compose/src/main/java/com/chesire/nekome/core/compose/theme/Color.kt +++ b/core/compose/src/main/java/com/chesire/nekome/core/compose/theme/Color.kt @@ -4,7 +4,7 @@ import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.ui.graphics.Color -internal val DarkColorPalette = darkColorScheme( +val DarkColorPalette = darkColorScheme( primary = Color(0xFF65d3ff), onPrimary = Color(0xFF003546), primaryContainer = Color(0xFF004d64), @@ -30,7 +30,7 @@ internal val DarkColorPalette = darkColorScheme( onSurfaceVariant = Color(0xFFc0c8cd) ) -internal val LightColorPalette = lightColorScheme( +val LightColorPalette = lightColorScheme( primary = Color(0xFF006783), onPrimary = Color(0xFFffffff), primaryContainer = Color(0xFFbde9ff), diff --git a/core/resources/src/main/res/values-ja/strings.xml b/core/resources/src/main/res/values-ja/strings.xml index ea7aa4c99..5c71b05b9 100644 --- a/core/resources/src/main/res/values-ja/strings.xml +++ b/core/resources/src/main/res/values-ja/strings.xml @@ -81,6 +81,9 @@ シリーズ%sの更新に失敗しました。再試行してください デリート + アニメ一覧 + +1 + 評価なし Kitsu eメール diff --git a/core/resources/src/main/res/values/strings.xml b/core/resources/src/main/res/values/strings.xml index b5274ca70..c2bd00f80 100644 --- a/core/resources/src/main/res/values/strings.xml +++ b/core/resources/src/main/res/values/strings.xml @@ -81,6 +81,9 @@ Failed to update series %s, please try again Delete + Anime list + +1 + No rating Kitsu email diff --git a/features/serieswidget/.gitignore b/features/serieswidget/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/features/serieswidget/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/features/serieswidget/build.gradle.kts b/features/serieswidget/build.gradle.kts new file mode 100644 index 000000000..bd56bcdfc --- /dev/null +++ b/features/serieswidget/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.google.dagger.hilt.android) + alias(libs.plugins.google.devtools.ksp) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "com.chesire.nekome.feature.serieswidget" + compileSdk = libs.versions.sdk.get().toInt() + + defaultConfig { + minSdk = 21 + + consumerProguardFiles("consumer-rules.pro") + } + buildFeatures { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() + } +} + +dependencies { + implementation(project(":core:compose")) + implementation(project(":core:preferences")) + implementation(project(":core:resources")) + implementation(project(":libraries:core")) + implementation(project(":libraries:datasource:series")) + + implementation(libs.androidx.glance.appwidget) + implementation(libs.androidx.glance.material3) + implementation(libs.bundles.compose) + implementation(libs.google.hilt.android) + implementation(libs.kotlin.result) + implementation(libs.timber) + debugImplementation(libs.androidx.compose.ui.tooling) + ksp(libs.google.hilt.android.compiler) +} diff --git a/features/serieswidget/consumer-rules.pro b/features/serieswidget/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/features/serieswidget/src/main/AndroidManifest.xml b/features/serieswidget/src/main/AndroidManifest.xml new file mode 100644 index 000000000..42cdec11f --- /dev/null +++ b/features/serieswidget/src/main/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/GlanceDataReceiver.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/GlanceDataReceiver.kt new file mode 100644 index 000000000..a93a2370f --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/GlanceDataReceiver.kt @@ -0,0 +1,10 @@ +package com.chesire.nekome.feature.serieswidget + +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.GlanceAppWidgetReceiver +import com.chesire.nekome.feature.serieswidget.ui.SeriesWidget + +class GlanceDataReceiver : GlanceAppWidgetReceiver() { + override val glanceAppWidget: GlanceAppWidget + get() = SeriesWidget() +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/SeriesWidgetEntryPoint.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/SeriesWidgetEntryPoint.kt new file mode 100644 index 000000000..17ae7f809 --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/SeriesWidgetEntryPoint.kt @@ -0,0 +1,13 @@ +package com.chesire.nekome.feature.serieswidget + +import com.chesire.nekome.feature.serieswidget.ui.SeriesWidgetViewModel +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@EntryPoint +@InstallIn(SingletonComponent::class) +interface SeriesWidgetEntryPoint { + + fun seriesWidgetViewModel(): SeriesWidgetViewModel +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/core/RetrieveSeriesUseCase.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/core/RetrieveSeriesUseCase.kt new file mode 100644 index 000000000..5994493d0 --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/core/RetrieveSeriesUseCase.kt @@ -0,0 +1,39 @@ +package com.chesire.nekome.feature.serieswidget.core + +import com.chesire.nekome.core.flags.SeriesType +import com.chesire.nekome.core.flags.UserSeriesStatus +import com.chesire.nekome.core.preferences.SeriesPreferences +import com.chesire.nekome.core.preferences.flags.SortOption +import com.chesire.nekome.datasource.series.SeriesDomain +import com.chesire.nekome.datasource.series.SeriesRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map + +class RetrieveSeriesUseCase @Inject constructor( + private val seriesRepository: SeriesRepository, + private val pref: SeriesPreferences +) { + + suspend operator fun invoke(): Flow> { + val sortOption = pref.sort.first() + return seriesRepository + .getSeries() + .map { seriesList -> + seriesList + .filter { series -> series.type == SeriesType.Anime } + .filter { series -> series.userSeriesStatus == UserSeriesStatus.Current } + .filter { series -> series.totalLength == 0 || series.progress < series.totalLength } + .sortedWith( + when (sortOption) { + SortOption.Default -> compareBy { it.userId } + SortOption.Title -> compareBy { it.title } + SortOption.StartDate -> compareBy { it.startDate } + SortOption.EndDate -> compareBy { it.endDate } + SortOption.Rating -> compareBy { it.rating } + } + ) + } + } +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/core/UpdateSeriesUseCase.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/core/UpdateSeriesUseCase.kt new file mode 100644 index 000000000..8681fc4d7 --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/core/UpdateSeriesUseCase.kt @@ -0,0 +1,30 @@ +package com.chesire.nekome.feature.serieswidget.core + +import com.chesire.nekome.datasource.series.SeriesRepository +import com.github.michaelbull.result.Result +import com.github.michaelbull.result.mapEither +import javax.inject.Inject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class UpdateSeriesUseCase @Inject constructor( + private val seriesRepository: SeriesRepository +) { + + suspend operator fun invoke(seriesId: Int): Result { + val currentSeries = seriesRepository.getSeries(seriesId) + return withContext(Dispatchers.IO) { + seriesRepository + .updateSeries( + currentSeries.userId, + currentSeries.progress + 1, + currentSeries.userSeriesStatus, + currentSeries.rating + ) + .mapEither( + success = { Unit }, + failure = { Unit } + ) + } + } +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/DomainMapper.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/DomainMapper.kt new file mode 100644 index 000000000..d53853cf0 --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/DomainMapper.kt @@ -0,0 +1,21 @@ +package com.chesire.nekome.feature.serieswidget.ui + +import com.chesire.nekome.datasource.series.SeriesDomain +import javax.inject.Inject + +class DomainMapper @Inject constructor() { + + fun toSeries(domain: SeriesDomain): Series { + return Series( + userId = domain.userId, + title = domain.title, + progress = buildProgress(domain.progress, domain.totalLength), + isUpdating = false + ) + } + + private fun buildProgress(progress: Int, totalLength: Int): String { + val maxLengthString = if (totalLength == 0) "-" else totalLength + return "$progress / $maxLengthString" + } +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/SeriesWidget.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/SeriesWidget.kt new file mode 100644 index 000000000..a6c62a2f3 --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/SeriesWidget.kt @@ -0,0 +1,153 @@ +package com.chesire.nekome.feature.serieswidget.ui + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.unit.dp +import androidx.glance.Button +import androidx.glance.GlanceId +import androidx.glance.GlanceModifier +import androidx.glance.appwidget.CircularProgressIndicator +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.appWidgetBackground +import androidx.glance.appwidget.background +import androidx.glance.appwidget.cornerRadius +import androidx.glance.appwidget.lazy.LazyColumn +import androidx.glance.appwidget.lazy.items +import androidx.glance.appwidget.provideContent +import androidx.glance.color.ColorProvider +import androidx.glance.layout.Alignment +import androidx.glance.layout.Column +import androidx.glance.layout.Row +import androidx.glance.layout.Spacer +import androidx.glance.layout.fillMaxSize +import androidx.glance.layout.fillMaxWidth +import androidx.glance.layout.height +import androidx.glance.layout.padding +import androidx.glance.text.FontWeight +import androidx.glance.text.Text +import androidx.glance.text.TextStyle +import com.chesire.nekome.core.compose.theme.DarkColorPalette +import com.chesire.nekome.core.compose.theme.LightColorPalette +import com.chesire.nekome.feature.serieswidget.SeriesWidgetEntryPoint +import com.chesire.nekome.resources.StringResource +import dagger.hilt.EntryPoints + +class SeriesWidget : GlanceAppWidget() { + + override suspend fun provideGlance(context: Context, id: GlanceId) { + val viewModel = EntryPoints.get( + context, + SeriesWidgetEntryPoint::class.java + ).seriesWidgetViewModel() + + provideContent { + val state by viewModel.uiState.collectAsState() + Render( + state = state, + incrementText = context.getString(StringResource.series_widget_increment), + updateSeries = { viewModel.execute(ViewAction.UpdateSeries(it)) } + ) + } + } + + @Composable + private fun Render( + state: UIState, + incrementText: String, + updateSeries: (Int) -> Unit + ) { + LazyColumn( + modifier = GlanceModifier + .appWidgetBackground() + .background( + day = LightColorPalette.surface, + night = DarkColorPalette.surface + ) + .fillMaxSize() + .padding(8.dp) + ) { + items( + items = state.series, + itemId = { it.userId.toLong() } + ) { item -> + Column { + SeriesCard( + id = item.userId, + title = item.title, + progress = item.progress, + isUpdating = item.isUpdating, + incrementText = incrementText, + updateSeries = updateSeries + ) + Spacer(modifier = GlanceModifier.height(8.dp).fillMaxWidth()) + } + } + } + } + + @Suppress("LongParameterList") + @Composable + private fun SeriesCard( + id: Int, + title: String, + progress: String, + isUpdating: Boolean, + incrementText: String, + updateSeries: (Int) -> Unit + ) { + Row( + modifier = GlanceModifier.fillMaxWidth() + .background( + day = LightColorPalette.primaryContainer, + night = DarkColorPalette.primaryContainer + ) + .cornerRadius(8.dp) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column( + modifier = GlanceModifier + .defaultWeight() + .padding(end = 8.dp) + ) { + Text( + text = title, + style = TextStyle( + color = ColorProvider( + day = LightColorPalette.onPrimaryContainer, + night = DarkColorPalette.onPrimaryContainer + ), + fontWeight = FontWeight.Medium + ), + maxLines = 3 + ) + Text( + text = progress, + style = TextStyle( + color = ColorProvider( + day = LightColorPalette.onPrimaryContainer, + night = DarkColorPalette.onPrimaryContainer + ) + ) + ) + } + + if (isUpdating) { + CircularProgressIndicator( + color = ColorProvider( + day = LightColorPalette.onPrimaryContainer, + night = DarkColorPalette.onPrimaryContainer + ), + modifier = GlanceModifier.height(36.dp) + ) + } else { + Button( + text = incrementText, + onClick = { updateSeries(id) } + ) + } + } + } +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/SeriesWidgetViewModel.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/SeriesWidgetViewModel.kt new file mode 100644 index 000000000..9521ad5ac --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/SeriesWidgetViewModel.kt @@ -0,0 +1,68 @@ +package com.chesire.nekome.feature.serieswidget.ui + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.chesire.nekome.feature.serieswidget.core.RetrieveSeriesUseCase +import com.chesire.nekome.feature.serieswidget.core.UpdateSeriesUseCase +import com.github.michaelbull.result.onFailure +import com.github.michaelbull.result.onSuccess +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +class SeriesWidgetViewModel @Inject constructor( + private val retrieveSeries: RetrieveSeriesUseCase, + private val updateSeries: UpdateSeriesUseCase, + private val mapper: DomainMapper +) : ViewModel() { + + private val _uiState = MutableStateFlow(UIState()) + val uiState = _uiState.asStateFlow() + + init { + viewModelScope.launch { + retrieveSeries().collect { series -> + _uiState.update { + it.copy(series = series.map(mapper::toSeries)) + } + } + } + } + + fun execute(viewAction: ViewAction) { + when (viewAction) { + is ViewAction.UpdateSeries -> handleUpdateSeries(viewAction.id) + } + } + + private fun handleUpdateSeries(id: Int) { + _uiState.update { + it.copy(series = updateIsUpdating(id, true)) + } + viewModelScope.launch { + updateSeries(id) + .onSuccess { + _uiState.update { + it.copy(series = updateIsUpdating(id, false)) + } + } + .onFailure { + _uiState.update { + it.copy(series = updateIsUpdating(id, false)) + } + } + } + } + + private fun updateIsUpdating(id: Int, isUpdating: Boolean): List { + return _uiState.value.series.map { + if (it.userId == id) { + it.copy(isUpdating = isUpdating) + } else { + it + } + } + } +} diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/UIState.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/UIState.kt new file mode 100644 index 000000000..88ad7ca1e --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/UIState.kt @@ -0,0 +1,12 @@ +package com.chesire.nekome.feature.serieswidget.ui + +data class UIState( + val series: List = emptyList() +) + +data class Series( + val userId: Int, + val title: String, + val progress: String, + val isUpdating: Boolean +) diff --git a/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/ViewAction.kt b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/ViewAction.kt new file mode 100644 index 000000000..7c845d7d5 --- /dev/null +++ b/features/serieswidget/src/main/java/com/chesire/nekome/feature/serieswidget/ui/ViewAction.kt @@ -0,0 +1,6 @@ +package com.chesire.nekome.feature.serieswidget.ui + +sealed interface ViewAction { + + data class UpdateSeries(val id: Int) : ViewAction +} diff --git a/features/serieswidget/src/main/res/xml/series_widget_info.xml b/features/serieswidget/src/main/res/xml/series_widget_info.xml new file mode 100644 index 000000000..513db493e --- /dev/null +++ b/features/serieswidget/src/main/res/xml/series_widget_info.xml @@ -0,0 +1,9 @@ + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ad0c68649..413c6a5f6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ aboutlibraries = "10.9.1" accompanist = "0.32.0" android-gradle-plugin = "8.1.2" androidx-espresso = "3.5.1" +androidx-glance = "1.0.0" androidx-hilt = "1.0.0" androidx-navigation = "2.7.4" androidx-room = "2.5.2" @@ -38,6 +39,8 @@ androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayo androidx-core = { module = "androidx.core:core-ktx", version = "1.12.0" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version = "1.0.0" } androidx-fragment = { module = "androidx.fragment:fragment-ktx", version = "1.6.1" } +androidx-glance-appwidget = { module = "androidx.glance:glance-appwidget", version.ref = "androidx-glance" } +androidx-glance-material3 = { module = "androidx.glance:glance-material3", version.ref = "androidx-glance" } androidx-hilt-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "androidx-hilt" } androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version = "1.0.0" } androidx-hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "androidx-hilt" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 952962732..263cd4f53 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,6 +23,7 @@ include( ":features:login", ":features:search", ":features:series", + ":features:serieswidget", ":features:settings", ":libraries:core", ":libraries:database",