Skip to content

Commit ba5b5ef

Browse files
Merge pull request #3396 from nextcloud/feat/improve-error-feedback
improve sync error handling
2 parents ce6fbc0 + 6b0ae68 commit ba5b5ef

9 files changed

Lines changed: 380 additions & 169 deletions

File tree

‎app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Nextcloud Notes - Android Client
33
*
44
* SPDX-FileCopyrightText: 2015-2024 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
56
* SPDX-License-Identifier: GPL-3.0-or-later
67
*/
78
package it.niedermann.owncloud.notes.main;
@@ -215,7 +216,7 @@ protected void onCreate(Bundle savedInstanceState) {
215216
mainViewModel.getSyncStatus().observe(this, syncStatus -> swipeRefreshLayout.setRefreshing(syncStatus));
216217
mainViewModel.getSyncErrors().observe(this, exceptions -> {
217218
if (mainViewModel.containsNonInfrastructureRelatedItems(exceptions)) {
218-
BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG)
219+
BrandedSnackbar.make(coordinatorLayout, SyncErrorMessage.of(exceptions), Snackbar.LENGTH_LONG)
219220
.setAnchorView(binding.activityNotesListView.fabCreate)
220221
.setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(exceptions)
221222
.show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()))
@@ -324,7 +325,7 @@ public void onError(@NonNull Throwable t) {
324325
.setAnchorView(binding.activityNotesListView.fabCreate)
325326
.show();
326327
} else {
327-
BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG)
328+
BrandedSnackbar.make(coordinatorLayout, SyncErrorMessage.of(t), Snackbar.LENGTH_LONG)
328329
.setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(t)
329330
.show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()))
330331
.setAnchorView(binding.activityNotesListView.fabCreate)
@@ -608,7 +609,7 @@ public void onError(@NonNull Throwable t) {
608609
.setAnchorView(binding.activityNotesListView.fabCreate)
609610
.show();
610611
} else {
611-
BrandedSnackbar.make(coordinatorLayout, R.string.error_synchronization, Snackbar.LENGTH_LONG)
612+
BrandedSnackbar.make(coordinatorLayout, SyncErrorMessage.of(t), Snackbar.LENGTH_LONG)
612613
.setAction(R.string.simple_more, v -> ExceptionDialogFragment.newInstance(t)
613614
.show(getSupportFragmentManager(), ExceptionDialogFragment.class.getSimpleName()))
614615
.setAnchorView(binding.activityNotesListView.fabCreate)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
package it.niedermann.owncloud.notes.main
8+
9+
import androidx.annotation.StringRes
10+
import com.nextcloud.android.sso.exceptions.NextcloudApiNotRespondingException
11+
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException
12+
import com.nextcloud.android.sso.exceptions.NextcloudNetworkException
13+
import com.nextcloud.android.sso.exceptions.TokenMismatchException
14+
import it.niedermann.owncloud.notes.persistence.NoteSyncException
15+
import it.niedermann.owncloud.notes.persistence.SyncFailureReason
16+
17+
object SyncErrorMessage {
18+
@JvmStatic
19+
@StringRes
20+
fun of(exceptions: Collection<Throwable>): Int =
21+
(exceptions.map { it.syncFailureReason() }.distinct().singleOrNull() ?: SyncFailureReason.UNKNOWN).message
22+
23+
@JvmStatic
24+
@StringRes
25+
fun of(exception: Throwable): Int = exception.syncFailureReason().message
26+
27+
private fun Throwable.syncFailureReason(): SyncFailureReason =
28+
generateSequence(this) { it.cause }.firstNotNullOfOrNull { it.directSyncFailureReason() }
29+
?: SyncFailureReason.UNKNOWN
30+
31+
private fun Throwable.directSyncFailureReason(): SyncFailureReason? = when (this) {
32+
is NoteSyncException -> reason
33+
is NextcloudHttpRequestFailedException -> SyncFailureReason.fromStatusCode(statusCode)
34+
is NextcloudNetworkException, is NextcloudApiNotRespondingException -> SyncFailureReason.SERVER_UNREACHABLE
35+
is TokenMismatchException -> SyncFailureReason.TOKEN_MISMATCH
36+
else -> null
37+
}
38+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
package it.niedermann.owncloud.notes.persistence
8+
9+
import retrofit2.Response
10+
11+
class NoteSyncException(noteTitle: String, response: Response<*>) :
12+
Exception("Could not sync \"$noteTitle\" (HTTP ${response.code()}): ${response.message()}") {
13+
val reason = SyncFailureReason.fromStatusCode(response.code())
14+
}

‎app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ public LiveData<ImportStatus> addAccount(@NonNull String url, @NonNull String us
250250
return importTask.importNotes(new IResponseCallback<>() {
251251
@Override
252252
public void onSuccess(Void result) {
253+
syncActive.put(account.getId(), false);
253254
callback.onSuccess(account);
254255
}
255256

0 commit comments

Comments
 (0)