diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 6538bfe..bee7c8d 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -24,9 +24,16 @@ jobs: run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build - - name: Build Debug APK + # Create APK Debug + - name: Build apk debug project (APK) run: ./gradlew assembleDebug - - name: Create APK directory - run: mkdir -p apk - - name: Copy APK to directory - run: cp app/build/outputs/apk/debug/*.apk apk/ + # Create an artifacts folder if it doesn't exist, and move APK into it + - name: Move APK to artifacts folder + run: | + mkdir -p ${{ github.workspace }}/artifacts/ + mv ${{ env.main_project_module }}/build/outputs/apk/debug/* ${{ github.workspace }}/artifacts/ + - name: Upload APK Debug - ${{ env.repository_name }} + uses: actions/upload-artifact@v3 + with: + name: Tasky_debug + path: ${{ github.workspace }}/artifacts/ diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 5a2d133..0c0c338 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,17 +1,10 @@ - - - - - - - - - - - - + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index ae388c2..0897082 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,16 +4,15 @@ diff --git a/app/build.gradle b/app/build.gradle index f2b11eb..f9c3735 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.thatsmanmeet.taskyapp" minSdk 26 targetSdk 34 - versionCode 25 - versionName "2.4.1" + versionCode 26 + versionName "2.4.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true @@ -71,7 +71,7 @@ dependencies { androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" - def room_version = "2.6.0" + def room_version = "2.6.1" implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" implementation "androidx.compose.runtime:runtime-livedata:1.5.4" diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/ActionDialogBox.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/ActionDialogBox.kt index a588d7e..86bebf3 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/components/ActionDialogBox.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/ActionDialogBox.kt @@ -26,7 +26,6 @@ fun ActionDialogBox( if(isDialogShowing.value){ AlertDialog( onDismissRequest = { - onDismissClick() isDialogShowing.value = false }, confirmButton = { diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/AddTodoDialog.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/AddTodoDialog.kt index 271c85c..3c16d29 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/components/AddTodoDialog.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/AddTodoDialog.kt @@ -163,7 +163,7 @@ fun addTodoDialog( }, confirmButton = { Button(onClick = { - if (enteredText1.isNotEmpty() && descriptionText.isNotEmpty()){ + if (enteredText1.isNotEmpty()){ val todo = Todo( ID = null, title = enteredText1, @@ -216,7 +216,7 @@ fun addTodoDialog( isRepeating = false } else{ - Toast.makeText(context,"Fill in all fields",Toast.LENGTH_SHORT).show() + Toast.makeText(context,"Task name is required.",Toast.LENGTH_SHORT).show() } } ) { diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/DeletedTodoItem.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/DeletedTodoItem.kt new file mode 100644 index 0000000..eae1862 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/DeletedTodoItem.kt @@ -0,0 +1,103 @@ +package com.thatsmanmeet.taskyapp.components + +import android.content.Context +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.thatsmanmeet.taskyapp.room.Todo +import com.thatsmanmeet.taskyapp.room.TodoViewModel +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodo +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodoViewModel +import com.thatsmanmeet.taskyapp.screens.currentDateTimeComparator +import com.thatsmanmeet.taskyapp.screens.scheduleNotification + + +@Composable +fun DeletedTodoItem( + deletedTodo: DeletedTodo, + todoViewModel: TodoViewModel, + deletedTodoViewModel: DeletedTodoViewModel, + context:Context = LocalContext.current, + modifier: Modifier = Modifier +) { + val isShowing = remember { + mutableStateOf(false) + } + Row( + modifier = modifier + .fillMaxWidth() + .padding(10.dp) + .heightIn(60.dp) + .clip(RoundedCornerShape(10.dp)) + .clickable { + isShowing.value = true + } + .background(MaterialTheme.colorScheme.inverseOnSurface), + verticalAlignment = Alignment.CenterVertically + ) { + Box(modifier = modifier + .fillMaxWidth() + .padding(10.dp)){ + Text( + text = deletedTodo.title!!, + fontSize = 20.sp, + textDecoration = if(deletedTodo.isCompleted) TextDecoration.LineThrough else TextDecoration.None + ) + } + } + if(isShowing.value){ + ActionDialogBox( + isDialogShowing = isShowing, + title = "Choose Action", + message = "Do you want to restore or delete this task?", + confirmButtonText = "Restore" , + dismissButtonText = "Delete", + onConfirmClick = { + val newTodo = Todo( + ID = deletedTodo.ID, + title = deletedTodo.title, + todoDescription = deletedTodo.todoDescription, + isCompleted = deletedTodo.isCompleted, + date = deletedTodo.date, + time = deletedTodo.time, + notificationID = deletedTodo.notificationID, + isRecurring = deletedTodo.isRecurring + ) + todoViewModel.insertTodo(newTodo) + if(newTodo.time!!.isNotEmpty()){ + currentDateTimeComparator(inputDate = newTodo.date!!, inputTime = newTodo.time!!) { + scheduleNotification( + context = context, + titleText = newTodo.title!!, + messageText = newTodo.todoDescription!!, + time = "${newTodo.date} ${newTodo.time}", + todo = newTodo + ) + } + } + deletedTodoViewModel.deleteDeletedTodo(deletedTodo) + }, + onDismissClick = { + deletedTodoViewModel.deleteDeletedTodo(deletedTodo) + }, + + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskList.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskList.kt index 03b8611..3f0d1b3 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskList.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/components/TaskList.kt @@ -26,6 +26,7 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SwipeToDismiss import androidx.compose.material3.rememberDismissState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.movableContentOf import androidx.compose.runtime.mutableStateOf @@ -40,6 +41,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import com.thatsmanmeet.taskyapp.room.Todo import com.thatsmanmeet.taskyapp.room.TodoViewModel +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodo +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodoViewModel import com.thatsmanmeet.taskyapp.screens.CurrentDateTimeComparator import com.thatsmanmeet.taskyapp.screens.cancelNotification import com.thatsmanmeet.taskyapp.screens.scheduleNotification @@ -56,6 +59,7 @@ fun TaskList( state: LazyListState, list : List, todoViewModel: TodoViewModel, + deletedTodoViewModel: DeletedTodoViewModel, onClick : (Int) -> Unit, searchText: String, coroutineScope: CoroutineScope, @@ -96,39 +100,37 @@ fun TaskList( if(dismissState.isDismissed(direction = DismissDirection.EndToStart)){ isSwipeDeleteDialogShowing.value = true - ActionDialogBox( - isDialogShowing = isSwipeDeleteDialogShowing, - title = "Delete Task?", - message = "Do you want to delete this task?", - confirmButtonText = "Delete", - dismissButtonText = "Cancel", - onConfirmClick = { - todoViewModel.deleteTodo(currentItem) - }, - onDismissClick = { - isSwipeDeleteDialogShowing.value = false - coroutineScope.launch { - dismissState.reset() - } - }, - confirmButtonColor = Color(0xFFF75F5F), - confirmButtonContentColor = Color.White - ) -// LaunchedEffect(Unit){ -// val result = snackbarHostState.showSnackbar( -// message = "Task will be deleted soon!", -// actionLabel = "Undo", -// duration = SnackbarDuration.Short -// ) -// when(result){ -// SnackbarResult.Dismissed -> { -// todoViewModel.deleteTodo(currentItem) -// } -// SnackbarResult.ActionPerformed -> { + deletedTodoViewModel.insertDeletedTodo(DeletedTodo( + ID = currentItem.ID, + title = currentItem.title, + todoDescription = currentItem.todoDescription, + isCompleted = currentItem.isCompleted, + date = currentItem.date, + time = currentItem.time, + isRecurring = currentItem.isRecurring, + notificationID = currentItem.notificationID, + todoDeletionDate = getDate30DaysLater(currentItem.date!!) + )) + todoViewModel.deleteTodo(currentItem) + cancelNotification(context,currentItem) +// ActionDialogBox( +// isDialogShowing = isSwipeDeleteDialogShowing, +// title = "Delete Task?", +// message = "Do you want to delete this task?", +// confirmButtonText = "Delete", +// dismissButtonText = "Cancel", +// onConfirmClick = { +// todoViewModel.deleteTodo(currentItem) +// }, +// onDismissClick = { +// isSwipeDeleteDialogShowing.value = false +// coroutineScope.launch { // dismissState.reset() // } -// } -// } +// }, +// confirmButtonColor = Color(0xFFF75F5F), +// confirmButtonContentColor = Color.White +// ) } if(dismissState.isDismissed(direction = DismissDirection.StartToEnd)){ @@ -214,4 +216,13 @@ fun TaskList( } } } +} + +fun getDate30DaysLater(enteredDate:String):String{ + val sdf = SimpleDateFormat("dd/MM/yyyy",Locale.getDefault()) + val date = sdf.parse(enteredDate) + val calendar = Calendar.getInstance() + calendar.time = date!! + calendar.add(Calendar.DAY_OF_MONTH,30) + return sdf.format(calendar.time) } \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/receiver/RepeatingTasksReceiver.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/receiver/RepeatingTasksReceiver.kt index 5627e8d..f5f7393 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/receiver/RepeatingTasksReceiver.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/receiver/RepeatingTasksReceiver.kt @@ -10,6 +10,7 @@ import androidx.room.Room import com.thatsmanmeet.taskyapp.constants.Constants import com.thatsmanmeet.taskyapp.room.Todo import com.thatsmanmeet.taskyapp.room.TodoDatabase +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodoDatabase import com.thatsmanmeet.taskyapp.screens.scheduleNotification import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -28,6 +29,11 @@ class RepeatingTasksReceiver : BroadcastReceiver() { TodoDatabase::class.java, "todo_database" ).build() + val deletedTodoDatabase = Room.databaseBuilder( + context!!.applicationContext, + DeletedTodoDatabase::class.java, + "deleted_todo_database" + ).build() coroutineScope.launch { withTimeout(10000) { todoDatabase.todoDao().getAllTodosFlow().collect{todos-> @@ -60,6 +66,21 @@ class RepeatingTasksReceiver : BroadcastReceiver() { } } } + coroutineScope.launch { + withTimeout(10000){ + deletedTodoDatabase.deletedTodoDao().getAllTodosFlow().collect{deletedTodos-> + val currentDate = + SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format( + Date() + ) + for(todo in deletedTodos){ + if(currentDate == todo.todoDeletionDate){ + deletedTodoDatabase.deletedTodoDao().deleteTodo(todo) + } + } + } + } + } val nextAlarmIntent = Intent(context.applicationContext,RepeatingTasksReceiver::class.java).also { it.action = "repeating_tasks" } diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/room/TodoRepository.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/room/TodoRepository.kt index ab30b89..287accc 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/room/TodoRepository.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/room/TodoRepository.kt @@ -18,5 +18,4 @@ class TodoRepository(private val todoDao: TodoDao) { } fun getAllTodosFlow() : Flow> = todoDao.getAllTodosFlow() - } \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodo.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodo.kt new file mode 100644 index 0000000..9ea0471 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodo.kt @@ -0,0 +1,19 @@ +package com.thatsmanmeet.taskyapp.room.deletedtodo + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "deleted_todo_table") +data class DeletedTodo( + @PrimaryKey(autoGenerate = true) var ID:Long? = null, + @ColumnInfo(name = "title") var title:String? = "", + @ColumnInfo(name = "completed") var isCompleted:Boolean = false, + @ColumnInfo(name = "date") var date:String? = "", + @ColumnInfo(name = "time") var time:String? = "", + @ColumnInfo(name = "notificationID", defaultValue = "0") var notificationID:Int = 0, + @ColumnInfo(name = "is_Recurring", defaultValue = "false") var isRecurring : Boolean = false, + @ColumnInfo(name = "description", defaultValue = "") var todoDescription : String? = "", + @ColumnInfo(name = "deletionDate", defaultValue = "") var todoDeletionDate: String ? = "" +) + diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoDao.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoDao.kt new file mode 100644 index 0000000..2dbae53 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoDao.kt @@ -0,0 +1,30 @@ +package com.thatsmanmeet.taskyapp.room.deletedtodo + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import kotlinx.coroutines.flow.Flow + +@Dao +interface DeletedTodoDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun addTodo(todo: DeletedTodo) + + @Update(onConflict = OnConflictStrategy.REPLACE) + suspend fun updateTodo(todo: DeletedTodo) + + @Delete + suspend fun deleteTodo(todo: DeletedTodo) + + @Query("SELECT * FROM deleted_todo_table ORDER BY ID ASC") + fun getAllTodos() : LiveData> + + @Query("SELECT * FROM deleted_todo_table ORDER BY ID ASC") + fun getAllTodosFlow() : Flow> + +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoDatabase.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoDatabase.kt new file mode 100644 index 0000000..110f076 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoDatabase.kt @@ -0,0 +1,35 @@ +package com.thatsmanmeet.taskyapp.room.deletedtodo + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database( + entities = [DeletedTodo::class], + version = 1 +) +abstract class DeletedTodoDatabase : RoomDatabase() { + + abstract fun deletedTodoDao(): DeletedTodoDao + + companion object{ + @Volatile + private var INSTANCE : DeletedTodoDatabase? = null + + fun getInstance(context: Context): DeletedTodoDatabase{ + synchronized(this){ + var instance = INSTANCE + if(instance == null){ + instance = Room.databaseBuilder( + context.applicationContext, + DeletedTodoDatabase::class.java, + "deleted_todo_database" + ).allowMainThreadQueries().build() + INSTANCE = instance + } + return instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoRepository.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoRepository.kt new file mode 100644 index 0000000..70905f3 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoRepository.kt @@ -0,0 +1,20 @@ +package com.thatsmanmeet.taskyapp.room.deletedtodo + + +import kotlinx.coroutines.flow.Flow + +class DeletedTodoRepository(private val deletedTodoDao: DeletedTodoDao) { + suspend fun insertTodo(todo: DeletedTodo){ + deletedTodoDao.addTodo(todo) + } + + suspend fun updateTodo(todo: DeletedTodo){ + deletedTodoDao.updateTodo(todo) + } + + suspend fun deleteTodo(todo: DeletedTodo){ + deletedTodoDao.deleteTodo(todo) + } + + fun getAllTodosFlow() : Flow> = deletedTodoDao.getAllTodosFlow() +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoViewModel.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoViewModel.kt new file mode 100644 index 0000000..5898d3e --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/room/deletedtodo/DeletedTodoViewModel.kt @@ -0,0 +1,31 @@ +package com.thatsmanmeet.taskyapp.room.deletedtodo + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch + +class DeletedTodoViewModel(application: Application) : ViewModel() { + + private var repository:DeletedTodoRepository + val getAllDeletedTodos: Flow> + + init { + val dao = DeletedTodoDatabase.getInstance(application).deletedTodoDao() + repository = DeletedTodoRepository(dao) + getAllDeletedTodos = repository.getAllTodosFlow() + } + + fun insertDeletedTodo(deletedTodo: DeletedTodo){ + viewModelScope.launch { + repository.insertTodo(deletedTodo) + } + } + fun deleteDeletedTodo(deletedTodo: DeletedTodo){ + viewModelScope.launch { + repository.deleteTodo(deletedTodo) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt index aff9679..1df4a1d 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/App.kt @@ -19,9 +19,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import com.thatsmanmeet.taskyapp.BuildConfig import com.thatsmanmeet.taskyapp.R import com.thatsmanmeet.taskyapp.components.OpenEditTodoDialog import com.thatsmanmeet.taskyapp.components.SearchBarTop @@ -35,9 +38,11 @@ import com.thatsmanmeet.taskyapp.notification.channelID import com.thatsmanmeet.taskyapp.receiver.RepeatingTasksReceiver import com.thatsmanmeet.taskyapp.room.Todo import com.thatsmanmeet.taskyapp.room.TodoViewModel +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodoViewModel import com.thatsmanmeet.taskyapp.ui.theme.TaskyTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.* @@ -51,6 +56,7 @@ fun MyApp( val activity = LocalContext.current as Activity val context = LocalContext.current val todoViewModel = TodoViewModel(activity.application) + val deletedTodoViewModel = DeletedTodoViewModel(activity.application) val listState = rememberLazyListState() val selectedItem = rememberSaveable { mutableIntStateOf(-1) @@ -96,6 +102,10 @@ fun MyApp( SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + + val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) + createNotificationChannel(context.applicationContext) // setup settings store val settingsStore = SettingsStore(context) @@ -108,138 +118,198 @@ fun MyApp( else -> {true} } ) { - Scaffold( - snackbarHost = {SnackbarHost(hostState = snackBarHostState)}, - topBar = { - TopAppBar( - title = { - Row( - modifier = modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Text( - text = stringResource(id = R.string.app_name), - fontSize = 25.sp - ) - SearchBarTop(searchText) { searchText = it } - Spacer(modifier = modifier.width(0.dp)) + ModalNavigationDrawer( + drawerState = drawerState, + gesturesEnabled = true, + drawerContent = { + ModalDrawerSheet { + Row( + modifier = modifier.fillMaxWidth().padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text("Tasky") + Text(text = "V${BuildConfig.VERSION_NAME}") + } + HorizontalDivider() + NavigationDrawerItem( + modifier = modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp), + icon = { Icon(imageVector = Icons.Default.Delete, contentDescription = null)}, + label = { Text(text = "Deleted Tasks") }, + selected = false, + onClick = { + coroutineScope.launch { + drawerState.close() + } + navHostController.navigate(route = Screen.DeletedTodosScreen.route) + } + ) + NavigationDrawerItem( + modifier = modifier.padding(start = 16.dp, end = 16.dp), + icon = { Icon(imageVector = Icons.Default.Info, contentDescription = null)}, + label = { Text(text = "Guide") }, + selected = false, + onClick = { + coroutineScope.launch { + drawerState.close() + } + navHostController.navigate(route = Screen.GuideScreen.route) + } + ) + NavigationDrawerItem( + modifier = modifier.padding(bottom = 16.dp,start = 16.dp, end = 16.dp), + icon = { Icon(imageVector = Icons.Default.Settings, contentDescription = null)}, + label = { Text(text = "Settings") }, + selected = false, + onClick = { + coroutineScope.launch { + drawerState.close() + } + navHostController.navigate(route = Screen.SettingsScreen.route) + } + ) + } + } + ) { + Scaffold( + snackbarHost = {SnackbarHost(hostState = snackBarHostState)}, + topBar = { + TopAppBar( + navigationIcon = { IconButton(onClick = { - // Implement Navigation to settings - navHostController.navigate(route = Screen.SettingsScreen.route) - }) { - Icon( - imageVector = Icons.Default.Settings, - contentDescription = null + coroutineScope.launch { + drawerState.apply { + if(isClosed) open() else close() + } + } + }) { + Icon( + imageVector = Icons.Default.Menu, + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimary + ) + } + }, + title = { + Row( + modifier = modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = stringResource(id = R.string.app_name), + fontSize = 25.sp ) + SearchBarTop(searchText) { searchText = it } } - } - }, - colors = topAppBarColors.topAppBarColors( - containerColor = MaterialTheme.colorScheme.primary, - titleContentColor = MaterialTheme.colorScheme.onPrimary + }, + colors = topAppBarColors.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary + ) ) + }, + floatingActionButton = { + ExtendedFloatingActionButton( + text = { Text(text = stringResource(R.string.add_task_button)) }, + icon = { Icon(painter = painterResource(id = R.drawable.ic_add_task), contentDescription = null) }, + onClick = { + openDialog.value = true + }, + expanded = listState.isScrollingUp() + ) + } + ) { paddingValues -> + enteredText = addTodoDialog( + openDialog, + enteredText, + descriptionText, + dateText, + isDateDialogShowing, + context, + timeText, + isTimeDialogShowing, + todoViewModel, + isRepeatingState.value ) - }, - floatingActionButton = { - ExtendedFloatingActionButton( - text = { Text(text = stringResource(R.string.add_task_button)) }, - icon = { Icon(painter = painterResource(id = R.drawable.ic_add_task), contentDescription = null) }, - onClick = { - openDialog.value = true - }, - expanded = listState.isScrollingUp() - ) - } - ) { paddingValues -> - enteredText = addTodoDialog( - openDialog, - enteredText, - descriptionText, - dateText, - isDateDialogShowing, - context, - timeText, - isTimeDialogShowing, - todoViewModel, - isRepeatingState.value - ) - Surface( - modifier = modifier - .fillMaxSize() - .padding(paddingValues), - color = MaterialTheme.colorScheme.background - ) { - if(todoListFromFlow.isEmpty()){ - Box(modifier = modifier + Surface( + modifier = modifier .fillMaxSize() .padding(paddingValues), - contentAlignment = Alignment.Center) { - Column( - modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Icon( - modifier = modifier - .size(50.dp) - .alpha(0.8f), - imageVector = Icons.Filled.Check, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary - ) - Text( - text = stringResource(R.string.empty_list_no_tasks_text), - fontSize = 30.sp, - color = MaterialTheme.colorScheme.primary, - fontWeight = FontWeight.Light - ) + color = MaterialTheme.colorScheme.background + ) { + if(todoListFromFlow.isEmpty()){ + Box(modifier = modifier + .fillMaxSize() + .padding(paddingValues), + contentAlignment = Alignment.Center) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Icon( + modifier = modifier + .size(50.dp) + .alpha(0.8f), + imageVector = Icons.Filled.Check, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary + ) + Text( + text = stringResource(R.string.empty_list_no_tasks_text), + fontSize = 30.sp, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Light + ) + } } + }else { + TaskList( + state = listState, + list = todoListFromFlow, + todoViewModel = todoViewModel, + deletedTodoViewModel = deletedTodoViewModel, + onClick = {index-> + selectedItem.intValue = index + openEditDialog.value = true + }, + searchText = searchText, + coroutineScope = rememberCoroutineScope(), + snackbarHostState = snackBarHostState + ) + } + if (openEditDialog.value){ + OpenEditTodoDialog( + todoListFromFlow, + selectedItem, + openEditDialog, + todoViewModel, + enteredText, + todoListFromFlow[selectedItem.intValue].todoDescription!!, + context + ) } - }else { - TaskList( - state = listState, - list = todoListFromFlow, - todoViewModel = todoViewModel, - onClick = {index-> - selectedItem.intValue = index - openEditDialog.value = true - }, - searchText = searchText, - coroutineScope = rememberCoroutineScope(), - snackbarHostState = snackBarHostState - ) - } - if (openEditDialog.value){ - OpenEditTodoDialog( - todoListFromFlow, - selectedItem, - openEditDialog, - todoViewModel, - enteredText, - todoListFromFlow[selectedItem.intValue].todoDescription!!, - context - ) } + } + if(todoViewModel.isAnimationPlayingState.value && (savedAnimationKey.value == true || savedAnimationKey.value == null)){ + Column(modifier = modifier.fillMaxSize()) { + TaskCompleteAnimations( + isLottiePlaying = isLottiePlaying, + modifier = modifier.fillMaxSize() + ) + LaunchedEffect(Unit){ + delay(2200) + withContext(Dispatchers.Main){ + todoViewModel.isAnimationPlayingState.value = false + } - } - if(todoViewModel.isAnimationPlayingState.value && (savedAnimationKey.value == true || savedAnimationKey.value == null)){ - Column(modifier = modifier.fillMaxSize()) { - TaskCompleteAnimations( - isLottiePlaying = isLottiePlaying, - modifier = modifier.fillMaxSize() - ) - LaunchedEffect(Unit){ - delay(2200) - withContext(Dispatchers.Main){ - todoViewModel.isAnimationPlayingState.value = false } - } } } - } + } } @@ -251,8 +321,6 @@ fun createNotificationChannel(context: Context){ channel.description = desc channel.enableLights(true) channel.enableVibration(true) -// val attributes = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT).build() -// channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/raw/notifications"),attributes) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if(notificationManager.getNotificationChannel("Reminder Channel") != null){ notificationManager.deleteNotificationChannel("Reminder Channel") @@ -371,3 +439,36 @@ fun CurrentDateTimeComparator( onTruePerform() } } + + +fun currentDateTimeComparator( + inputDate:String, + inputTime:String, + onTruePerform: () -> Unit +) { + val calendarInstance = Calendar.getInstance() + val currentDate = calendarInstance.apply { + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + } + val format = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()) + val parsedDate = format.parse(inputDate) + val calendar = calendarInstance.apply { + time = parsedDate!! + set(Calendar.HOUR_OF_DAY, inputTime.substringBefore(":").toInt()) + set(Calendar.MINUTE, inputTime.substringAfter(":").toInt()) + set(Calendar.SECOND, 0) + } + val currentTime = Calendar.getInstance().timeInMillis + if(calendar >= currentDate && calendar.timeInMillis >= currentTime){ + onTruePerform() + } +} + + +@Preview +@Composable +fun DisplayAppScreen() { + MyApp(navHostController = rememberNavController()) +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/DeletedTodoScreen.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/DeletedTodoScreen.kt new file mode 100644 index 0000000..c8c7753 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/DeletedTodoScreen.kt @@ -0,0 +1,118 @@ +package com.thatsmanmeet.taskyapp.screens + +import android.app.Activity +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults.topAppBarColors +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import com.thatsmanmeet.taskyapp.components.DeletedTodoItem +import com.thatsmanmeet.taskyapp.datastore.SettingsStore +import com.thatsmanmeet.taskyapp.room.TodoViewModel +import com.thatsmanmeet.taskyapp.room.deletedtodo.DeletedTodoViewModel +import com.thatsmanmeet.taskyapp.ui.theme.TaskyTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DeletedTodoScreen( + navHostController: NavHostController, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + val activity = context as Activity + val settingStore = SettingsStore(context) + val savedThemeKey = settingStore.getThemeModeKey.collectAsState(initial = "") + val deletedTodoViewModel = DeletedTodoViewModel(activity.application) + val todoViewModel = TodoViewModel(activity.application) + val deletedTodoList = deletedTodoViewModel.getAllDeletedTodos.collectAsState(initial = emptyList()) + + TaskyTheme(darkTheme = when (savedThemeKey.value) { + "0" -> { + isSystemInDarkTheme() + } + "1" -> {false} + else -> {true} + }) { + Scaffold( + modifier = modifier.fillMaxSize(), + topBar = { + TopAppBar( + title = { + Text(text = "Deleted Tasks") + }, navigationIcon = { + IconButton(onClick = { + navHostController.navigate(route = Screen.MyApp.route){ + popUpTo(route = Screen.MyApp.route){ + inclusive = true + } + } + }) { + Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Arrow back", tint = MaterialTheme.colorScheme.onPrimary) + } + }, + colors = topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + ) {paddingValues -> + Column( + modifier = modifier.padding(paddingValues), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = modifier + .fillMaxWidth() + .height(100.dp) + .padding(16.dp) + ){ + Text(text = "Deleted Tasks will be automatically deleted in 30 days. Tap on a task to restore or permanently delete it.", fontSize = 15.sp) + } + LazyColumn{ + items(deletedTodoList.value){deletedTodo-> + DeletedTodoItem( + deletedTodo = deletedTodo, + todoViewModel = todoViewModel, + deletedTodoViewModel = deletedTodoViewModel + ) + Spacer(modifier = modifier.height(5.dp)) + } + + } + } + } + } + +} + +@Preview +@Composable +fun PreviewDeletedTodoScreen() { + DeletedTodoScreen(rememberNavController()) +} \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/GuideScreen.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/GuideScreen.kt new file mode 100644 index 0000000..85ba1d1 --- /dev/null +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/GuideScreen.kt @@ -0,0 +1,161 @@ +package com.thatsmanmeet.taskyapp.screens + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import com.thatsmanmeet.taskyapp.datastore.SettingsStore +import com.thatsmanmeet.taskyapp.ui.theme.TaskyTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun GuideScreen( + navHostController: NavHostController, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + val settingStore = SettingsStore(context) + val savedThemeKey = settingStore.getThemeModeKey.collectAsState(initial = "") + val height = 12.dp + TaskyTheme( + darkTheme = when (savedThemeKey.value) { + "0" -> { + isSystemInDarkTheme() + } + "1" -> {false} + else -> {true} + } + ) { + Scaffold( + topBar = { + TopAppBar( + title = { Text(text = "Guide") }, + navigationIcon = { + IconButton(onClick = { + navHostController.navigate(route = Screen.MyApp.route){ + popUpTo(route = Screen.MyApp.route){ + inclusive = true + } + } + }) { + Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary + ) + ) + } + ) {paddingValues -> + Column( + modifier = modifier + .verticalScroll(rememberScrollState()) + .fillMaxSize() + .padding(paddingValues) + .padding(16.dp) + ) { + Text( + text = "Welcome to Tasky, a free and open source, minimal and aesthetic task management app. This guide will provide you with everything you can do in this app.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "1. On very first start, you will be greeted with a permission screen (if your android version is 13 or above). Here the app will ask for notification permission that is required to provide you with notifications on time.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "2. You will be on the task screen. Here the navigation bar have 3 things (menu icon, app name and search icon). On the screen you have a add tasks button and an empty list.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "3. You can click on add task and an dialog will open where you have to enter task name (description is optional). You can set date and time of the task and can set if the notification should be repeated daily or not just like a routine habit tracker. You can save task by clicking Add button. Notification will display on set date (everyday if repeating option is checked)/time and notification will contain tasks title and description.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "4. You will see the task added on the screen. You can tap on the task and an edit dialog will open where you can edit or delete the task.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "5. You can also swipe an individual task. Swiping left to right on task will mark task as complete/uncompleted and swiping from right to left will delete the task and will add it to trash.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "6. On top you can see a search icon. You can click on it and search for a task. This will search both task and description of all the tasks.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "7. On top you can see a search icon. You can click on it and search for a task. This will search both task and description of all the tasks.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "8. On Clicking Menu button a navigation drawer will open and contains app name and version code. It contains three items (Deleted Tasks, Guide and Settings).", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "9. On Deleted Tasks Screen you can see all the tasks you deleted. You can only tap on the item to either delete them permanently or restore them. You cannot edit them. Also if they are completed they have line-through the text. ", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "10. Guide button will bring you to this guide. ", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "11. Settings button will take you to settings screen where you can tweak various settings. ", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + Spacer(modifier = modifier.height(height)) + Text( + text = "12. In Settings screen, you can set app theme, can enable/disable confetti animations on task complete, can enable/disable task completion sounds, switch to 12/24 hour clock, backup/restore tasks locally and enable autostart.", + fontSize = 16.sp, + textAlign = TextAlign.Justify + ) + } + } + } + } diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/NavGraph.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/NavGraph.kt index 19fdddc..24fad38 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/NavGraph.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/NavGraph.kt @@ -49,5 +49,13 @@ fun SetupNavGraph( ){ MyApp(navHostController = navController) } + + composable(route = Screen.DeletedTodosScreen.route){ + DeletedTodoScreen(navHostController = navController) + } + + composable(route = Screen.GuideScreen.route){ + GuideScreen(navHostController = navController) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/Screen.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/Screen.kt index b887282..cd2357a 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/Screen.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/Screen.kt @@ -5,4 +5,7 @@ sealed class Screen(val route:String){ object PermissionScreen: Screen("permission_screen") object SettingsScreen : Screen("settings_screen") object SearchScreen: Screen("search_screen") + object DeletedTodosScreen:Screen("deleted_todo_screen") + + object GuideScreen:Screen("guide_screen") } diff --git a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt index bdf5efb..6bafcb8 100644 --- a/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt +++ b/app/src/main/java/com/thatsmanmeet/taskyapp/screens/SettingsScreen.kt @@ -23,6 +23,7 @@ import androidx.core.net.toUri import androidx.navigation.NavHostController import com.thatsmanmeet.taskyapp.MainActivity import com.thatsmanmeet.taskyapp.R +import com.thatsmanmeet.taskyapp.components.ActionDialogBox import com.thatsmanmeet.taskyapp.components.SettingsComponent import com.thatsmanmeet.taskyapp.components.ThemeChangerDialog import com.thatsmanmeet.taskyapp.datastore.SettingsStore @@ -46,9 +47,6 @@ fun SettingsScreen( val scope = rememberCoroutineScope() val settingStore = SettingsStore(context) val savedThemeKey = settingStore.getThemeModeKey.collectAsState(initial = "") - val isCheckedState = remember { - mutableStateOf(isChecked.value) - } val shouldShowAnimationState = remember { mutableStateOf(shouldShowAnimation.value) } @@ -58,7 +56,7 @@ fun SettingsScreen( val is24HourClockState = remember { mutableStateOf(is24HourClockKey.value) } - var isDialogShowingState by rememberSaveable { + val isBackupDialogShowingState = rememberSaveable { mutableStateOf(false) } val isThemeChangerShowing = rememberSaveable { @@ -245,7 +243,7 @@ fun SettingsScreen( settingText = stringResource(id = R.string.settings_backup_restore_information_text), painterResourceID = R.drawable.ic_history ) { - isDialogShowingState = true + isBackupDialogShowingState.value = true } // Visit Github Card SettingsComponent( @@ -257,34 +255,19 @@ fun SettingsScreen( } } } - if(isDialogShowingState){ - AlertDialog( - onDismissRequest = { - isDialogShowingState = false - }, - title = { - Text(text = stringResource(R.string.settings_backup_restore)) - }, - text = { - Text(text = stringResource(R.string.settings_backup_restore_information_text)) - }, - confirmButton = { - OutlinedButton(onClick = { + if(isBackupDialogShowingState.value){ + ActionDialogBox( + isDialogShowing = isBackupDialogShowingState, + title = stringResource(id = R.string.settings_backup_restore) , + message = stringResource(id = R.string.settings_backup_restore_information_text) , + confirmButtonText = "Restore", + dismissButtonText = "Backup", + onConfirmClick = { MainActivity().restoreFile(context = activity,dbPath.toUri()) - isDialogShowingState = false - }) { - Text(text = "Restore") - } - }, - dismissButton = { - OutlinedButton(onClick = { - MainActivity().writeFile(context = activity,dbPath.toUri()) - isDialogShowingState = false - }) { - Text(text = "Backup") - } - } - ) + }, + onDismissClick = { + MainActivity().writeFile(context = activity,dbPath.toUri()) + }) } // Backup dialog ends here ThemeChangerDialog( diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 043142d..48a82a2 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -23,7 +23,7 @@ Oddělte úkoly pomocí datumů Použít animaci dokončení úkolu Povolit AutoStart - Na některých zařízeních nemusí být upozornění přijímána včas nebo po restartu nemusí fungovat. Klepnutím sem povolíte automatické spuštění. \n\n(Užitečné pro Xiaomi, Oppo, vivo a zařízení se stock ROM) + Na některých zařízeních nemusí být upozornění přijímána včas nebo po restartu nemusí fungovat. Klepnutím sem povolíte automatické spuštění. Užitečné pro Xiaomi, Oppo, vivo a zařízení se stock ROM Zobrazit zdrojový kód Tasky je aplikace s otevřeným zdrojovým kódem. Máte zpětnou vazbu nebo se chcete pustit do vývoje? navštivte Github! A nezapomeňte dát ⭐️ ;) Použít 24-hodinový čas diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9348401..d08aa1f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,7 +23,7 @@ Aufgaben trennen durch Verwendung von Daten Verwendung von Animation bei erfüllter Aufgabe AutoStart aktivieren - Bei einigen Geräten kommen die Benachrichtigungen nicht rechtzeitig oder funktionieren nicht nach einer Rebootbenachrichtigung. Klicken Sie hier um autostart zu aktivieren. \n\n(Nützlich für Xiaomi, vivo, Oppo ähnliche Geräte die stock rom verwenden) + Bei einigen Geräten kommen die Benachrichtigungen nicht rechtzeitig oder funktionieren nicht nach einer Rebootbenachrichtigung. Klicken Sie hier um autostart zu aktivieren. Nützlich für Xiaomi, vivo, Oppo ähnliche Geräte die stock rom verwenden Quelle ansehen Tasky ist komplett quelloffen. Für Rückmeldungen oder Beteiligung an der Entwicklung ? besuchen Sie Github! Oh vergessen Sie nicht mir einen ⭐️ zu geben ;) 24-Stunden-Uhr verwenden diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7ca6453..114ce86 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -23,7 +23,7 @@ Séparez les tâches en utilisant les dates. Utilisez complètement les animations. Activez le démarrage automatique. - Pour certains appareils, les notifications peuvent ne pas être reçues à temps ou ne pas fonctionner après le redémarrage. Cliquez ici pour activer le démarrage automatique. \n\n(Utile pour Xiaomi, vivo, Oppo comme les appareils exécutant une rom de stockage). + Pour certains appareils, les notifications peuvent ne pas être reçues à temps ou ne pas fonctionner après le redémarrage. Cliquez ici pour activer le démarrage automatique. Utile pour Xiaomi, vivo, Oppo comme les appareils exécutant une rom de stockage. Voir la Source. Tasky est complètement à source ouverte. Vous avez un retour d expérience ou souhaitez vous lancez dans le développement ? Visitez Github! Oh et n oubliez pas de donnez une ⭐️ ;). Utiliser l horloge 24 heures. diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 0af04b3..c1e0cde 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -23,7 +23,7 @@ Oddeľte úlohy pomocou dátumov Použiť animáciu dokončenia úlohy Povoliť AutoStart - Na niektorých zariadeniach nemusia byť upozornenia prijímané včas alebo po reštarte nemusia fungovať. Kliknutím sem povolíte automatické spustenie. \n\n(Užitočné pre Xiaomi, Oppo, vivo a zariadenia so stock ROM) + Na niektorých zariadeniach nemusia byť upozornenia prijímané včas alebo po reštarte nemusia fungovať. Kliknutím sem povolíte automatické spustenie. Užitočné pre Xiaomi, Oppo, vivo a zariadenia so stock ROM Zobraziť zdrojový kód Tasky je aplikácia s otvoreným zdrojovým kódom. Máte spätnú väzbu alebo sa chcete pustiť do vývoja? navštívte Github! A nezabudnite dať ⭐️ ;) Použiť 24-hodinový čas diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 20055b5..b38e290 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -23,7 +23,7 @@ Görevleri tarihlerine göre ayır Görev tamamlama animasyonunu etkinleştir Otomatik Başlatmayı Etkinleştir - Bazı cihazlarda bildirimler zamanında alınmayabilir veya yeniden başlatıldıktan sonra çalışmayabilir. Otomatik başlatmayı etkinleştirmek için buraya tıklayın. \n\n(Stok rom çalıştıran Xiaomi, vivo, Oppo gibi cihazlar için kullanışlıdır) + Bazı cihazlarda bildirimler zamanında alınmayabilir veya yeniden başlatıldıktan sonra çalışmayabilir. Otomatik başlatmayı etkinleştirmek için buraya tıklayın. Stok rom çalıştıran Xiaomi, vivo, Oppo gibi cihazlar için kullanışlıdır Kaynak kodunu görüntüle Tasky tamamen açık kaynak kodludur. Bir geri bildiriminiz mi var veya geliştirme sürecine dahil olmak mı istiyorsunuz? Github\'ı ziyaret edin! Ve bir de ⭐️ vermeyi unutmayın ;) 24 Saat Formatı diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ed2e435..863e119 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,7 +23,7 @@ Separate tasks using dates Use task complete animations Enable AutoStart - For some devices, notifications might not be received on time, or may not work after reboot. Click here to enable autostart. \n\n(Useful for Xiaomi, Oppo, vivo and devices running stock ROM) + For some devices, notifications might not be received on time, or may not work after reboot. Click here to enable autostart. Useful for Xiaomi, Oppo, vivo and devices running stock ROM View Source Tasky is completely open source. Have a feedback or want to get into development? visit Github! Oh and don\'t forget to give a ⭐️ ;) Use 24 Hour Clock