feat: 支持自定义学科 (#163)
This commit is contained in:
parent
af8b83a6c1
commit
3251af9fd5
13 changed files with 182 additions and 40 deletions
|
|
@ -34,7 +34,7 @@ android {
|
||||||
applicationId = "cn.super12138.todo"
|
applicationId = "cn.super12138.todo"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 556
|
versionCode = 557
|
||||||
versionName = "2.0.2"
|
versionName = "2.0.2"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 3,
|
||||||
|
"identityHash": "ce6665893b60113c5fcaf00af5c0db57",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "todo",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`content` TEXT NOT NULL, `subject` INTEGER NOT NULL, `custom_subject` TEXT NOT NULL, `completed` INTEGER NOT NULL, `priority` REAL NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "content",
|
||||||
|
"columnName": "content",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "subject",
|
||||||
|
"columnName": "subject",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "customSubject",
|
||||||
|
"columnName": "custom_subject",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isCompleted",
|
||||||
|
"columnName": "completed",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "priority",
|
||||||
|
"columnName": "priority",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ce6665893b60113c5fcaf00af5c0db57')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,10 @@ object Constants {
|
||||||
|
|
||||||
const val KEY_TODO_FAB_TRANSITION = "todo_fab"
|
const val KEY_TODO_FAB_TRANSITION = "todo_fab"
|
||||||
const val KEY_TODO_CONTENT_TRANSITION = "todo_content"
|
const val KEY_TODO_CONTENT_TRANSITION = "todo_content"
|
||||||
|
const val KEY_TODO_SUBJECT_TRANSITION = "todo_subject"
|
||||||
|
|
||||||
const val DB_NAME = "todo"
|
const val DB_NAME = "todo"
|
||||||
|
const val DB_TABLE_NAME = "todo"
|
||||||
|
|
||||||
const val SP_NAME = "cn.super12138.todo_preferences"
|
const val SP_NAME = "cn.super12138.todo_preferences"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ interface TodoDao {
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insert(toDo: TodoEntity)
|
suspend fun insert(toDo: TodoEntity)
|
||||||
|
|
||||||
@Query("SELECT * FROM ${Constants.DB_NAME}")
|
@Query("SELECT * FROM ${Constants.DB_TABLE_NAME}")
|
||||||
fun getAll(): Flow<List<TodoEntity>>
|
fun getAll(): Flow<List<TodoEntity>>
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
|
|
@ -23,7 +23,7 @@ interface TodoDao {
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(toDo: TodoEntity)
|
suspend fun delete(toDo: TodoEntity)
|
||||||
|
|
||||||
@Query("DELETE FROM ${Constants.DB_NAME} WHERE id in (:toDoIds)")
|
@Query("DELETE FROM ${Constants.DB_TABLE_NAME} WHERE id in (:toDoIds)")
|
||||||
suspend fun deleteFromIds(toDoIds: Set<Int>)
|
suspend fun deleteFromIds(toDoIds: Set<Int>)
|
||||||
|
|
||||||
/*@Query("DELETE FROM todo")
|
/*@Query("DELETE FROM todo")
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ import android.content.Context
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import cn.super12138.todo.constants.Constants
|
import cn.super12138.todo.constants.Constants
|
||||||
|
|
||||||
@Database(entities = [TodoEntity::class], version = 2)
|
@Database(entities = [TodoEntity::class], version = 3)
|
||||||
abstract class TodoDatabase : RoomDatabase() {
|
abstract class TodoDatabase : RoomDatabase() {
|
||||||
abstract fun toDoDao(): TodoDao
|
abstract fun toDoDao(): TodoDao
|
||||||
|
|
||||||
|
|
@ -20,6 +22,7 @@ abstract class TodoDatabase : RoomDatabase() {
|
||||||
TodoDatabase::class.java,
|
TodoDatabase::class.java,
|
||||||
Constants.DB_NAME
|
Constants.DB_NAME
|
||||||
)
|
)
|
||||||
|
.addMigrations(MIGRATION_2_3)
|
||||||
.fallbackToDestructiveMigration()
|
.fallbackToDestructiveMigration()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
|
@ -27,5 +30,11 @@ abstract class TodoDatabase : RoomDatabase() {
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MIGRATION_2_3 = object : Migration(2, 3) {
|
||||||
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
|
db.execSQL("ALTER TABLE ${Constants.DB_TABLE_NAME} ADD COLUMN custom_subject TEXT NOT NULL DEFAULT ''")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,11 +3,13 @@ package cn.super12138.todo.logic.database
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import cn.super12138.todo.constants.Constants
|
||||||
|
|
||||||
@Entity(tableName = "todo")
|
@Entity(tableName = Constants.DB_TABLE_NAME)
|
||||||
data class TodoEntity(
|
data class TodoEntity(
|
||||||
@ColumnInfo(name = "content") val content: String,
|
@ColumnInfo(name = "content") val content: String,
|
||||||
@ColumnInfo(name = "subject") val subject: Int,
|
@ColumnInfo(name = "subject") val subject: Int,
|
||||||
|
@ColumnInfo(name = "custom_subject") val customSubject: String = "",
|
||||||
@ColumnInfo(name = "completed") val isCompleted: Boolean = false,
|
@ColumnInfo(name = "completed") val isCompleted: Boolean = false,
|
||||||
@ColumnInfo(name = "priority") val priority: Float,
|
@ColumnInfo(name = "priority") val priority: Float,
|
||||||
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int = 0,
|
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int = 0,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ enum class Subjects(val id: Int) {
|
||||||
Moral(6),
|
Moral(6),
|
||||||
Chemistry(7),
|
Chemistry(7),
|
||||||
History(8),
|
History(8),
|
||||||
Others(99);
|
Others(99),
|
||||||
|
Custom(100);
|
||||||
|
|
||||||
fun getDisplayName(context: Context): String {
|
fun getDisplayName(context: Context): String {
|
||||||
val resId = when (this) {
|
val resId = when (this) {
|
||||||
|
|
@ -27,6 +28,7 @@ enum class Subjects(val id: Int) {
|
||||||
Chemistry -> R.string.subject_chemistry
|
Chemistry -> R.string.subject_chemistry
|
||||||
History -> R.string.subject_history
|
History -> R.string.subject_history
|
||||||
Others -> R.string.subject_others
|
Others -> R.string.subject_others
|
||||||
|
Custom -> R.string.subject_customization
|
||||||
}
|
}
|
||||||
return context.getString(resId) // 返回资源中的文本
|
return context.getString(resId) // 返回资源中的文本
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,23 +34,23 @@ import cn.super12138.todo.utils.VibrationUtils
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun FilterChipGroup(
|
fun FilterChipGroup(
|
||||||
items: List<String>,
|
items: List<ChipItem>,
|
||||||
defaultSelectedItemIndex: Int = 0,
|
defaultSelectedItemIndex: Int = 0,
|
||||||
onSelectedChanged: (Int) -> Unit = {},
|
onSelectedChanged: (Int) -> Unit = {},
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
var selectedItemIndex by rememberSaveable { mutableIntStateOf(defaultSelectedItemIndex) }
|
var selectedItemId by rememberSaveable { mutableIntStateOf(defaultSelectedItemIndex) }
|
||||||
|
|
||||||
FlowRow(modifier = modifier) {
|
FlowRow(modifier = modifier) {
|
||||||
items.forEachIndexed { index, item ->
|
items.forEach { item ->
|
||||||
FilterChipItem(
|
FilterChipItem(
|
||||||
selected = items[selectedItemIndex] == items[index],
|
selected = item.id == selectedItemId,
|
||||||
text = item,
|
text = item.text,
|
||||||
onClick = {
|
onClick = {
|
||||||
selectedItemIndex = index
|
selectedItemId = item.id
|
||||||
VibrationUtils.performHapticFeedback(view)
|
VibrationUtils.performHapticFeedback(view)
|
||||||
onSelectedChanged(index)
|
onSelectedChanged(item.id)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ fun FilterChipGroup(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FilterChipItem(
|
private fun FilterChipItem(
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
text: String,
|
text: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
|
|
@ -85,4 +85,9 @@ fun FilterChipItem(
|
||||||
},
|
},
|
||||||
modifier = Modifier.padding(end = 10.dp)
|
modifier = Modifier.padding(end = 10.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ChipItem(
|
||||||
|
val id: Int,
|
||||||
|
val text: String
|
||||||
|
)
|
||||||
|
|
@ -34,6 +34,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
|
@ -56,6 +57,7 @@ import cn.super12138.todo.logic.model.Priority
|
||||||
import cn.super12138.todo.logic.model.Subjects
|
import cn.super12138.todo.logic.model.Subjects
|
||||||
import cn.super12138.todo.ui.TodoDefaults
|
import cn.super12138.todo.ui.TodoDefaults
|
||||||
import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton
|
import cn.super12138.todo.ui.components.AnimatedExtendedFloatingActionButton
|
||||||
|
import cn.super12138.todo.ui.components.ChipItem
|
||||||
import cn.super12138.todo.ui.components.FilterChipGroup
|
import cn.super12138.todo.ui.components.FilterChipGroup
|
||||||
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
|
import cn.super12138.todo.ui.components.LargeTopAppBarScaffold
|
||||||
import cn.super12138.todo.ui.components.WarningDialog
|
import cn.super12138.todo.ui.components.WarningDialog
|
||||||
|
|
@ -80,15 +82,22 @@ fun TodoEditorPage(
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
|
||||||
var toDoContent by rememberSaveable { mutableStateOf(toDo?.content ?: "") }
|
var toDoContent by rememberSaveable { mutableStateOf(toDo?.content ?: "") }
|
||||||
var isError by rememberSaveable { mutableStateOf(false) }
|
var isErrorContent by rememberSaveable { mutableStateOf(false) }
|
||||||
var selectedSubjectIndex by rememberSaveable { mutableIntStateOf(toDo?.subject ?: 0) }
|
var selectedSubjectId by rememberSaveable { mutableIntStateOf(toDo?.subject ?: 0) }
|
||||||
|
var subjectContent by rememberSaveable { mutableStateOf(toDo?.customSubject ?: "") }
|
||||||
|
var isErrorSubject by rememberSaveable { mutableStateOf(false) }
|
||||||
var priorityState by rememberSaveable { mutableFloatStateOf(toDo?.priority ?: 0f) }
|
var priorityState by rememberSaveable { mutableFloatStateOf(toDo?.priority ?: 0f) }
|
||||||
var completedSwitchState by rememberSaveable { mutableStateOf(toDo?.isCompleted ?: false) }
|
var completedSwitchState by rememberSaveable { mutableStateOf(toDo?.isCompleted ?: false) }
|
||||||
|
|
||||||
|
val isCustomSubject by remember {
|
||||||
|
derivedStateOf { selectedSubjectId == Subjects.Custom.id }
|
||||||
|
}
|
||||||
|
|
||||||
fun checkModifiedBeforeBack() {
|
fun checkModifiedBeforeBack() {
|
||||||
var isModified = false
|
var isModified = false
|
||||||
if ((toDo?.content ?: "") != toDoContent) isModified = true
|
if ((toDo?.content ?: "") != toDoContent) isModified = true
|
||||||
if ((toDo?.subject ?: 0) != selectedSubjectIndex) isModified = true
|
if ((toDo?.subject ?: 0) != selectedSubjectId) isModified = true
|
||||||
|
if ((toDo?.customSubject ?: "") != subjectContent) isModified = true
|
||||||
if ((toDo?.priority ?: 0f) != priorityState) isModified = true
|
if ((toDo?.priority ?: 0f) != priorityState) isModified = true
|
||||||
if ((toDo?.isCompleted == true) != completedSwitchState) isModified = true
|
if ((toDo?.isCompleted == true) != completedSwitchState) isModified = true
|
||||||
if (isModified) {
|
if (isModified) {
|
||||||
|
|
@ -123,15 +132,23 @@ fun TodoEditorPage(
|
||||||
expanded = true,
|
expanded = true,
|
||||||
onClick = {
|
onClick = {
|
||||||
if (toDoContent.trim().isEmpty()) {
|
if (toDoContent.trim().isEmpty()) {
|
||||||
isError = true
|
isErrorContent = true
|
||||||
|
return@AnimatedExtendedFloatingActionButton
|
||||||
|
}
|
||||||
|
if (subjectContent.trim()
|
||||||
|
.isEmpty() && selectedSubjectId == Subjects.Custom.id
|
||||||
|
) {
|
||||||
|
isErrorSubject = true
|
||||||
return@AnimatedExtendedFloatingActionButton
|
return@AnimatedExtendedFloatingActionButton
|
||||||
}
|
}
|
||||||
|
|
||||||
isError = false
|
isErrorContent = false
|
||||||
|
isErrorSubject = false
|
||||||
onSave(
|
onSave(
|
||||||
TodoEntity(
|
TodoEntity(
|
||||||
content = toDoContent,
|
content = toDoContent,
|
||||||
subject = selectedSubjectIndex,
|
subject = selectedSubjectId,
|
||||||
|
customSubject = subjectContent,
|
||||||
isCompleted = completedSwitchState,
|
isCompleted = completedSwitchState,
|
||||||
priority = priorityState,
|
priority = priorityState,
|
||||||
id = toDo?.id ?: 0
|
id = toDo?.id ?: 0
|
||||||
|
|
@ -163,10 +180,10 @@ fun TodoEditorPage(
|
||||||
value = toDoContent,
|
value = toDoContent,
|
||||||
onValueChange = { toDoContent = it },
|
onValueChange = { toDoContent = it },
|
||||||
label = { Text(stringResource(R.string.placeholder_add_todo)) },
|
label = { Text(stringResource(R.string.placeholder_add_todo)) },
|
||||||
isError = isError,
|
isError = isErrorContent,
|
||||||
supportingText = {
|
supportingText = {
|
||||||
AnimatedVisibility(isError) {
|
AnimatedVisibility(isErrorContent) {
|
||||||
Text(stringResource(R.string.error_no_task_content))
|
Text(stringResource(R.string.error_no_content_entered))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -180,11 +197,6 @@ fun TodoEditorPage(
|
||||||
|
|
||||||
Spacer(Modifier.size(5.dp))
|
Spacer(Modifier.size(5.dp))
|
||||||
|
|
||||||
val subjects = remember {
|
|
||||||
Subjects.entries.map {
|
|
||||||
it.getDisplayName(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.label_subject),
|
text = stringResource(R.string.label_subject),
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
|
@ -192,14 +204,44 @@ fun TodoEditorPage(
|
||||||
|
|
||||||
Spacer(Modifier.size(5.dp))
|
Spacer(Modifier.size(5.dp))
|
||||||
|
|
||||||
|
val subjects = remember {
|
||||||
|
Subjects.entries.map {
|
||||||
|
ChipItem(
|
||||||
|
id = it.id,
|
||||||
|
text = it.getDisplayName(context)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
FilterChipGroup(
|
FilterChipGroup(
|
||||||
items = subjects,
|
items = subjects,
|
||||||
defaultSelectedItemIndex = toDo?.subject ?: 0,
|
defaultSelectedItemIndex = toDo?.subject ?: Subjects.Chinese.id,
|
||||||
onSelectedChanged = {
|
onSelectedChanged = {
|
||||||
selectedSubjectIndex = it
|
selectedSubjectId = it
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
|
AnimatedVisibility(isCustomSubject) {
|
||||||
|
with(sharedTransitionScope) {
|
||||||
|
TextField(
|
||||||
|
value = subjectContent,
|
||||||
|
onValueChange = { subjectContent = it },
|
||||||
|
label = { Text(stringResource(R.string.label_enter_subject_name)) },
|
||||||
|
isError = isErrorSubject,
|
||||||
|
supportingText = {
|
||||||
|
AnimatedVisibility(isErrorSubject) {
|
||||||
|
Text(stringResource(R.string.error_no_content_entered))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.sharedBounds(
|
||||||
|
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_SUBJECT_TRANSITION}_${toDo?.id}"),
|
||||||
|
animatedVisibilityScope = animatedVisibilityScope
|
||||||
|
)
|
||||||
|
.padding(top = 5.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(Modifier.size(10.dp))
|
Spacer(Modifier.size(10.dp))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,16 @@ fun ManagerFragment(
|
||||||
items = list,
|
items = list,
|
||||||
key = { it.id }
|
key = { it.id }
|
||||||
) { item ->
|
) { item ->
|
||||||
|
val subject = if (item.subject == Subjects.Custom.id) {
|
||||||
|
item.customSubject
|
||||||
|
} else {
|
||||||
|
Subjects.fromId(item.subject).getDisplayName(context)
|
||||||
|
}
|
||||||
|
|
||||||
TodoCard(
|
TodoCard(
|
||||||
id = item.id,
|
id = item.id,
|
||||||
content = item.content,
|
content = item.content,
|
||||||
subject = Subjects.fromId(item.subject).getDisplayName(context),
|
subject = subject,
|
||||||
completed = item.isCompleted,
|
completed = item.isCompleted,
|
||||||
priority = Priority.fromFloat(item.priority),
|
priority = Priority.fromFloat(item.priority),
|
||||||
selected = selectedTodoIds.contains(item.id),
|
selected = selectedTodoIds.contains(item.id),
|
||||||
|
|
|
||||||
|
|
@ -144,12 +144,18 @@ fun TodoCard(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
with(sharedTransitionScope) {
|
||||||
text = subject,
|
Text(
|
||||||
style = MaterialTheme.typography.labelMedium,
|
text = subject,
|
||||||
textDecoration = if (completed) TextDecoration.LineThrough else TextDecoration.None,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
maxLines = 1
|
textDecoration = if (completed) TextDecoration.LineThrough else TextDecoration.None,
|
||||||
)
|
maxLines = 1,
|
||||||
|
modifier = Modifier.sharedBounds(
|
||||||
|
sharedContentState = rememberSharedContentState("${Constants.KEY_TODO_SUBJECT_TRANSITION}_$id"),
|
||||||
|
animatedVisibilityScope = animatedVisibilityScope
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(!selected && !completed) {
|
AnimatedVisibility(!selected && !completed) {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<string name="placeholder_add_todo">待办内容</string>
|
<string name="placeholder_add_todo">待办内容</string>
|
||||||
<string name="action_cancel">取消</string>
|
<string name="action_cancel">取消</string>
|
||||||
<string name="action_save">保存</string>
|
<string name="action_save">保存</string>
|
||||||
<string name="error_no_task_content">没有输入待办内容</string>
|
<string name="error_no_content_entered">没有输入内容</string>
|
||||||
<string name="tip_select_this">选择该项</string>
|
<string name="tip_select_this">选择该项</string>
|
||||||
<string name="tip_mark_completed">标记为已完成</string>
|
<string name="tip_mark_completed">标记为已完成</string>
|
||||||
<string name="subject_chinese">语文</string>
|
<string name="subject_chinese">语文</string>
|
||||||
|
|
@ -108,4 +108,6 @@
|
||||||
<string name="pref_secure_mode_desc">阻止截屏并保护后台预览图</string>
|
<string name="pref_secure_mode_desc">阻止截屏并保护后台预览图</string>
|
||||||
<string name="label_more">更多</string>
|
<string name="label_more">更多</string>
|
||||||
<string name="happy_birthday">待办1岁生日快乐</string>
|
<string name="happy_birthday">待办1岁生日快乐</string>
|
||||||
|
<string name="subject_customization">自定义</string>
|
||||||
|
<string name="label_enter_subject_name">输入学科名称</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<string name="placeholder_add_todo">Task content</string>
|
<string name="placeholder_add_todo">Task content</string>
|
||||||
<string name="action_cancel">Cancel</string>
|
<string name="action_cancel">Cancel</string>
|
||||||
<string name="action_save">Save</string>
|
<string name="action_save">Save</string>
|
||||||
<string name="error_no_task_content">No task content entered</string>
|
<string name="error_no_content_entered">No content entered</string>
|
||||||
<string name="tip_select_this">Select this</string>
|
<string name="tip_select_this">Select this</string>
|
||||||
<string name="tip_mark_completed">Mark as completed</string>
|
<string name="tip_mark_completed">Mark as completed</string>
|
||||||
<string name="subject_chinese">Chinese</string>
|
<string name="subject_chinese">Chinese</string>
|
||||||
|
|
@ -109,4 +109,6 @@
|
||||||
<string name="pref_secure_mode_desc">Prevent screenshots and protect the background preview image</string>
|
<string name="pref_secure_mode_desc">Prevent screenshots and protect the background preview image</string>
|
||||||
<string name="label_more">More</string>
|
<string name="label_more">More</string>
|
||||||
<string name="happy_birthday">Happy 1st birthday to ToDo</string>
|
<string name="happy_birthday">Happy 1st birthday to ToDo</string>
|
||||||
|
<string name="subject_customization">Customization</string>
|
||||||
|
<string name="label_enter_subject_name">Enter subject name</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in a new issue