Skip to content
Open
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
3 changes: 2 additions & 1 deletion app/src/main/java/com/juandgaines/todoapp/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.juandgaines.todoapp.presentation.screens.detail.TaskScreen
import com.juandgaines.todoapp.presentation.screens.home.HomeScreenRoot
import com.juandgaines.todoapp.ui.theme.TodoAppTheme

Expand All @@ -13,7 +14,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge()
setContent {
TodoAppTheme() {
HomeScreenRoot()

}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
package com.juandgaines.todoapp.presentation.screens.detail

import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextAlign.Companion
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import com.juandgaines.todoapp.R
import com.juandgaines.todoapp.domain.Category
import com.juandgaines.todoapp.presentation.screens.detail.providers.TaskScreenStatePreviewProvider
import com.juandgaines.todoapp.ui.theme.TodoAppTheme

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TaskScreen(
modifier: Modifier = Modifier,
state: TaskScreenState
) {

var isDescriptionFocus by remember {
mutableStateOf(false)
}
var isExpanded by remember {
mutableStateOf(false)
}

Scaffold (
topBar = {
TopAppBar(
title = {
Text(
style = MaterialTheme.typography.headlineSmall,
text = stringResource(R.string.task)
)
}
)
}
){ padding->
Column (
verticalArrangement = Arrangement.spacedBy(
8.dp
),
modifier = Modifier
.fillMaxSize()
.padding(padding)
.padding(horizontal = 16.dp)
){
Row (
verticalAlignment = Alignment.CenterVertically
){
Text(
text = stringResource(R.string.done),
style = MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.onSurface
),
modifier = Modifier.padding(8.dp)
)
Checkbox(
checked = state.isTaskDone,
onCheckedChange = {

},
)
Spacer(
modifier = Modifier.weight(1f)
)

Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
isExpanded = true
}
){

Text(
text = state.category?.toString() ?: stringResource(R.string.category),
style = MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.onSurface
),
modifier = Modifier.border(
width = 1.dp,
color = MaterialTheme.colorScheme.outline,
shape = RoundedCornerShape(8.dp)
)
.padding(8.dp)
)
Box (
modifier = Modifier.padding(8.dp),
contentAlignment = Alignment.Center
){
Icon(
imageVector = Icons.Default.KeyboardArrowDown,
contentDescription = "Add Task",
tint = MaterialTheme.colorScheme.onSurface,
)
DropdownMenu(
modifier = Modifier.background(
color = MaterialTheme.colorScheme.surfaceContainerHighest
),
expanded = isExpanded,
onDismissRequest = { isExpanded = false }
) {
Column {
Category.entries.forEach { category ->
Text(
text = category.name,
style = MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.onSurface
),
modifier = Modifier.padding(8.dp).padding(
8.dp
).clickable {

}
)
}
}
}
}
}


}

BasicTextField(
value = state.taskName,
textStyle = MaterialTheme.typography.headlineLarge.copy(
color = MaterialTheme.colorScheme.onSurface,
fontWeight = FontWeight.Bold
),
maxLines = 1,
onValueChange = {

},
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
,
decorationBox = { innerBox ->
Column (
modifier = Modifier.fillMaxWidth(),
){
if(state.taskName.isEmpty()){
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.task_name),
color = MaterialTheme.colorScheme.onSurface.copy(
alpha = 0.5f
),
style = MaterialTheme.typography.headlineLarge.copy(
fontWeight = FontWeight.Bold
)
)
}
else{
innerBox()
}
}
}
)
BasicTextField(
value = state.taskDescription ?: "",
textStyle = MaterialTheme.typography.bodyLarge.copy(
color = MaterialTheme.colorScheme.onSurface
),
maxLines = 15,
onValueChange = {

},
modifier = Modifier
.fillMaxWidth()
.onFocusChanged {
isDescriptionFocus = it.isFocused
}
,
decorationBox = { innerBox ->
Column {
if(state.taskDescription.isNullOrEmpty() && !isDescriptionFocus){
Text(
text = stringResource(R.string.task_description),
color = MaterialTheme.colorScheme.onSurface.copy(
alpha = 0.5f
)
)
}else{
innerBox()
}
}
}
)
Spacer(
modifier = Modifier.weight(1f)
)
Button(
onClick = { },
modifier = Modifier.fillMaxWidth()
.padding(46.dp)
){
Text(
text = stringResource(R.string.save),
style = MaterialTheme.typography.titleMedium.copy(
color = MaterialTheme.colorScheme.onPrimary
)
)
}
}
}
}

@Composable
@Preview
fun TaskScreenLightPreview(
@PreviewParameter(TaskScreenStatePreviewProvider::class) state: TaskScreenState
){
TodoAppTheme {
TaskScreen(
state = state
)
}
}

@Composable
@Preview(
uiMode = UI_MODE_NIGHT_YES
)
fun TaskScreenDarkPreview(
@PreviewParameter(TaskScreenStatePreviewProvider::class) state: TaskScreenState
){
TodoAppTheme {
TaskScreen(
state = state
)
}
}


data class TaskScreenState(
val taskName: String = "",
val taskDescription: String? = null,
val category:Category? = null,
val isTaskDone : Boolean = false,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.juandgaines.todoapp.presentation.screens.detail.providers

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.juandgaines.todoapp.domain.Category.OTHER
import com.juandgaines.todoapp.domain.Category.WORK
import com.juandgaines.todoapp.presentation.screens.detail.TaskScreenState

class TaskScreenStatePreviewProvider:PreviewParameterProvider<TaskScreenState> {
override val values: Sequence<TaskScreenState>
get() = sequenceOf(
TaskScreenState(
taskName = "Task 1",
taskDescription = "Description 1",
isTaskDone = false,
category = WORK
),
TaskScreenState(
taskName = "Task 2",
taskDescription = "Description 2",
isTaskDone = true,
category = WORK
),
TaskScreenState(
taskName = "Task 3",
taskDescription = "Description 3",
isTaskDone = false,
category = OTHER
),
TaskScreenState(
taskName = "Task 4",
taskDescription = "Description 4",
isTaskDone = true,
category = null
),
TaskScreenState(
taskName = "Task 5",
taskDescription = null,
isTaskDone = false,
category = null
)
)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.juandgaines.todoapp.presentation.screens.home

import android.icu.text.DateFormat
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.juandgaines.todoapp.data.FakeTaskLocalDataSource
import com.juandgaines.todoapp.presentation.screens.home.HomeScreenAction.OnAddTask
import com.juandgaines.todoapp.presentation.screens.home.HomeScreenAction.OnDeleteAllTasks
import com.juandgaines.todoapp.presentation.screens.home.HomeScreenAction.OnDeleteTask
import com.juandgaines.todoapp.presentation.screens.home.HomeScreenAction.OnToggleTask
Expand All @@ -17,7 +15,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

class HomeScreenViewModel:ViewModel() {
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@
<string name="all_task_deleted">All tasked deleted</string>
<string name="task_updated">Task updated</string>
<string name="summary">You have %s pending task</string>
<string name="task_name">Task name</string>
<string name="task_description">Task description</string>
<string name="task">Task</string>
<string name="done">Completed:</string>
<string name="category">Category</string>
<string name="save">Save</string>
</resources>