From d9d728bf21946fef33e98d882906a14b4949c39d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 10 Jun 2026 10:20:23 +0200 Subject: [PATCH 1/6] fix notification deletion Signed-off-by: alperozturk96 --- .../ui/adapter/NotificationListAdapter.kt | 6 +++--- .../notifications/NotificationsFragment.kt | 21 +++++++++---------- .../ui/notifications/NotificationsContract.kt | 5 ++--- .../res/layout/notification_list_item.xml | 2 +- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt index 00677da4fa82..ab78b6866259 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt @@ -279,9 +279,9 @@ class NotificationListAdapter( notifyDataSetChanged() } - fun removeNotification(holder: NotificationViewHolder) { - val position = holder.bindingAdapterPosition - if (position in 0 until notificationsList.size) { + fun removeNotification(id: Int) { + val position = notificationsList.indexOfFirst { it.notificationId == id } + if (position != -1) { notificationsList.removeAt(position) notifyItemRemoved(position) notifyItemRangeChanged(position, notificationsList.size) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt index dcfe1e6b7583..d5ea7658be08 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt @@ -323,18 +323,17 @@ class NotificationsFragment : } // region Callbacks - override fun onRemovedNotification(isSuccess: Boolean, client: NextcloudClient) { - if (!isSuccess) { + override fun removeNotification(id: Int, success: Boolean, client: NextcloudClient) { + if (success) { + adapter?.removeNotification(id) + if (adapter?.itemCount == 0) { + state = NotificationsUIState.Empty + } + } else { DisplayUtils.showSnackMessage(requireActivity(), getString(R.string.remove_notification_failed)) - fetchAndSetData(client) } - } - override fun removeNotification(holder: NotificationListAdapter.NotificationViewHolder) { - adapter?.removeNotification(holder) - if (adapter?.itemCount == 0) { - state = NotificationsUIState.Empty - } + fetchAndSetData(client) } override fun onRemovedAllNotifications(isSuccess: Boolean) { @@ -352,7 +351,7 @@ class NotificationsFragment : holder: NotificationListAdapter.NotificationViewHolder ) { if (isSuccess) { - adapter?.removeNotification(holder) + adapter?.removeNotification(notification.notificationId) } else { adapter?.bindButtons(holder, notification) DisplayUtils.showSnackMessage(requireActivity(), getString(R.string.notification_action_failed)) @@ -379,7 +378,7 @@ class NotificationsFragment : lifecycleScope.launch(Dispatchers.IO) { val result = DeleteNotificationRemoteOperation(id).execute(client) withContext(Dispatchers.Main) { - onRemovedNotification(result?.isSuccess == true, client) + removeNotification(id, success = (result?.isSuccess == true), client) } } } diff --git a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt index 01702e1ed0ef..7eeab82429f9 100644 --- a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt +++ b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2019 Tobias Kaminsky * SPDX-FileCopyrightText: 2019 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only @@ -13,9 +14,7 @@ import com.owncloud.android.ui.adapter.NotificationListAdapter.NotificationViewH interface NotificationsContract { interface View { - fun onRemovedNotification(isSuccess: Boolean, client: NextcloudClient) - - fun removeNotification(holder: NotificationViewHolder) + fun removeNotification(id: Int, success: Boolean, client: NextcloudClient) fun onRemovedAllNotifications(isSuccess: Boolean) diff --git a/app/src/main/res/layout/notification_list_item.xml b/app/src/main/res/layout/notification_list_item.xml index 1419aafd5b92..7f28bbe99b75 100644 --- a/app/src/main/res/layout/notification_list_item.xml +++ b/app/src/main/res/layout/notification_list_item.xml @@ -79,7 +79,7 @@ From fab3ed83792060ec32fdf5f3059e8a1cd7328e6d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 10 Jun 2026 10:31:50 +0200 Subject: [PATCH 2/6] simplify and make remove button more reachable Signed-off-by: alperozturk96 --- .../ui/adapter/NotificationListAdapter.kt | 23 ++++++++++--------- .../NotificationExecuteActionTask.kt | 2 +- .../notifications/NotificationsFragment.kt | 7 +++--- .../ui/notifications/NotificationsContract.kt | 8 +++++-- .../res/layout/notification_list_item.xml | 14 +++++++---- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt index ab78b6866259..3872e32af85d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt @@ -16,7 +16,6 @@ import android.content.Intent import android.graphics.Typeface import android.text.Spannable import android.text.SpannableStringBuilder -import android.text.TextUtils import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan import android.view.Gravity @@ -91,7 +90,7 @@ class NotificationListAdapter( private fun bindSubject(holder: NotificationViewHolder, notification: Notification) { val file = notification.subjectRichParameters[FILE] - if (file == null && !TextUtils.isEmpty(notification.getLink())) { + if (file == null && !notification.getLink().isNullOrEmpty()) { val subject = "${notification.getSubject()} ↗" holder.binding.subject.run { setTypeface(typeface, Typeface.BOLD) @@ -102,7 +101,7 @@ class NotificationListAdapter( } } else { holder.binding.subject.run { - text = if (!TextUtils.isEmpty(notification.subjectRich)) { + text = if (!notification.subjectRich.isNullOrEmpty()) { makeSpecialPartsBold(notification) } else { notification.getSubject() @@ -139,14 +138,18 @@ class NotificationListAdapter( private fun colorViewHolder(holder: NotificationViewHolder) { viewThemeUtils.platform.run { - colorImageView(holder.binding.icon, ColorRole.ON_SURFACE_VARIANT) - colorImageView(holder.binding.dismiss, ColorRole.ON_SURFACE_VARIANT) - colorTextView(holder.binding.subject, ColorRole.ON_SURFACE) - colorTextView(holder.binding.message, ColorRole.ON_SURFACE_VARIANT) - colorTextView(holder.binding.datetime, ColorRole.ON_SURFACE_VARIANT) + holder.binding.run { + colorImageView(icon, ColorRole.ON_SURFACE_VARIANT) + colorTextView(subject, ColorRole.ON_SURFACE) + colorTextView(message, ColorRole.ON_SURFACE_VARIANT) + colorTextView(datetime, ColorRole.ON_SURFACE_VARIANT) + } } - } + viewThemeUtils.material.run { + colorMaterialButtonText(holder.binding.dismiss) + } + } // endregion // region Button binding @@ -271,7 +274,6 @@ class NotificationListAdapter( // endregion // region Data manipulation - @SuppressLint("NotifyDataSetChanged") fun setNotificationItems(notificationItems: List) { notificationsList.clear() @@ -299,7 +301,6 @@ class NotificationListAdapter( holder.binding.buttons.getChildAt(i).isEnabled = enabled } } - // endregion private fun makeSpecialPartsBold(notification: Notification): SpannableStringBuilder { diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/NotificationExecuteActionTask.kt b/app/src/main/java/com/owncloud/android/ui/asynctasks/NotificationExecuteActionTask.kt index f6be5f5bf140..b8c3e9f3bc1f 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/NotificationExecuteActionTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/NotificationExecuteActionTask.kt @@ -42,7 +42,7 @@ class NotificationExecuteActionTask( performRequest(action) } - fragment.onActionCallback(isSuccess, notification, holder) + fragment.onNotificationActionCompletion(isSuccess, notification, holder) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt index d5ea7658be08..fdae22ca5262 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt @@ -230,7 +230,7 @@ class NotificationsFragment : if (item.itemId != R.id.action_empty_notifications) return false lifecycleScope.launch(Dispatchers.IO) { val result = DeleteAllNotificationsRemoteOperation().execute(client) - withContext(Dispatchers.Main) { onRemovedAllNotifications(result.isSuccess) } + withContext(Dispatchers.Main) { removeAllNotifications(result.isSuccess) } } return true } @@ -336,7 +336,7 @@ class NotificationsFragment : fetchAndSetData(client) } - override fun onRemovedAllNotifications(isSuccess: Boolean) { + override fun removeAllNotifications(isSuccess: Boolean) { if (isSuccess) { adapter?.removeAllNotifications() state = NotificationsUIState.Empty @@ -345,11 +345,12 @@ class NotificationsFragment : } } - override fun onActionCallback( + override fun onNotificationActionCompletion( isSuccess: Boolean, notification: Notification, holder: NotificationListAdapter.NotificationViewHolder ) { + // after any action successfully completed remove the notification if (isSuccess) { adapter?.removeNotification(notification.notificationId) } else { diff --git a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt index 7eeab82429f9..806a9385a8c4 100644 --- a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt +++ b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationsContract.kt @@ -16,8 +16,12 @@ interface NotificationsContract { interface View { fun removeNotification(id: Int, success: Boolean, client: NextcloudClient) - fun onRemovedAllNotifications(isSuccess: Boolean) + fun removeAllNotifications(isSuccess: Boolean) - fun onActionCallback(isSuccess: Boolean, notification: Notification, holder: NotificationViewHolder) + fun onNotificationActionCompletion( + isSuccess: Boolean, + notification: Notification, + holder: NotificationViewHolder + ) } } diff --git a/app/src/main/res/layout/notification_list_item.xml b/app/src/main/res/layout/notification_list_item.xml index 7f28bbe99b75..d100ed13ec18 100644 --- a/app/src/main/res/layout/notification_list_item.xml +++ b/app/src/main/res/layout/notification_list_item.xml @@ -2,7 +2,8 @@ - + android:paddingBottom="@dimen/standard_padding"> - - - - - - - - - - - - + android:src="@drawable/ic_notification" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + - + From 7e21f633a9cae2de42fcb9eed951c6055b5e78e6 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 10 Jun 2026 10:45:13 +0200 Subject: [PATCH 4/6] make dismiss button gray Signed-off-by: alperozturk96 --- .../owncloud/android/ui/adapter/NotificationListAdapter.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt index 1ce3fc4630c0..2a8dbf915ebb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.kt @@ -146,11 +146,7 @@ class NotificationListAdapter( } } - viewThemeUtils.material.run { - colorMaterialButtonText(holder.binding.dismiss) - } - - viewThemeUtils.platform.colorTextView(holder.binding.dismiss, ColorRole.SECONDARY) + viewThemeUtils.material.colorMaterialButtonContent(holder.binding.dismiss, ColorRole.ON_SURFACE) } // endregion From b387e4b79e7b221467d1b858fa5228d6df9fc8bf Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 10 Jun 2026 10:50:28 +0200 Subject: [PATCH 5/6] by default hide notification bell Signed-off-by: alperozturk96 --- .../owncloud/android/ui/activity/FileDisplayActivity.kt | 8 ++++---- app/src/main/res/layout/toolbar_standard.xml | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 6cf56f6c862f..b727e0d70a2b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -84,6 +84,7 @@ import com.nextcloud.utils.extensions.lastFragment import com.nextcloud.utils.extensions.logFileSize import com.nextcloud.utils.extensions.navigateToAllFiles import com.nextcloud.utils.extensions.observeWorker +import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.fileNameValidator.FileNameValidator.checkFolderPath import com.nextcloud.utils.view.FastScrollUtils import com.owncloud.android.MainApp @@ -481,10 +482,9 @@ class FileDisplayActivity : val result = GetNotificationsRemoteOperation() .execute(clientFactory.createNextcloudClient(accountManager.user)) - if (result.isSuccess && result.getResultData()?.isEmpty() == false) { - runOnUiThread { mNotificationButton.visibility = View.VISIBLE } - } else { - runOnUiThread { mNotificationButton.visibility = View.GONE } + val isVisible = (result.isSuccess && result.getResultData()?.isEmpty() == false) + withContext(Dispatchers.Main) { + mNotificationButton.setVisibleIf(isVisible) } } catch (_: CreationException) { Log_OC.e(TAG, "Could not fetch notifications!") diff --git a/app/src/main/res/layout/toolbar_standard.xml b/app/src/main/res/layout/toolbar_standard.xml index af71bd5843e2..e07ee7726dd3 100644 --- a/app/src/main/res/layout/toolbar_standard.xml +++ b/app/src/main/res/layout/toolbar_standard.xml @@ -221,7 +221,9 @@ app:iconTint="@color/fontAppbar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@id/switch_account_button" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + android:visibility="gone" + tools:visibility="visible" /> From f5edaa0b734f3ff6ab40d1954863f1f8ea4c3630 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 10 Jun 2026 10:56:04 +0200 Subject: [PATCH 6/6] fix lifecycle crash for initialize adapter Signed-off-by: alperozturk96 --- .../android/ui/fragment/notifications/NotificationsFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt index fdae22ca5262..7fe9a3bf27ff 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/notifications/NotificationsFragment.kt @@ -271,7 +271,6 @@ class NotificationsFragment : // region Data loading private fun fetchAndSetData(client: NextcloudClient) { lifecycleScope.launch(Dispatchers.IO) { - initializeAdapter() val result = GetNotificationsRemoteOperation().execute(client) withContext(Dispatchers.Main) { state = when {