Skip to content

Commit 0e96757

Browse files
committed
Merge feature/v1.3.2-lint-cleanup into main
2 parents b79c0d2 + 547c0a1 commit 0e96757

25 files changed

Lines changed: 342 additions & 174 deletions

File tree

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,43 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
---
88

9+
## [1.3.2] - 2026-01-10
10+
11+
### Changed
12+
- **🧹 Code-Qualität: "Clean Slate" Release**
13+
- Alle einfachen Lint-Issues behoben (Phase 1-7 des Cleanup-Plans)
14+
- Unused Imports und Members entfernt
15+
- Magic Numbers durch benannte Konstanten ersetzt
16+
- SwallowedExceptions mit Logger.w() versehen
17+
- MaxLineLength-Verstöße reformatiert
18+
- ConstructorParameterNaming (snake_case → camelCase mit @SerializedName)
19+
- Custom Exceptions: SyncException.kt und ValidationException.kt erstellt
20+
21+
### Added
22+
- **📝 F-Droid Privacy Notice**
23+
- Datenschutz-Hinweis für die Datei-Logging-Funktion
24+
- Erklärt dass Logs nur lokal gespeichert werden
25+
- Erfüllt F-Droid Opt-in Consent-Anforderungen
26+
27+
### Technical Improvements
28+
- **⚡ Neue Konstanten für bessere Wartbarkeit**
29+
- `SYNC_COMPLETED_DELAY_MS`, `ERROR_DISPLAY_DELAY_MS` (MainActivity)
30+
- `CONNECTION_TIMEOUT_MS` (SettingsActivity)
31+
- `SOCKET_TIMEOUT_MS`, `MAX_FILENAME_LENGTH`, `ETAG_PREVIEW_LENGTH` (WebDavSyncService)
32+
- `AUTO_CANCEL_TIMEOUT_MS` (NotificationHelper)
33+
- RFC 1918 IP-Range Konstanten (UrlValidator)
34+
- `DAYS_THRESHOLD`, `TRUNCATE_SUFFIX_LENGTH` (Extensions)
35+
36+
- **🔒 @Suppress Annotations für legitime Patterns**
37+
- ReturnCount: Frühe Returns für Validierung sind idiomatisch
38+
- LoopWithTooManyJumpStatements: Komplexe Sync-Logik dokumentiert
39+
40+
### Notes
41+
- Komplexe Refactorings (LargeClass, LongMethod) für v1.3.3+ geplant
42+
- Deprecation-Warnungen (LocalBroadcastManager, ProgressDialog) bleiben bestehen
43+
44+
---
45+
946
## [1.3.1] - 2026-01-08
1047

1148
### Fixed

README.en.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ cd android
8585
./gradlew assembleStandardRelease
8686
```
8787

88-
➡️ **Build guide:** [DOCS.en.md](docs/DOCS.en.md)
88+
➡️ **Build guide:** [DOCS.en.md](docs/DOCS.en.md#-build--deployment)
8989

9090
---
9191

@@ -101,4 +101,4 @@ MIT License - see [LICENSE](LICENSE)
101101

102102
---
103103

104-
**v1.2.1** · Built with ❤️ using Kotlin + Material Design 3
104+
**v1.3.2** · Built with ❤️ using Kotlin + Material Design 3

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ cd android
8888
./gradlew assembleStandardRelease
8989
```
9090

91-
➡️ **Build-Anleitung:** [DOCS.md](docs/DOCS.md)
91+
➡️ **Build-Anleitung:** [DOCS.md](docs/DOCS.md#-build--deployment)
9292

9393
---
9494

@@ -104,4 +104,4 @@ MIT License - siehe [LICENSE](LICENSE)
104104

105105
---
106106

107-
**v1.2.1** · Built with ❤️ using Kotlin + Material Design 3
107+
**v1.3.2** · Built with ❤️ using Kotlin + Material Design 3

android/app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ android {
2020
applicationId = "dev.dettmer.simplenotes"
2121
minSdk = 24
2222
targetSdk = 36
23-
versionCode = 9 // 🚀 v1.3.1: Sync-Performance & Debug-Logging
24-
versionName = "1.3.1" // 🚀 v1.3.1: Skip unchanged MD-Files, Sync-Mutex, Debug-Logging UI
23+
versionCode = 10 // 🚀 v1.3.2: Lint-Cleanup "Clean Slate"
24+
versionName = "1.3.2" // 🚀 v1.3.2: Code-Qualität-Release (alle einfachen Lint-Issues behoben)
2525

2626
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2727

android/app/src/main/java/dev/dettmer/simplenotes/MainActivity.kt

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class MainActivity : AppCompatActivity() {
7676
private const val REQUEST_SETTINGS = 1002
7777
private const val MIN_AUTO_SYNC_INTERVAL_MS = 60_000L // 1 Minute
7878
private const val PREF_LAST_AUTO_SYNC_TIME = "last_auto_sync_timestamp"
79+
private const val SYNC_COMPLETED_DELAY_MS = 1500L
80+
private const val ERROR_DISPLAY_DELAY_MS = 3000L
7981
}
8082

8183
/**
@@ -152,7 +154,7 @@ class MainActivity : AppCompatActivity() {
152154
// Show completed briefly, then hide
153155
syncStatusText.text = status.message ?: getString(R.string.sync_status_completed)
154156
lifecycleScope.launch {
155-
kotlinx.coroutines.delay(1500)
157+
kotlinx.coroutines.delay(SYNC_COMPLETED_DELAY_MS)
156158
syncStatusBanner.visibility = View.GONE
157159
SyncStateManager.reset()
158160
}
@@ -164,7 +166,7 @@ class MainActivity : AppCompatActivity() {
164166
// Show error briefly, then hide
165167
syncStatusText.text = status.message ?: getString(R.string.sync_status_error)
166168
lifecycleScope.launch {
167-
kotlinx.coroutines.delay(3000)
169+
kotlinx.coroutines.delay(ERROR_DISPLAY_DELAY_MS)
168170
syncStatusBanner.visibility = View.GONE
169171
SyncStateManager.reset()
170172
}
@@ -518,16 +520,28 @@ class MainActivity : AppCompatActivity() {
518520
val success = webdavService.deleteNoteFromServer(note.id)
519521
if (success) {
520522
runOnUiThread {
521-
Toast.makeText(this@MainActivity, "Vom Server gelöscht", Toast.LENGTH_SHORT).show()
523+
Toast.makeText(
524+
this@MainActivity,
525+
"Vom Server gelöscht",
526+
Toast.LENGTH_SHORT
527+
).show()
522528
}
523529
} else {
524530
runOnUiThread {
525-
Toast.makeText(this@MainActivity, "Server-Löschung fehlgeschlagen", Toast.LENGTH_LONG).show()
531+
Toast.makeText(
532+
this@MainActivity,
533+
"Server-Löschung fehlgeschlagen",
534+
Toast.LENGTH_LONG
535+
).show()
526536
}
527537
}
528538
} catch (e: Exception) {
529539
runOnUiThread {
530-
Toast.makeText(this@MainActivity, "Server-Fehler: ${e.message}", Toast.LENGTH_LONG).show()
540+
Toast.makeText(
541+
this@MainActivity,
542+
"Server-Fehler: ${e.message}",
543+
Toast.LENGTH_LONG
544+
).show()
531545
}
532546
}
533547
}
@@ -689,4 +703,4 @@ class MainActivity : AppCompatActivity() {
689703
}
690704
}
691705
}
692-
}
706+
}

android/app/src/main/java/dev/dettmer/simplenotes/SettingsActivity.kt

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
2525
import com.google.android.material.appbar.MaterialToolbar
2626
import com.google.android.material.card.MaterialCardView
2727
import com.google.android.material.color.DynamicColors
28-
import com.google.android.material.switchmaterial.SwitchMaterial
29-
import kotlinx.coroutines.CoroutineScope
3028
import kotlinx.coroutines.Dispatchers
3129
import kotlinx.coroutines.launch
3230
import dev.dettmer.simplenotes.backup.BackupManager
@@ -39,7 +37,6 @@ import dev.dettmer.simplenotes.sync.NetworkMonitor
3937
import dev.dettmer.simplenotes.utils.Constants
4038
import dev.dettmer.simplenotes.utils.Logger
4139
import dev.dettmer.simplenotes.utils.showToast
42-
import java.io.File
4340
import java.net.HttpURLConnection
4441
import java.net.URL
4542
import java.text.SimpleDateFormat
@@ -52,6 +49,7 @@ class SettingsActivity : AppCompatActivity() {
5249
private const val GITHUB_REPO_URL = "https://github.com/inventory69/simple-notes-sync"
5350
private const val GITHUB_PROFILE_URL = "https://github.com/inventory69"
5451
private const val LICENSE_URL = "https://github.com/inventory69/simple-notes-sync/blob/main/LICENSE"
52+
private const val CONNECTION_TIMEOUT_MS = 3000
5553
}
5654

5755
private lateinit var textInputLayoutServerUrl: com.google.android.material.textfield.TextInputLayout
@@ -325,7 +323,10 @@ class SettingsActivity : AppCompatActivity() {
325323
*/
326324
private fun setupSyncIntervalPicker() {
327325
// Load current interval from preferences
328-
val currentInterval = prefs.getLong(Constants.PREF_SYNC_INTERVAL_MINUTES, Constants.DEFAULT_SYNC_INTERVAL_MINUTES)
326+
val currentInterval = prefs.getLong(
327+
Constants.PREF_SYNC_INTERVAL_MINUTES,
328+
Constants.DEFAULT_SYNC_INTERVAL_MINUTES
329+
)
329330

330331
// Set checked radio button based on current interval
331332
val checkedId = when (currentInterval) {
@@ -654,8 +655,8 @@ class SettingsActivity : AppCompatActivity() {
654655
try {
655656
val url = URL(serverUrl)
656657
val connection = url.openConnection() as HttpURLConnection
657-
connection.connectTimeout = 3000
658-
connection.readTimeout = 3000
658+
connection.connectTimeout = CONNECTION_TIMEOUT_MS
659+
connection.readTimeout = CONNECTION_TIMEOUT_MS
659660
val code = connection.responseCode
660661
connection.disconnect()
661662
code in 200..299 || code == 401 // 401 = Server da, Auth fehlt
@@ -764,7 +765,10 @@ class SettingsActivity : AppCompatActivity() {
764765
.apply()
765766

766767
updateMarkdownButtonVisibility()
767-
showToast("Markdown Auto-Sync aktiviert - Notizen werden als .md-Dateien exportiert und importiert")
768+
showToast(
769+
"Markdown Auto-Sync aktiviert - " +
770+
"Notizen werden als .md-Dateien exportiert und importiert"
771+
)
768772
}
769773

770774
} catch (e: Exception) {
@@ -818,11 +822,13 @@ class SettingsActivity : AppCompatActivity() {
818822
intent.data = Uri.parse("package:$packageName")
819823
startActivity(intent)
820824
} catch (e: Exception) {
825+
Logger.w(TAG, "Failed to open battery optimization settings: ${e.message}")
821826
// Fallback: Open general battery settings
822827
try {
823828
val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
824829
startActivity(intent)
825830
} catch (e2: Exception) {
831+
Logger.w(TAG, "Failed to open fallback battery settings: ${e2.message}")
826832
showToast("Bitte Akku-Optimierung manuell deaktivieren")
827833
}
828834
}
@@ -841,49 +847,6 @@ class SettingsActivity : AppCompatActivity() {
841847
}
842848
}
843849

844-
private fun showRestoreConfirmation() {
845-
android.app.AlertDialog.Builder(this)
846-
.setTitle(R.string.restore_confirmation_title)
847-
.setMessage(R.string.restore_confirmation_message)
848-
.setPositiveButton(R.string.restore_button) { _, _ ->
849-
performRestore()
850-
}
851-
.setNegativeButton(R.string.cancel, null)
852-
.show()
853-
}
854-
855-
private fun performRestore() {
856-
val progressDialog = android.app.ProgressDialog(this).apply {
857-
setMessage(getString(R.string.restore_progress))
858-
setCancelable(false)
859-
show()
860-
}
861-
862-
CoroutineScope(Dispatchers.Main).launch {
863-
try {
864-
val webdavService = WebDavSyncService(this@SettingsActivity)
865-
val result = withContext(Dispatchers.IO) {
866-
webdavService.restoreFromServer()
867-
}
868-
869-
progressDialog.dismiss()
870-
871-
if (result.isSuccess) {
872-
showToast(getString(R.string.restore_success, result.restoredCount))
873-
// Refresh MainActivity's note list
874-
setResult(RESULT_OK)
875-
} else {
876-
showToast(getString(R.string.restore_error, result.errorMessage))
877-
}
878-
checkServerStatus()
879-
} catch (e: Exception) {
880-
progressDialog.dismiss()
881-
showToast(getString(R.string.restore_error, e.message))
882-
checkServerStatus()
883-
}
884-
}
885-
}
886-
887850
override fun onOptionsItemSelected(item: MenuItem): Boolean {
888851
return when (item.itemId) {
889852
android.R.id.home -> {
@@ -946,7 +909,6 @@ class SettingsActivity : AppCompatActivity() {
946909
}
947910

948911
// Custom View mit Radio Buttons
949-
val dialogView = layoutInflater.inflate(android.R.layout.select_dialog_singlechoice, null)
950912
val radioGroup = android.widget.RadioGroup(this).apply {
951913
orientation = android.widget.RadioGroup.VERTICAL
952914
setPadding(50, 20, 50, 20)
@@ -1039,12 +1001,12 @@ class SettingsActivity : AppCompatActivity() {
10391001
progressDialog.dismiss()
10401002

10411003
if (result.success) {
1042-
val message = result.message ?: "Wiederhergestellt: ${result.imported_notes} Notizen"
1004+
val message = result.message ?: "Wiederhergestellt: ${result.importedNotes} Notizen"
10431005
showToast("$message")
10441006

10451007
// Refresh MainActivity's note list
10461008
setResult(RESULT_OK)
1047-
broadcastNotesChanged(result.imported_notes)
1009+
broadcastNotesChanged(result.importedNotes)
10481010
} else {
10491011
showErrorDialog("Wiederherstellung fehlgeschlagen", result.error ?: "Unbekannter Fehler")
10501012
}
@@ -1153,10 +1115,16 @@ class SettingsActivity : AppCompatActivity() {
11531115
progressDialog.dismiss()
11541116

11551117
// Erfolgs-Nachricht
1156-
val message = "✅ Sync abgeschlossen\n📤 ${result.exportedCount} exportiert\n📥 ${result.importedCount} importiert"
1118+
val message = "✅ Sync abgeschlossen\n" +
1119+
"📤 ${result.exportedCount} exportiert\n" +
1120+
"📥 ${result.importedCount} importiert"
11571121
showToast(message)
11581122

1159-
Logger.d("SettingsActivity", "Manual markdown sync: exported=${result.exportedCount}, imported=${result.importedCount}")
1123+
Logger.d(
1124+
"SettingsActivity",
1125+
"Manual markdown sync: exported=${result.exportedCount}, " +
1126+
"imported=${result.importedCount}"
1127+
)
11601128

11611129
} catch (e: Exception) {
11621130
progressDialog?.dismiss()

0 commit comments

Comments
 (0)