Skip to content

Commit

Permalink
Onboarding, daily notification and more (#141)
Browse files Browse the repository at this point in the history
* Disable move undone tasks by default

* Add daily reminder notification

* Add onboarding feature
  • Loading branch information
costular authored Oct 28, 2024
1 parent 8c81c3a commit 5244ee2
Show file tree
Hide file tree
Showing 94 changed files with 2,415 additions and 160 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ dependencies {
implementation(projects.common.tasks)
implementation(projects.feature.postponeTask)
implementation(projects.feature.detail)
implementation(projects.feature.onboarding)

implementation(libs.compose.activity)
implementation(libs.compose.ui)
Expand Down
2 changes: 1 addition & 1 deletion app/config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ exceptions:
active: true
ignoreLabeled: false
SwallowedException:
active: true
active: false
ignoredExceptionTypes:
- 'InterruptedException'
- 'MalformedURLException'
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/costular/atomtasks/ui/MainGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import com.ramcosta.composedestinations.annotation.ExternalNavGraph
import com.ramcosta.composedestinations.annotation.NavHostGraph
import com.ramcosta.composedestinations.generated.agenda.navgraphs.AgendaNavGraph
import com.ramcosta.composedestinations.generated.detail.navgraphs.TaskDetailNavGraph
import com.ramcosta.composedestinations.generated.onboarding.navgraphs.OnboardingNavGraph
import com.ramcosta.composedestinations.generated.settings.navgraphs.SettingsNavGraph

@NavHostGraph
annotation class MainGraph {
@ExternalNavGraph<SettingsNavGraph>
@ExternalNavGraph<TaskDetailNavGraph>()
@ExternalNavGraph<OnboardingNavGraph>()
@ExternalNavGraph<AgendaNavGraph>(start = true)
companion object Includes
}
21 changes: 20 additions & 1 deletion app/src/main/java/com/costular/atomtasks/ui/home/AppNavigator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package com.costular.atomtasks.ui.home

import androidx.navigation.NavController
import com.costular.atomtasks.agenda.ui.AgendaNavigator
import com.costular.atomtasks.feature.onboarding.OnboardingNavigator
import com.costular.atomtasks.settings.SettingsNavigator
import com.ramcosta.composedestinations.generated.agenda.destinations.AgendaScreenDestination
import com.ramcosta.composedestinations.generated.agenda.destinations.TasksActionsBottomSheetDestination
import com.ramcosta.composedestinations.generated.detail.destinations.TaskDetailScreenDestination
import com.ramcosta.composedestinations.generated.onboarding.navgraphs.OnboardingNavGraph
import com.ramcosta.composedestinations.generated.settings.destinations.ThemeSelectorScreenDestination
import com.ramcosta.composedestinations.utils.toDestinationsNavigator
import java.time.LocalDate

class AppNavigator(
private val navController: NavController,
) : SettingsNavigator, AgendaNavigator {
) : SettingsNavigator, AgendaNavigator, OnboardingNavigator {

private val destinationsNavigator by lazy {
navController.toDestinationsNavigator()
Expand Down Expand Up @@ -39,11 +42,27 @@ class AppNavigator(
destinationsNavigator.navigate(TasksActionsBottomSheetDestination(taskId, taskName, isDone))
}

override fun navigateToOnboarding() {
destinationsNavigator.navigate(OnboardingNavGraph) {
popUpTo(OnboardingNavGraph) {
inclusive = true
}
}
}

override fun navigateUp() {
destinationsNavigator.navigateUp()
}

override fun navigateToSelectTheme(theme: String) {
destinationsNavigator.navigate(ThemeSelectorScreenDestination(theme))
}

override fun navigateToAgenda() {
destinationsNavigator.navigate(AgendaScreenDestination) {
popUpTo(AgendaScreenDestination) {
inclusive = true
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class AndroidHiltConventionPlugin : Plugin<Project> {
dependencies {
"implementation"(libs.findLibrary("hilt").get())
"ksp"(libs.findLibrary("hilt.compiler").get())
"ksp"(libs.findLibrary("hilt.ext.compiler").get())
"kspAndroidTest"(libs.findLibrary("hilt.compiler").get())
"kspTest"(libs.findLibrary("hilt.compiler").get())
}
Expand Down
1 change: 0 additions & 1 deletion common/tasks/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ dependencies {
implementation(libs.accompanist.permissions)
implementation(libs.room.ktx)
ksp(libs.room.compiler)
ksp(libs.hilt.ext.compiler)
api(libs.reordeable)

testImplementation(projects.common.tasks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ internal class DefaultTasksLocalDataSource @Inject constructor(
reminderDao.insertReminder(reminder)
}

override suspend fun getTasksCount(): Int {
return tasksDao.getTaskCount()
}

override fun getTasks(day: LocalDate?): Flow<List<TaskAggregated>> {
return if (day != null) {
tasksDao.getAllTasksForDate(day).distinctUntilChanged()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ internal class DefaultTasksRepository @Inject constructor(
return taskId
}

override suspend fun getTaskCount(): Int {
return localDataSource.getTasksCount()
}

override fun getTaskById(id: Long): Flow<Task> {
return localDataSource.getTaskById(id).map { it.toDomain() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface TaskLocalDataSource {
reminderEnabled: Boolean,
taskId: Long,
)

suspend fun getTasksCount(): Int
fun getTasks(day: LocalDate? = null): Flow<List<TaskAggregated>>
fun getTaskById(id: Long): Flow<TaskAggregated>
suspend fun removeTask(taskId: Long, recurringRemovalStrategy: RecurringRemovalStrategy?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface TasksRepository {
recurrenceType: RecurrenceType?,
parentId: Long?,
): Long

suspend fun getTaskCount(): Int
fun getTaskById(id: Long): Flow<Task>
fun getTasks(day: LocalDate? = null): Flow<List<Task>>
suspend fun removeTask(taskId: Long, recurringRemovalStrategy: RecurringRemovalStrategy?)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.costular.designsystem.components

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import com.costular.designsystem.theme.AppTheme
import com.costular.designsystem.theme.AtomTheme

@Composable
fun OutlinedButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = ButtonDefaults.outlinedShape,
border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
elevation: ButtonElevation? = null,
contentPadding: PaddingValues = PaddingValues(AppTheme.dimens.spacingLarge),
content: @Composable RowScope.() -> Unit,
) {
androidx.compose.material3.OutlinedButton(
onClick,
modifier = modifier,
enabled = enabled,
border = border,
shape = shape,
interactionSource = interactionSource,
elevation = elevation,
colors = colors,
contentPadding = contentPadding,
content = content,
)
}

@Preview
@Composable
private fun OutlinedButtonPreview() {
AtomTheme {
OutlinedButton(onClick = {}) {
Text("Click me!")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import com.costular.designsystem.theme.AppTheme
import com.costular.designsystem.theme.AtomTheme
Expand All @@ -21,25 +22,28 @@ fun PrimaryButton(
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = ButtonDefaults.shape,
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
colors: ButtonColors = ButtonDefaults.buttonColors(),
contentPadding: PaddingValues = PaddingValues(AppTheme.dimens.spacingLarge),
content: @Composable RowScope.() -> Unit,
) {
Button(
onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
interactionSource = interactionSource,
elevation = elevation,
colors = colors,
contentPadding = PaddingValues(AppTheme.dimens.spacingLarge),
contentPadding = contentPadding,
content = content,
)
}

@Preview
@Composable
fun PrimaryButtonPrev() {
private fun PrimaryButtonPreview() {
AtomTheme {
PrimaryButton(onClick = {}) {
Text("Click me!")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.costular.designsystem.components

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import com.costular.designsystem.theme.AppTheme
import com.costular.designsystem.theme.AtomTheme

@Composable
fun SecondaryButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = ButtonDefaults.filledTonalShape,
colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
elevation: ButtonElevation? = ButtonDefaults.filledTonalButtonElevation(),
contentPadding: PaddingValues = PaddingValues(AppTheme.dimens.spacingLarge),
content: @Composable RowScope.() -> Unit,
) {
FilledTonalButton(
onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
interactionSource = interactionSource,
elevation = elevation,
colors = colors,
contentPadding = contentPadding,
content = content,
)
}

@Preview
@Composable
private fun SecondaryButtonPreview() {
AtomTheme {
SecondaryButton(onClick = {}) {
Text("Click me!")
}
}
}
1 change: 1 addition & 0 deletions core/locale/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
13 changes: 13 additions & 0 deletions core/locale/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
id("atomtasks.android.library")
id("atomtasks.detekt")
id("atomtasks.android.hilt")
}

android {
namespace = "com.costular.atomtasks.core.locale"
}

dependencies {

}
Empty file added core/locale/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions core/locale/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions core/locale/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.costular.atomtasks.core.locale

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@InstallIn(SingletonComponent::class)
@Module
internal interface LocaleModule {
@Binds
fun bindLocaleResolver(impl: LocaleResolverImpl): LocaleResolver
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.costular.atomtasks.core.locale

import java.util.Locale

interface LocaleResolver {
fun getLocale(): Locale
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.costular.atomtasks.core.locale

import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import java.util.Locale
import javax.inject.Inject

internal class LocaleResolverImpl @Inject constructor(
@ApplicationContext private val context: Context,
) : LocaleResolver {
override fun getLocale(): Locale {
return context.resources.configuration.locales[0]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.costular.atomtasks.notifications

interface DailyReminderNotificationManager {
fun showDailyReminderNotification()
fun removeDailyReminderNotification()
}
Loading

0 comments on commit 5244ee2

Please sign in to comment.