Skip to content

Commit 940495a

Browse files
Baker0o7AndroidForClaw
andcommitted
fix: 修复7个bug
- 修复收藏夹筛选器不工作的问题 (combine缺少showFavoritesOnly) - 修复长按菜单恢复操作索引错误 (硬编码索引→动态查找) - 修复滑动撤销操作导致状态错误 (toggleArchive/trash→直接恢复) - 实现完整的JSON导入功能 (解析notes/tags/noteTags) - 修复loadTrashedNotes阻塞协程 (collect→asLiveData.observe) - 替换废弃的onBackPressed()为OnBackPressedCallback - 替换废弃的versionCode为longVersionCode Co-Authored-By: AndroidForClaw <androidforclaw@users.noreply.github.com>
1 parent 9989416 commit 940495a

File tree

4 files changed

+103
-27
lines changed

4 files changed

+103
-27
lines changed

app/src/main/kotlin/com/kitabu/app/ui/editor/EditorActivity.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import android.widget.LinearLayout
1616
import android.widget.GridLayout
1717
import android.widget.TextView as AndroidTextView
1818
import androidx.activity.result.contract.ActivityResultContracts
19+
import androidx.activity.OnBackPressedCallback
1920
import androidx.activity.viewModels
2021
import androidx.appcompat.app.AppCompatActivity
2122
import androidx.core.app.ActivityCompat
@@ -86,6 +87,7 @@ class EditorActivity : AppCompatActivity() {
8687
setupColorPicker()
8788
setupWordCount()
8889
setupAutoSave()
90+
setupBackPress()
8991

9092
val noteId = intent.getIntExtra(EXTRA_NOTE_ID, -1)
9193
val templateId = intent.getIntExtra(EXTRA_TEMPLATE_ID, -1)
@@ -757,6 +759,13 @@ class EditorActivity : AppCompatActivity() {
757759
else -> super.onOptionsItemSelected(item)
758760
}
759761

760-
override fun onBackPressed() { performSave() }
761762
override fun onPause() { super.onPause(); performSave(silent = true) }
763+
764+
private fun setupBackPress() {
765+
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
766+
override fun handleOnBackPressed() {
767+
performSave()
768+
}
769+
})
770+
}
762771
}

app/src/main/kotlin/com/kitabu/app/ui/notes/MainActivity.kt

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.activity.viewModels
1010
import androidx.appcompat.app.ActionBarDrawerToggle
1111
import androidx.appcompat.app.AppCompatActivity
1212
import androidx.appcompat.widget.SearchView
13+
import androidx.lifecycle.asLiveData
1314
import androidx.lifecycle.lifecycleScope
1415
import androidx.recyclerview.widget.ItemTouchHelper
1516
import androidx.recyclerview.widget.RecyclerView
@@ -135,12 +136,20 @@ class MainActivity : AppCompatActivity() {
135136
showingArchived -> {
136137
vm.toggleArchive(nwt.note)
137138
Snackbar.make(binding.root, "Restored to notes", Snackbar.LENGTH_LONG)
138-
.setAction("Undo") { vm.toggleArchive(nwt.note) }.show()
139+
.setAction("Undo") {
140+
lifecycleScope.launch {
141+
vm.repo.archive(nwt.note)
142+
}
143+
}.show()
139144
}
140145
else -> {
141146
vm.trash(nwt.note)
142147
Snackbar.make(binding.root, "Moved to trash", Snackbar.LENGTH_LONG)
143-
.setAction("Undo") { lifecycleScope.launch { vm.trash(nwt.note) } }.show()
148+
.setAction("Undo") {
149+
lifecycleScope.launch {
150+
vm.repo.restoreFromTrash(nwt.note)
151+
}
152+
}.show()
144153
}
145154
}
146155
}
@@ -170,16 +179,14 @@ class MainActivity : AppCompatActivity() {
170179
}
171180

172181
private fun loadTrashedNotes() {
173-
lifecycleScope.launch {
174-
vm.repo.trashedNotes.collect { list ->
175-
adapter.submitList(list)
176-
binding.layoutEmpty.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
177-
binding.recyclerView.visibility = if (list.isEmpty()) View.GONE else View.VISIBLE
178-
supportActionBar?.subtitle = "${list.size} trashed note${if (list.size != 1) "s" else ""}"
179-
binding.emptyIcon.text = ""
180-
binding.emptyTitle.text = "Trash is empty"
181-
binding.emptySubtitle.text = "Deleted notes appear here for 30 days"
182-
}
182+
vm.repo.trashedNotes.asLiveData().observe(this) { list ->
183+
adapter.submitList(list)
184+
binding.layoutEmpty.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
185+
binding.recyclerView.visibility = if (list.isEmpty()) View.GONE else View.VISIBLE
186+
supportActionBar?.subtitle = "${list.size} trashed note${if (list.size != 1) "s" else ""}"
187+
binding.emptyIcon.text = ""
188+
binding.emptyTitle.text = "Trash is empty"
189+
binding.emptySubtitle.text = "Deleted notes appear here for 30 days"
183190
}
184191
}
185192

@@ -264,20 +271,23 @@ class MainActivity : AppCompatActivity() {
264271
if (showingTrashed) opts.add("Restore")
265272
opts.add("Delete")
266273
opts.add("Share")
274+
val restoreIdx = opts.indexOf("Restore")
275+
val deleteIdx = opts.indexOf("Delete")
276+
val shareIdx = opts.indexOf("Share")
267277
MaterialAlertDialogBuilder(this, R.style.KitabuDialog)
268278
.setItems(opts.toTypedArray()) { _, i ->
269279
when {
270-
showingTrashed && i == opts.size - 3 -> { /* restore */
271-
lifecycleScope.launch { vm.trash(note) }
280+
restoreIdx != -1 && i == restoreIdx -> {
281+
lifecycleScope.launch { vm.repo.restoreFromTrash(note) }
272282
}
273283
i == 0 -> vm.togglePin(note)
274284
i == 1 -> vm.toggleFavorite(note)
275285
i == 2 -> vm.toggleLock(note)
276286
i == 3 && !showingTrashed -> {
277-
if (showingArchived) vm.toggleArchive(note) else vm.toggleArchive(note)
287+
vm.toggleArchive(note)
278288
}
279-
i == opts.size - 2 -> confirmDelete(note)
280-
i == opts.size - 1 -> shareNote(nwt)
289+
i == deleteIdx -> confirmDelete(note)
290+
i == shareIdx -> shareNote(nwt)
281291
}
282292
}.show()
283293
}
@@ -333,9 +343,59 @@ class MainActivity : AppCompatActivity() {
333343
val content = contentResolver.openInputStream(uri)?.use { stream ->
334344
BufferedReader(InputStreamReader(stream)).readText()
335345
} ?: return@launch
336-
Snackbar.make(binding.root, "Import started...", Snackbar.LENGTH_SHORT).show()
337-
// Basic import - show the JSON for now
338-
Snackbar.make(binding.root, "Import: ${content.take(100)}", Snackbar.LENGTH_LONG).show()
346+
val json = org.json.JSONObject(content)
347+
val notesArr = json.optJSONArray("notes") ?: org.json.JSONArray()
348+
val tagsArr = json.optJSONArray("tags") ?: org.json.JSONArray()
349+
val noteTagsArr = json.optJSONArray("noteTags") ?: org.json.JSONArray()
350+
351+
// Import tags first (build oldId -> newId map)
352+
val tagIdMap = mutableMapOf<Int, Int>()
353+
for (i in 0 until tagsArr.length()) {
354+
val t = tagsArr.getJSONObject(i)
355+
val oldId = t.getInt("id")
356+
val name = t.getString("name")
357+
val newTag = vm.getOrCreateTag(name)
358+
tagIdMap[oldId] = newTag.id
359+
}
360+
361+
// Import notes
362+
val noteIdMap = mutableMapOf<Int, Int>()
363+
var imported = 0
364+
for (i in 0 until notesArr.length()) {
365+
val n = notesArr.getJSONObject(i)
366+
val oldId = n.getInt("id")
367+
val note = Note(
368+
title = n.optString("title", ""),
369+
content = n.optString("content", ""),
370+
color = n.optInt("color", 0),
371+
isPinned = n.optBoolean("isPinned", false),
372+
isLocked = n.optBoolean("isLocked", false),
373+
isArchived = n.optBoolean("isArchived", false),
374+
isFavorite = n.optBoolean("isFavorite", false),
375+
isDaily = n.optBoolean("isDaily", false),
376+
dailyDate = n.optString("dailyDate", null),
377+
reminderTime = if (n.isNull("reminderTime")) null else n.optLong("reminderTime"),
378+
createdAt = n.optLong("createdAt", System.currentTimeMillis()),
379+
updatedAt = n.optLong("updatedAt", System.currentTimeMillis())
380+
)
381+
val newId = vm.repo.insert(note)
382+
noteIdMap[oldId] = newId.toInt()
383+
imported++
384+
}
385+
386+
// Import note-tag associations
387+
for (i in 0 until noteTagsArr.length()) {
388+
val nt = noteTagsArr.getJSONObject(i)
389+
val oldNoteId = nt.getInt("noteId")
390+
val oldTagId = nt.getInt("tagId")
391+
val newNoteId = noteIdMap[oldNoteId]
392+
val newTagId = tagIdMap[oldTagId]
393+
if (newNoteId != null && newTagId != null) {
394+
vm.setTagsForNote(newNoteId, listOf(newTagId))
395+
}
396+
}
397+
398+
Snackbar.make(binding.root, "Imported $imported notes", Snackbar.LENGTH_LONG).show()
339399
} catch (e: Exception) {
340400
Snackbar.make(binding.root, "Import failed: ${e.message}", Snackbar.LENGTH_SHORT).show()
341401
}

app/src/main/kotlin/com/kitabu/app/ui/notes/NoteViewModel.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ class NoteViewModel(application: Application) : AndroidViewModel(application) {
2424

2525
@OptIn(ExperimentalCoroutinesApi::class)
2626
val notes: LiveData<List<NoteWithTags>> = combine(
27-
_searchQuery.debounce(300), _sortOrder, _filterTagId, _showDailyOnly, _showArchivedOnly
28-
) { q, sort, tagId, dailyOnly, archivedOnly ->
29-
FilterState(q, sort, tagId, dailyOnly, archivedOnly)
27+
_searchQuery.debounce(300), _sortOrder, _filterTagId, _showDailyOnly, _showArchivedOnly, _showFavoritesOnly
28+
) { q, sort, tagId, dailyOnly, archivedOnly, favoritesOnly ->
29+
FilterState(q, sort, tagId, dailyOnly, archivedOnly, favoritesOnly)
3030
}
3131
.flatMapLatest { state ->
3232
val base: Flow<List<NoteWithTags>> = when {
33-
_showFavoritesOnly.value -> repo.favoriteNotes
33+
state.favoritesOnly -> repo.favoriteNotes
3434
state.archivedOnly -> repo.archivedNotes
3535
state.dailyOnly -> repo.dailyNotes
3636
state.tagId != null -> repo.getNotesByTag(state.tagId)
@@ -47,7 +47,8 @@ class NoteViewModel(application: Application) : AndroidViewModel(application) {
4747
val sort: SortOrder,
4848
val tagId: Int?,
4949
val dailyOnly: Boolean,
50-
val archivedOnly: Boolean
50+
val archivedOnly: Boolean,
51+
val favoritesOnly: Boolean = false
5152
)
5253

5354
private fun sorted(list: List<NoteWithTags>, sort: SortOrder): List<NoteWithTags> {

app/src/main/kotlin/com/kitabu/app/ui/settings/SettingsActivity.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,13 @@ class SettingsActivity : AppCompatActivity() {
5252

5353
try {
5454
val pInfo = packageManager.getPackageInfo(packageName, 0)
55-
binding.tvVersion.text = "Kitabu v${pInfo.versionName} (${pInfo.versionCode})"
55+
val versionCode = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
56+
pInfo.longVersionCode
57+
} else {
58+
@Suppress("DEPRECATION")
59+
pInfo.versionCode
60+
}
61+
binding.tvVersion.text = "Kitabu v${pInfo.versionName} ($versionCode)"
5662
} catch (_: Exception) {
5763
binding.tvVersion.text = "Kitabu v3.0.0"
5864
}

0 commit comments

Comments
 (0)