Created
January 3, 2024 15:31
-
-
Save ithustle/9a37b68be806de206090e258199870ec to your computer and use it in GitHub Desktop.
ToDo - Live 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Colors { | |
companion object { | |
val arrayColors = listOf( | |
Color(0xFF910101), | |
Color(0xFF0D0191), | |
Color(0xFF5D8238), | |
Color(0xFF000000), | |
Color(0xFFB47D3C), | |
Color(0xFF6D0D75), | |
Color(0xFF9C9C9C) | |
) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun DetailScreen( | |
viewModel: DetailViewModel, | |
onCreateTask: () -> Unit = {} | |
) { | |
val keyboardController = LocalSoftwareKeyboardController.current | |
val state by viewModel.uiState.collectAsState() | |
val categories = listOf( | |
"Negócios", | |
"Pessoal", | |
"Casa", | |
"Finanças", | |
"Saúde", | |
"Educação", | |
"Viagens", | |
"Projectos" | |
) | |
Scaffold( | |
floatingActionButton = { | |
FloatingActionButton( | |
onClick = onCreateTask, | |
shape = RoundedCornerShape(100.dp), | |
containerColor = MaterialTheme.colorScheme.primary | |
) { | |
Icon( | |
Icons.Default.Done, | |
contentDescription = "Add" | |
) | |
} | |
} | |
) { paddingValues -> | |
Column( | |
modifier = Modifier | |
.padding(paddingValues) | |
.fillMaxSize() | |
.background(color = MaterialTheme.colorScheme.background) | |
) { | |
Spacer(modifier = Modifier.size(30.dp)) | |
Text( | |
text = "Nova Tarefa", | |
fontSize = 32.sp, | |
fontWeight = FontWeight.SemiBold, | |
modifier = Modifier | |
.padding(horizontal = 16.dp) | |
) | |
Spacer(modifier = Modifier.size(30.dp)) | |
Text( | |
text = "Cor", | |
color = Color(0xFF676767), | |
modifier = Modifier | |
.padding(vertical = 8.dp, horizontal = 16.dp) | |
) | |
TextField( | |
value = state.descriptionTask, | |
onValueChange = { viewModel.updateDescription(it) }, | |
label = { | |
Text(text = "O que estás a planear?") | |
}, | |
modifier = Modifier | |
.fillMaxWidth() | |
.height(150.dp) | |
.padding(horizontal = 16.dp), | |
textStyle = TextStyle(color = Color.Black), | |
maxLines = 10 | |
) | |
Spacer(modifier = Modifier.size(16.dp)) | |
Text( | |
text = "Cor", | |
color = arrayColors[state.colorTask], | |
modifier = Modifier | |
.padding(vertical = 8.dp, horizontal = 16.dp) | |
) | |
Row( | |
horizontalArrangement = Arrangement.SpaceAround, | |
modifier = Modifier | |
.padding(horizontal = 16.dp) | |
.fillMaxWidth() | |
) { | |
arrayColors.forEachIndexed { index, color -> | |
TaskColorPicker( | |
color = color, | |
selected = state.colorTask | |
) { _ -> | |
viewModel.onColorTask(index) | |
keyboardController?.hide() | |
} | |
Spacer(modifier = Modifier.size(12.dp)) | |
} | |
} | |
Spacer(modifier = Modifier.size(16.dp)) | |
Text( | |
text = "Categorias", | |
color = Color(0xFF676767), | |
modifier = Modifier | |
.padding(vertical = 8.dp, horizontal = 16.dp) | |
) | |
LazyVerticalGrid( | |
columns = GridCells.Adaptive(minSize = 128.dp), | |
modifier = Modifier | |
.padding(horizontal = 16.dp) | |
) { | |
items(categories) { category -> | |
Column( | |
modifier = Modifier | |
.border(width = 0.5.dp, color = Color.LightGray) | |
.height(height = 72.dp) | |
.background(color = if (state.categoryTask == category) arrayColors[state.colorTask] else Color.White) | |
.clickable { | |
viewModel.onCategoryTask(category) | |
keyboardController?.hide() | |
}, | |
verticalArrangement = Arrangement.Center, | |
horizontalAlignment = Alignment.CenterHorizontally | |
) { | |
Text( | |
text = category, | |
color = if (state.categoryTask == category) Color.White else Color.Black | |
) | |
} | |
} | |
} | |
} | |
} | |
} | |
@Preview | |
@Composable | |
fun DetailScreenPrev() { | |
DetailScreen(viewModel = DetailViewModel(context = LocalContext.current)) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Criar somente quando precisar dele | |
data class DetailScreenUiState( | |
val descriptionTask: String = "", | |
val colorTask: Int = 0, | |
val categoryTask: String = "", | |
val stateTask: Boolean = false | |
) | |
class CreateTaskViewModel(context: Context): ViewModel() { | |
private var dao: TaskRepository = TaskRepository(context = context) | |
private val _uiState: MutableStateFlow<DetailScreenUiState> = MutableStateFlow(DetailScreenUiState()) | |
var uiState: StateFlow<DetailScreenUiState> = _uiState.asStateFlow() | |
fun updateDescription(description: String) { | |
_uiState.value = _uiState.value.copy(descriptionTask = description) | |
} | |
fun onColorTask(color: Int) { | |
_uiState.value = _uiState.value.copy(colorTask = color) | |
} | |
fun onCategoryTask(category: String) { | |
_uiState.value = _uiState.value.copy(categoryTask = category) | |
} | |
suspend fun handleSaveTask() { | |
val task = Task( | |
descriptionTask = _uiState.value.descriptionTask, | |
colorTask = _uiState.value.colorTask, | |
categoryTask = _uiState.value.categoryTask, | |
stateTask = _uiState.value.stateTask | |
) | |
dao.saveTask(task) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Database(entities = [Task::class], version = 1) | |
abstract class AppDatabase : RoomDatabase() { | |
abstract fun TaskDao(): TaskDao | |
} | |
@Dao | |
interface TaskDao { | |
@Insert | |
suspend fun saveTask(task: Task) | |
@Query("SELECT * FROM task") | |
fun getAllTasks(): Flow<List<Task>> | |
@Query("UPDATE task SET stateTask = :stateTask WHERE uid = :uid") | |
suspend fun updateTaskState(uid: UUID, stateTask: Boolean) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// O Scaffold deverá ser o último a ser adicionado | |
@Composable | |
fun DashboardScreen( | |
viewModel: DashboardModelView, | |
onNavigateToCreateTask: () -> Unit = {}, | |
onTaskDone: (UUID, Boolean) -> Unit = { _, _ -> } | |
) { | |
val isPreview = LocalInspectionMode.current | |
val state by viewModel.uiState.collectAsState() | |
val listOfTasks = if (isPreview) MockData.allTasks() else state.allTasks | |
Column( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(color = MaterialTheme.colorScheme.background) | |
) { | |
Scaffold( | |
floatingActionButton = { | |
FloatingActionButton( | |
onClick = onNavigateToCreateTask, | |
shape = RoundedCornerShape(100.dp), | |
containerColor = MaterialTheme.colorScheme.primary | |
) { | |
Icon( | |
Icons.Default.Add, | |
contentDescription = "Add" | |
) | |
} | |
} | |
) { paddingValues -> | |
Column( | |
modifier = Modifier | |
.padding(paddingValues) | |
.scrollable(state = rememberScrollState(), orientation = Orientation.Vertical), | |
) { | |
Spacer(modifier = Modifier.size(30.dp)) | |
Text( | |
text = "ToDo - Minhas Cenas", | |
fontSize = 32.sp, | |
fontWeight = FontWeight.SemiBold, | |
modifier = Modifier | |
.padding(horizontal = 16.dp) | |
) | |
// Quando chegares aqui, adiciona apenas o composable sem a condição e depois de tudo | |
// feito, cria a extensão - Está no final do gist | |
if (listOfTasks.isNotEmpty()) { | |
if (listOfTasks.allTasksNotDone().isNotEmpty()) { | |
TaskCardList( | |
sectionTitle = "Minhas Tarefas", | |
listOfTasks = listOfTasks.allTasksNotDone(), | |
onTaskDone = onTaskDone | |
) | |
} | |
if (listOfTasks.allTasksDone().isNotEmpty()) { | |
TaskCardList( | |
sectionTitle = "Finalizadas", | |
listOfTasks = listOfTasks.allTasksDone(), | |
onTaskDone = onTaskDone | |
) | |
} | |
} else { | |
Column( | |
modifier = Modifier | |
.fillMaxSize(), | |
verticalArrangement = Arrangement.Center, | |
horizontalAlignment = Alignment.CenterHorizontally | |
) { | |
Text( | |
text = "Nenhuma tarefa criada", | |
fontSize = 28.sp, | |
color = Color.Gray, | |
fontWeight = FontWeight.SemiBold, | |
modifier = Modifier | |
.padding(horizontal = 16.dp) | |
) | |
} | |
} | |
} | |
} | |
} | |
} | |
@Preview | |
@Composable | |
fun DashboardScreenPreview() { | |
DashboardScreen(viewModel = DashboardModelView(context = LocalContext.current)) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data class DashboardUiScreen( | |
val allTasks: List<Task> = emptyList() | |
) | |
class DashboardModelView(context: Context): ViewModel() { | |
private var dao: TaskRepository = TaskRepository(context = context) | |
private val _uiState: MutableStateFlow<DashboardUiScreen> = MutableStateFlow( | |
DashboardUiScreen() | |
) | |
var uiState: StateFlow<DashboardUiScreen> = _uiState.asStateFlow() | |
init { | |
viewModelScope.launch { | |
dao.getAllTasks().collect { listTasks -> | |
_uiState.update { | |
it.copy(allTasks = listTasks) | |
} | |
} | |
} | |
} | |
suspend fun markTaskAsDone(id: UUID, state: Boolean) { | |
dao.updateTask(id, state) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MockData { | |
companion object { | |
fun allTasks(): List<Task> { | |
return listOf( | |
Task( | |
descriptionTask = "Minha tarefa 1", | |
categoryTask = "Negócios", | |
colorTask = 2, | |
stateTask = false | |
), | |
Task( | |
descriptionTask = "Minha tarefa 2", | |
categoryTask = "Pessoal", | |
colorTask = 3, | |
stateTask = true | |
), | |
Task( | |
descriptionTask = "Minha tarefa 3", | |
categoryTask = "Negócios", | |
colorTask = 2, | |
stateTask = false | |
) | |
) | |
} | |
fun task(): Task { | |
return Task( | |
descriptionTask = "Minha tarefa 1", | |
categoryTask = "Negócios", | |
colorTask = 2, | |
stateTask = true | |
) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Entity | |
data class Task( | |
@PrimaryKey val uid: UUID = UUID.randomUUID(), | |
var descriptionTask: String, | |
var categoryTask: String, | |
var colorTask: Int, | |
var stateTask: Boolean | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun TaskCard( | |
task: Task, | |
modifier: Modifier | |
) { | |
Row( | |
modifier = modifier | |
.shadow( | |
elevation = 16.dp, | |
spotColor = Color(0x1A000000), | |
ambientColor = Color(0x1A000000) | |
) | |
.fillMaxWidth() | |
.background(color = Color.White, shape = RoundedCornerShape(size = 10.dp)) | |
.padding(all = 16.dp), | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
if (task.stateTask) { | |
Box( | |
modifier = Modifier | |
.size(32.dp) | |
.background( | |
color = Colors.arrayColors[task.colorTask], | |
shape = RoundedCornerShape(size = 24.dp) | |
) | |
) | |
} else { | |
Box( | |
modifier = Modifier | |
.size(32.dp) | |
.border( | |
width = 1.dp, | |
color = MaterialTheme.colorScheme.primary, | |
shape = RoundedCornerShape(size = 24.dp) | |
) | |
) | |
} | |
Spacer(modifier = Modifier.size(10.dp)) | |
Column { | |
Text( | |
text = task.descriptionTask, | |
fontSize = 16.sp, | |
textDecoration = if (task.stateTask) TextDecoration.LineThrough else TextDecoration.None, | |
fontWeight = FontWeight.SemiBold, | |
color = Color(0xFF676767) | |
) | |
Text( | |
text = task.categoryTask, | |
fontSize = 13.sp, | |
fontWeight = FontWeight.SemiBold, | |
color = Color.Gray | |
) | |
} | |
} | |
} | |
@Preview | |
@Composable | |
fun TaskCardPrev() { | |
TaskCard( | |
task = MockData.task(), | |
modifier = Modifier | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun TaskCardList( | |
sectionTitle: String, | |
listOfTasks: List<Task>, | |
onTaskDone: (UUID, Boolean) -> Unit | |
) { | |
Spacer(modifier = Modifier.size(30.dp)) | |
Text( | |
text = sectionTitle.uppercase(), | |
color = Color(0xFF676767), | |
modifier = Modifier | |
.padding(vertical = 8.dp, horizontal = 16.dp) | |
) | |
LazyColumn { | |
items(listOfTasks) { task -> | |
TaskCard( | |
task = task, | |
modifier = Modifier | |
.padding(vertical = 8.dp, horizontal = 16.dp) | |
.clickable { | |
onTaskDone(task.uid, !task.stateTask) | |
} | |
) | |
} | |
} | |
} | |
@Preview | |
@Composable | |
fun TaskCardListPrev() { | |
TaskCardList( | |
sectionTitle = "Minhas Tarefas", | |
listOfTasks = MockData.allTasks().allTasksNotDone(), | |
onTaskDone = { _, _ -> } | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun TaskColorPicker( | |
color: Color, | |
selected: Int, | |
onSelected: (Color) -> Unit = {} | |
) { | |
Box( | |
contentAlignment = Alignment.Center, | |
modifier = Modifier | |
.size(32.dp) | |
.background( | |
color = color, | |
shape = RoundedCornerShape(size = 32.dp) | |
) | |
.clickable { | |
onSelected(color) | |
} | |
) { | |
if (Colors.arrayColors[selected] == color) { | |
Icon( | |
Icons.Default.Check, | |
contentDescription = "Check", | |
tint = Color.White | |
) | |
} | |
} | |
} | |
@Preview | |
@Composable | |
fun TaskColorPickerPrev() { | |
TaskColorPicker(color = Color.Blue, selected = 1) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// extensão | |
fun List<Task>.allTasksDone(): List<Task> { | |
return this.filter { it.stateTask } | |
} | |
fun List<Task>.allTasksNotDone(): List<Task> { | |
return this.filter { !it.stateTask } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TaskRepository(val context: Context) { | |
private val db: AppDatabase by lazy { | |
Room.databaseBuilder( | |
context.applicationContext, | |
AppDatabase::class.java, "taskdb" | |
).build() | |
} | |
private val td = db.TaskDao() | |
suspend fun saveTask(task: Task) { | |
td.saveTask(task) | |
} | |
suspend fun updateTask(id: UUID, state: Boolean) { | |
td.updateTaskState(uid = id, stateTask = state) | |
} | |
fun getAllTasks(): Flow<List<Task>> { | |
return td.getAllTasks() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment