From 37802f23a35d034870ba196ff163ea76ae204468 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 22 Jul 2025 16:01:17 +0200 Subject: [PATCH 1/7] Rename .java to .kt Signed-off-by: alperozturk --- .../{NoteListWidgetFactory.java => NoteListWidgetFactory.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/{NoteListWidgetFactory.java => NoteListWidgetFactory.kt} (100%) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.java b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt similarity index 100% rename from app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.java rename to app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt From 8cec32cedb9a0f131074c1ba703167927538a851 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 22 Jul 2025 16:01:18 +0200 Subject: [PATCH 2/7] NoteListWidgetFactory npe checks Signed-off-by: alperozturk --- .../widget/notelist/NoteListWidgetFactory.kt | 354 ++++++++++-------- 1 file changed, 198 insertions(+), 156 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt index 939973a37..cfe3b8ddb 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt @@ -1,207 +1,249 @@ /* * Nextcloud Notes - Android Client * - * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2017-2025 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ -package it.niedermann.owncloud.notes.widget.notelist; - -import static it.niedermann.owncloud.notes.edit.EditNoteActivity.PARAM_CATEGORY; -import static it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData.MODE_DISPLAY_ALL; -import static it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData.MODE_DISPLAY_CATEGORY; -import static it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData.MODE_DISPLAY_STARRED; - -import android.appwidget.AppWidgetManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.widget.RemoteViews; -import android.widget.RemoteViewsService; - -import androidx.annotation.NonNull; -import androidx.core.content.ContextCompat; - -import java.util.ArrayList; -import java.util.List; - -import it.niedermann.owncloud.notes.R; -import it.niedermann.owncloud.notes.edit.EditNoteActivity; -import it.niedermann.owncloud.notes.main.MainActivity; -import it.niedermann.owncloud.notes.persistence.NotesRepository; -import it.niedermann.owncloud.notes.persistence.entity.Account; -import it.niedermann.owncloud.notes.persistence.entity.Note; -import it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData; -import it.niedermann.owncloud.notes.shared.model.ENavigationCategoryType; -import it.niedermann.owncloud.notes.shared.model.NavigationCategory; -import it.niedermann.owncloud.notes.shared.util.NotesColorUtil; - -public class NoteListWidgetFactory implements RemoteViewsService.RemoteViewsFactory { - private static final String TAG = NoteListWidgetFactory.class.getSimpleName(); - - private final Context context; - private final int appWidgetId; - private final NotesRepository repo; - @NonNull - private final List dbNotes = new ArrayList<>(); - private NotesListWidgetData data; - - NoteListWidgetFactory(Context context, Intent intent) { - this.context = context; - this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - repo = NotesRepository.getInstance(context); - } - - @Override - public void onCreate() { +package it.niedermann.owncloud.notes.widget.notelist + +import android.appwidget.AppWidgetManager +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.widget.RemoteViews +import android.widget.RemoteViewsService.RemoteViewsFactory +import androidx.core.content.ContextCompat +import it.niedermann.owncloud.notes.R +import it.niedermann.owncloud.notes.edit.EditNoteActivity +import it.niedermann.owncloud.notes.main.MainActivity +import it.niedermann.owncloud.notes.persistence.NotesRepository +import it.niedermann.owncloud.notes.persistence.entity.Account +import it.niedermann.owncloud.notes.persistence.entity.Note +import it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData +import it.niedermann.owncloud.notes.shared.model.ENavigationCategoryType +import it.niedermann.owncloud.notes.shared.model.NavigationCategory +import it.niedermann.owncloud.notes.shared.util.NotesColorUtil +import androidx.core.net.toUri + +class NoteListWidgetFactory internal constructor(private val context: Context, intent: Intent) : + RemoteViewsFactory { + private val appWidgetId: Int = intent.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) + private val repo: NotesRepository = NotesRepository.getInstance(context) + private val dbNotes: MutableList = ArrayList() + private var data: NotesListWidgetData? = null + + override fun onCreate() { // Nothing to do here… } - @Override - public void onDataSetChanged() { - dbNotes.clear(); + override fun onDataSetChanged() { + dbNotes.clear() try { - data = repo.getNoteListWidgetData(appWidgetId); + data = repo.getNoteListWidgetData(appWidgetId) if (data == null) { - Log.w(TAG, "Widget data is null"); - return; + Log.w(TAG, "Widget data is null") + return } - - Log.v(TAG, "--- data - " + data); - switch (data.getMode()) { - case MODE_DISPLAY_ALL -> - dbNotes.addAll(repo.searchRecentByModified(data.getAccountId(), "%")); - case MODE_DISPLAY_STARRED -> - dbNotes.addAll(repo.searchFavoritesByModified(data.getAccountId(), "%")); - default -> { - if (data.getCategory() != null) { - dbNotes.addAll(repo.searchCategoryByModified(data.getAccountId(), "%", data.getCategory())); + val widgetData = data ?: return + + Log.v(TAG, "--- data - $widgetData") + + when (widgetData.mode) { + NotesListWidgetData.MODE_DISPLAY_ALL -> dbNotes.addAll( + repo.searchRecentByModified( + widgetData.accountId, "%" + ) + ) + + NotesListWidgetData.MODE_DISPLAY_STARRED -> dbNotes.addAll( + repo.searchFavoritesByModified( + widgetData.accountId, "%" + ) + ) + + else -> { + if (widgetData.category != null) { + dbNotes.addAll( + repo.searchCategoryByModified( + widgetData.accountId, + "%", + widgetData.category + ) + ) } else { - dbNotes.addAll(repo.searchUncategorizedByModified(data.getAccountId(), "%")); + dbNotes.addAll( + repo.searchUncategorizedByModified( + widgetData.accountId, + "%" + ) + ) } } } - } catch (Exception e) { - Log.w(TAG, "Error caught at onDataSetChanged: " + e); + } catch (e: Exception) { + Log.w(TAG, "Error caught at onDataSetChanged: $e") } } - @Override - public void onDestroy() { + override fun onDestroy() { //NoOp } - @Override - public int getCount() { - return dbNotes.size() + 1; + override fun getCount(): Int { + return dbNotes.size + 1 } - private Intent getEditNoteIntent(Bundle bundle) { - final Intent intent = new Intent(context, EditNoteActivity.class); - intent.setPackage(context.getPackageName()); - intent.putExtras(bundle); - intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); - - return intent; + private fun getEditNoteIntent(bundle: Bundle): Intent { + return Intent(context, EditNoteActivity::class.java).apply { + setPackage(context.packageName) + putExtras(bundle) + setData(toUri(Intent.URI_INTENT_SCHEME).toUri()) + } } - private Intent getCreateNoteIntent(Account localAccount ) { - final Bundle bundle = new Bundle(); - bundle.putSerializable(PARAM_CATEGORY, data.getMode() == MODE_DISPLAY_STARRED ? new NavigationCategory(ENavigationCategoryType.FAVORITES) : new NavigationCategory(localAccount.getId(), data.getCategory())); - bundle.putLong(EditNoteActivity.PARAM_ACCOUNT_ID, data.getAccountId()); + private fun getCreateNoteIntent(localAccount: Account): Intent { + val bundle = Bundle() - return getEditNoteIntent(bundle); - } + data?.let { + val navigationCategory = if (it.mode == NotesListWidgetData.MODE_DISPLAY_STARRED) NavigationCategory( + ENavigationCategoryType.FAVORITES + ) else NavigationCategory(localAccount.id, it.category) - private Intent getOpenNoteIntent(Note note) { - final Bundle bundle = new Bundle(); - bundle.putLong(EditNoteActivity.PARAM_NOTE_ID, note.getId()); - bundle.putLong(EditNoteActivity.PARAM_ACCOUNT_ID, note.getAccountId()); + bundle.putSerializable(EditNoteActivity.PARAM_CATEGORY, navigationCategory) + bundle.putLong(EditNoteActivity.PARAM_ACCOUNT_ID, it.accountId) + } - return getEditNoteIntent(bundle); + return getEditNoteIntent(bundle) } - @Override - public RemoteViews getViewAt(int position) { - final RemoteViews note_content; - - if (position == 0) { - final Account localAccount = repo.getAccountById(data.getAccountId()); - - final Intent createNoteIntent = getCreateNoteIntent(localAccount); - final Intent openIntent = new Intent(Intent.ACTION_MAIN).setComponent(new ComponentName(context.getPackageName(), MainActivity.class.getName())); - - note_content = new RemoteViews(context.getPackageName(), R.layout.widget_entry_add); - note_content.setOnClickFillInIntent(R.id.widget_entry_content_tv, openIntent); - note_content.setOnClickFillInIntent(R.id.widget_entry_fav_icon, createNoteIntent); - note_content.setTextViewText(R.id.widget_entry_content_tv, getCategoryTitle(context, data.getMode(), data.getCategory())); - note_content.setImageViewResource(R.id.widget_entry_fav_icon, R.drawable.ic_add_blue_24dp); - note_content.setInt(R.id.widget_entry_fav_icon, "setColorFilter", NotesColorUtil.contrastRatioIsSufficient(ContextCompat.getColor(context, R.color.widget_background), localAccount.getColor()) - ? localAccount.getColor() - : ContextCompat.getColor(context, R.color.widget_foreground)); - } else { - position--; - if (position > dbNotes.size() - 1 || dbNotes.get(position) == null) { - Log.e(TAG, "Could not find position \"" + position + "\" in dbNotes list."); - return null; - } + private fun getOpenNoteIntent(note: Note): Intent { + val bundle = Bundle().apply { + putLong(EditNoteActivity.PARAM_NOTE_ID, note.id) + putLong(EditNoteActivity.PARAM_ACCOUNT_ID, note.accountId) + } - final Note note = dbNotes.get(position); - final Intent openNoteIntent = getOpenNoteIntent(note); + return getEditNoteIntent(bundle) + } - note_content = new RemoteViews(context.getPackageName(), R.layout.widget_entry); - note_content.setOnClickFillInIntent(R.id.widget_note_list_entry, openNoteIntent); - note_content.setTextViewText(R.id.widget_entry_content_tv, note.getTitle()); - note_content.setImageViewResource(R.id.widget_entry_fav_icon, note.getFavorite() - ? R.drawable.ic_star_yellow_24dp - : R.drawable.ic_star_grey_ccc_24dp); + private fun getRemoteViewFromData(): RemoteViews? { + val widgetData = data ?: return null + + val localAccount = repo.getAccountById(widgetData.accountId) + val createNoteIntent = getCreateNoteIntent(localAccount) + val openIntent = Intent(Intent.ACTION_MAIN).setComponent( + ComponentName( + context.packageName, + MainActivity::class.java.getName() + ) + ) + + return RemoteViews(context.packageName, R.layout.widget_entry_add).apply { + setOnClickFillInIntent(R.id.widget_entry_content_tv, openIntent) + setOnClickFillInIntent(R.id.widget_entry_fav_icon, createNoteIntent) + setTextViewText( + R.id.widget_entry_content_tv, + getCategoryTitle(context, widgetData.mode, widgetData.category) + ) + setImageViewResource( + R.id.widget_entry_fav_icon, + R.drawable.ic_add_blue_24dp + ) + setInt( + R.id.widget_entry_fav_icon, + "setColorFilter", + if (NotesColorUtil.contrastRatioIsSufficient( + ContextCompat.getColor( + context, + R.color.widget_background + ), localAccount.color + ) + ) + localAccount.color + else + ContextCompat.getColor(context, R.color.widget_foreground) + ) } + } - return note_content; + private fun getRemoteViewFromPosition(position: Int): RemoteViews? { + var position = position + position-- + if (position < 0 || position >= dbNotes.size) { + Log.e(TAG, "Could not find position \"$position\" in dbNotes list.") + return null + } + val note = dbNotes[position] + val openNoteIntent = getOpenNoteIntent(note) + + return RemoteViews(context.packageName, R.layout.widget_entry).apply { + setOnClickFillInIntent(R.id.widget_note_list_entry, openNoteIntent) + setTextViewText(R.id.widget_entry_content_tv, note.title) + setImageViewResource( + R.id.widget_entry_fav_icon, if (note.favorite) + R.drawable.ic_star_yellow_24dp + else + R.drawable.ic_star_grey_ccc_24dp + ) + } } - @NonNull - private static String getCategoryTitle(@NonNull Context context, int displayMode, String category) { - return switch (displayMode) { - case MODE_DISPLAY_STARRED -> - context.getString(R.string.label_favorites); - case MODE_DISPLAY_CATEGORY -> - "".equals(category) - ? context.getString(R.string.action_uncategorized) - : category; - default -> context.getString(R.string.app_name); - }; + override fun getViewAt(position: Int): RemoteViews? { + return if (position == 0 && data != null) { + getRemoteViewFromData() + } else { + getRemoteViewFromPosition(position) + } } - @Override - public RemoteViews getLoadingView() { - return null; + override fun getLoadingView(): RemoteViews? { + return null } - @Override - public int getViewTypeCount() { - return 2; + override fun getViewTypeCount(): Int { + return 2 } - @Override - public long getItemId(int position) { + override fun getItemId(position: Int): Long { + var position = position if (position == 0) { - return -1; + return -1 } else { - position--; - if (position > dbNotes.size() - 1 || dbNotes.get(position) == null) { - Log.e(TAG, "Could not find position \"" + position + "\" in dbNotes list."); - return -2; + position-- + if (position > dbNotes.size - 1 || dbNotes.get(position) == null) { + Log.e(TAG, "Could not find position \"" + position + "\" in dbNotes list.") + return -2 } - return dbNotes.get(position).getId(); + return dbNotes[position].id } } - @Override - public boolean hasStableIds() { - return true; + override fun hasStableIds(): Boolean { + return true + } + + companion object { + private val TAG: String = NoteListWidgetFactory::class.java.getSimpleName() + + private fun getCategoryTitle( + context: Context, + displayMode: Int, + category: String? + ): String { + return when (displayMode) { + NotesListWidgetData.MODE_DISPLAY_STARRED -> context.getString(R.string.label_favorites) + NotesListWidgetData.MODE_DISPLAY_CATEGORY -> if ("" == category) + context.getString(R.string.action_uncategorized) + else + category + + else -> context.getString(R.string.app_name) + }!! + } } } From 2a58c63e3c6a8178183a718266f5e31a5045d52a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 22 Jul 2025 16:48:38 +0200 Subject: [PATCH 3/7] Rename .java to .kt Signed-off-by: alperozturk --- .../widget/notelist/{NoteListWidget.java => NoteListWidget.kt} | 0 .../singlenote/{SingleNoteWidget.java => SingleNoteWidget.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/{NoteListWidget.java => NoteListWidget.kt} (100%) rename app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/{SingleNoteWidget.java => SingleNoteWidget.kt} (100%) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidget.kt similarity index 100% rename from app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidget.java rename to app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidget.kt diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.java b/app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.kt similarity index 100% rename from app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.java rename to app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.kt From 992ff991a61f40a751d4fdfb949eb5c94ab40804 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 22 Jul 2025 16:48:39 +0200 Subject: [PATCH 4/7] fix Signed-off-by: alperozturk --- app/src/main/AndroidManifest.xml | 6 +- .../notes/widget/notelist/NoteListWidget.kt | 203 ++++++++++-------- .../widget/notelist/NoteListWidgetFactory.kt | 127 +++-------- .../widget/singlenote/SingleNoteWidget.kt | 160 +++++++------- app/src/main/res/layout/widget_note_list.xml | 2 +- 5 files changed, 229 insertions(+), 269 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a43f4dba..309541c56 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -174,11 +174,13 @@ + android:permission="android.permission.BIND_REMOTEVIEWS" + android:exported="false"/> + android:permission="android.permission.BIND_REMOTEVIEWS" + android:exported="false"/> repo.removeNoteListWidget(appWidgetId)); + for (appWidgetId in appWidgetIds) { + executor.submit(Runnable { repo.removeNoteListWidget(appWidgetId) }) } } - /** - * Update note list widgets, if the note data was changed. - */ - public static void updateNoteListWidgets(Context context) { - context.sendBroadcast(new Intent(context, NoteListWidget.class).setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)); + companion object { + private val TAG: String = NoteListWidget::class.java.getSimpleName() + fun updateAppWidget(context: Context, awm: AppWidgetManager, appWidgetIds: IntArray) { + val repo = NotesRepository.getInstance(context) + appWidgetIds.forEach { appWidgetId -> + repo.getNoteListWidgetData(appWidgetId)?.let { data -> + val serviceIntent = Intent(context, NoteListWidgetService::class.java).apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + setData(toUri(Intent.URI_INTENT_SCHEME).toUri()) + } + + + Log.v(TAG, "-- data - $data") + + val editNoteIntent = Intent(context, EditNoteActivity::class.java).apply { + setPackage(context.packageName) + } + + val pendingIntentFlags = + WidgetUtil.pendingIntentFlagCompat(PendingIntent.FLAG_UPDATE_CURRENT or Intent.FILL_IN_COMPONENT) + val editNotePendingIntent = + PendingIntent.getActivity(context, 0, editNoteIntent, pendingIntentFlags) + + val views = RemoteViews(context.packageName, R.layout.widget_note_list).apply { + setRemoteAdapter(R.id.note_list_widget_lv, serviceIntent) + setPendingIntentTemplate(R.id.note_list_widget_lv, editNotePendingIntent) + setEmptyView( + R.id.note_list_widget_lv, + R.id.widget_note_list_placeholder_tv + ) + } + + awm.run { + updateAppWidget(appWidgetId, views) + notifyAppWidgetViewDataChanged(appWidgetId, R.id.note_list_widget_lv) + } + } + } + } + + @JvmStatic + fun updateNoteListWidgets(context: Context) { + val intent = Intent(context, NoteListWidget::class.java).apply { + setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE) + } + context.sendBroadcast(intent) + } } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt index cfe3b8ddb..5d0f1dddf 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt @@ -7,25 +7,21 @@ package it.niedermann.owncloud.notes.widget.notelist import android.appwidget.AppWidgetManager -import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.widget.RemoteViews import android.widget.RemoteViewsService.RemoteViewsFactory -import androidx.core.content.ContextCompat +import androidx.core.net.toUri import it.niedermann.owncloud.notes.R import it.niedermann.owncloud.notes.edit.EditNoteActivity -import it.niedermann.owncloud.notes.main.MainActivity import it.niedermann.owncloud.notes.persistence.NotesRepository import it.niedermann.owncloud.notes.persistence.entity.Account import it.niedermann.owncloud.notes.persistence.entity.Note import it.niedermann.owncloud.notes.persistence.entity.NotesListWidgetData import it.niedermann.owncloud.notes.shared.model.ENavigationCategoryType import it.niedermann.owncloud.notes.shared.model.NavigationCategory -import it.niedermann.owncloud.notes.shared.util.NotesColorUtil -import androidx.core.net.toUri class NoteListWidgetFactory internal constructor(private val context: Context, intent: Intent) : RemoteViewsFactory { @@ -37,9 +33,7 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i private val dbNotes: MutableList = ArrayList() private var data: NotesListWidgetData? = null - override fun onCreate() { - // Nothing to do here… - } + override fun onCreate() = Unit override fun onDataSetChanged() { dbNotes.clear() @@ -90,12 +84,10 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i } } - override fun onDestroy() { - //NoOp - } + override fun onDestroy() = Unit override fun getCount(): Int { - return dbNotes.size + 1 + return dbNotes.size } private fun getEditNoteIntent(bundle: Bundle): Intent { @@ -130,74 +122,41 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i return getEditNoteIntent(bundle) } - private fun getRemoteViewFromData(): RemoteViews? { - val widgetData = data ?: return null + override fun getViewAt(position: Int): RemoteViews? { + val note = dbNotes.getOrNull(position) ?: return null - val localAccount = repo.getAccountById(widgetData.accountId) - val createNoteIntent = getCreateNoteIntent(localAccount) - val openIntent = Intent(Intent.ACTION_MAIN).setComponent( - ComponentName( - context.packageName, - MainActivity::class.java.getName() - ) - ) - - return RemoteViews(context.packageName, R.layout.widget_entry_add).apply { - setOnClickFillInIntent(R.id.widget_entry_content_tv, openIntent) - setOnClickFillInIntent(R.id.widget_entry_fav_icon, createNoteIntent) - setTextViewText( - R.id.widget_entry_content_tv, - getCategoryTitle(context, widgetData.mode, widgetData.category) - ) - setImageViewResource( - R.id.widget_entry_fav_icon, - R.drawable.ic_add_blue_24dp - ) - setInt( - R.id.widget_entry_fav_icon, - "setColorFilter", - if (NotesColorUtil.contrastRatioIsSufficient( - ContextCompat.getColor( - context, - R.color.widget_background - ), localAccount.color - ) - ) - localAccount.color - else - ContextCompat.getColor(context, R.color.widget_foreground) + val openNoteIntent = getOpenNoteIntent(note) + + return RemoteViews(context.packageName, R.layout.widget_entry).apply { + setOnClickFillInIntent(R.id.widget_note_list_entry, openNoteIntent) + setTextViewText(R.id.widget_entry_content_tv, + (note.title + getCategoryTitle(context)) ) + + val starIconId = if (note.favorite) { + R.drawable.ic_star_yellow_24dp + } else { + R.drawable.ic_star_grey_ccc_24dp + } + setImageViewResource(R.id.widget_entry_fav_icon, starIconId) } } - private fun getRemoteViewFromPosition(position: Int): RemoteViews? { - var position = position - position-- - if (position < 0 || position >= dbNotes.size) { - Log.e(TAG, "Could not find position \"$position\" in dbNotes list.") + private fun getCategoryTitle(context: Context): String? { + if (data == null) { return null } - val note = dbNotes[position] - val openNoteIntent = getOpenNoteIntent(note) + val widgetData = data ?: return null - return RemoteViews(context.packageName, R.layout.widget_entry).apply { - setOnClickFillInIntent(R.id.widget_note_list_entry, openNoteIntent) - setTextViewText(R.id.widget_entry_content_tv, note.title) - setImageViewResource( - R.id.widget_entry_fav_icon, if (note.favorite) - R.drawable.ic_star_yellow_24dp - else - R.drawable.ic_star_grey_ccc_24dp - ) - } - } + return when (widgetData.mode) { + NotesListWidgetData.MODE_DISPLAY_STARRED -> context.getString(R.string.label_favorites) + NotesListWidgetData.MODE_DISPLAY_CATEGORY -> if ("" == widgetData.category) + context.getString(R.string.action_uncategorized) + else + widgetData.category - override fun getViewAt(position: Int): RemoteViews? { - return if (position == 0 && data != null) { - getRemoteViewFromData() - } else { - getRemoteViewFromPosition(position) + else -> context.getString(R.string.app_name) } } @@ -210,17 +169,7 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i } override fun getItemId(position: Int): Long { - var position = position - if (position == 0) { - return -1 - } else { - position-- - if (position > dbNotes.size - 1 || dbNotes.get(position) == null) { - Log.e(TAG, "Could not find position \"" + position + "\" in dbNotes list.") - return -2 - } - return dbNotes[position].id - } + return dbNotes[position].id } override fun hasStableIds(): Boolean { @@ -229,21 +178,5 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i companion object { private val TAG: String = NoteListWidgetFactory::class.java.getSimpleName() - - private fun getCategoryTitle( - context: Context, - displayMode: Int, - category: String? - ): String { - return when (displayMode) { - NotesListWidgetData.MODE_DISPLAY_STARRED -> context.getString(R.string.label_favorites) - NotesListWidgetData.MODE_DISPLAY_CATEGORY -> if ("" == category) - context.getString(R.string.action_uncategorized) - else - category - - else -> context.getString(R.string.app_name) - }!! - } } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.kt b/app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.kt index 954ba45b8..8c2cd829a 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/widget/singlenote/SingleNoteWidget.kt @@ -4,90 +4,98 @@ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: GPL-3.0-or-later */ -package it.niedermann.owncloud.notes.widget.singlenote; - -import static it.niedermann.owncloud.notes.shared.util.WidgetUtil.pendingIntentFlagCompat; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.util.Log; -import android.widget.RemoteViews; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import it.niedermann.owncloud.notes.R; -import it.niedermann.owncloud.notes.edit.BaseNoteFragment; -import it.niedermann.owncloud.notes.edit.EditNoteActivity; -import it.niedermann.owncloud.notes.persistence.NotesRepository; -import it.niedermann.owncloud.notes.persistence.entity.SingleNoteWidgetData; - -public class SingleNoteWidget extends AppWidgetProvider { - - private static final String TAG = SingleNoteWidget.class.getSimpleName(); - private final ExecutorService executor = Executors.newCachedThreadPool(); - - static void updateAppWidget(Context context, AppWidgetManager awm, int[] appWidgetIds) { - final var templateIntent = new Intent(context, EditNoteActivity.class); - final var repo = NotesRepository.getInstance(context); - - for (int appWidgetId : appWidgetIds) { - final var data = repo.getSingleNoteWidgetData(appWidgetId); - if (data != null) { - templateIntent.putExtra(BaseNoteFragment.PARAM_ACCOUNT_ID, data.getAccountId()); - - final var serviceIntent = new Intent(context, SingleNoteWidgetService.class); - serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))); - - final var views = new RemoteViews(context.getPackageName(), R.layout.widget_single_note); - views.setPendingIntentTemplate(R.id.single_note_widget_lv, PendingIntent.getActivity(context, appWidgetId, templateIntent, - pendingIntentFlagCompat(PendingIntent.FLAG_UPDATE_CURRENT))); - views.setRemoteAdapter(R.id.single_note_widget_lv, serviceIntent); - views.setEmptyView(R.id.single_note_widget_lv, R.id.widget_single_note_placeholder_tv); - - awm.notifyAppWidgetViewDataChanged(appWidgetId, R.id.single_note_widget_lv); - awm.updateAppWidget(appWidgetId, views); - } else { - Log.i(TAG, "onUpdate has been triggered before the user finished configuring the widget"); - } - } - } - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - super.onUpdate(context, appWidgetManager, appWidgetIds); - updateAppWidget(context, appWidgetManager, appWidgetIds); +package it.niedermann.owncloud.notes.widget.singlenote + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.widget.RemoteViews +import it.niedermann.owncloud.notes.R +import it.niedermann.owncloud.notes.edit.BaseNoteFragment +import it.niedermann.owncloud.notes.edit.EditNoteActivity +import it.niedermann.owncloud.notes.persistence.NotesRepository +import it.niedermann.owncloud.notes.shared.util.WidgetUtil +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import androidx.core.net.toUri + +class SingleNoteWidget : AppWidgetProvider() { + private val executor: ExecutorService = Executors.newCachedThreadPool() + + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray + ) { + super.onUpdate(context, appWidgetManager, appWidgetIds) + updateAppWidget(context, appWidgetManager, appWidgetIds) } - @Override - public void onReceive(Context context, Intent intent) { - super.onReceive(context, intent); - final var awm = AppWidgetManager.getInstance(context); + override fun onReceive(context: Context, intent: Intent?) { + super.onReceive(context, intent) + val awm = AppWidgetManager.getInstance(context) - updateAppWidget(context, AppWidgetManager.getInstance(context), - (awm.getAppWidgetIds(new ComponentName(context, SingleNoteWidget.class)))); + val provider = ComponentName(context, SingleNoteWidget::class.java) + val appWidgetIds = awm.getAppWidgetIds(provider) + updateAppWidget(context, awm, appWidgetIds) } - @Override - public void onDeleted(Context context, int[] appWidgetIds) { - final var repo = NotesRepository.getInstance(context); + override fun onDeleted(context: Context, appWidgetIds: IntArray) { + val repo = NotesRepository.getInstance(context) - for (int appWidgetId : appWidgetIds) { - executor.submit(() -> repo.removeSingleNoteWidget(appWidgetId)); + for (appWidgetId in appWidgetIds) { + executor.submit { repo.removeSingleNoteWidget(appWidgetId) } } - super.onDeleted(context, appWidgetIds); + super.onDeleted(context, appWidgetIds) } - /** - * Update single note widget, if the note data was changed. - */ - public static void updateSingleNoteWidgets(Context context) { - context.sendBroadcast(new Intent(context, SingleNoteWidget.class).setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)); + companion object { + private val TAG: String = SingleNoteWidget::class.java.getSimpleName() + fun updateAppWidget(context: Context, awm: AppWidgetManager, appWidgetIds: IntArray) { + val templateIntent = Intent(context, EditNoteActivity::class.java) + val repo = NotesRepository.getInstance(context) + + appWidgetIds.forEach { appWidgetId -> + repo.getSingleNoteWidgetData(appWidgetId)?.let { data -> + templateIntent.putExtra(BaseNoteFragment.PARAM_ACCOUNT_ID, data.accountId) + + val serviceIntent = Intent(context, SingleNoteWidgetService::class.java).apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + setData(toUri(Intent.URI_INTENT_SCHEME).toUri()) + } + + + val views = RemoteViews(context.packageName, R.layout.widget_single_note).apply { + setPendingIntentTemplate( + R.id.single_note_widget_lv, PendingIntent.getActivity( + context, appWidgetId, templateIntent, + WidgetUtil.pendingIntentFlagCompat(PendingIntent.FLAG_UPDATE_CURRENT) + ) + ) + setRemoteAdapter(R.id.single_note_widget_lv, serviceIntent) + setEmptyView( + R.id.single_note_widget_lv, + R.id.widget_single_note_placeholder_tv + ) + } + + awm.run { + updateAppWidget(appWidgetId, views) + notifyAppWidgetViewDataChanged(appWidgetId, R.id.single_note_widget_lv) + } + } + } + } + + @JvmStatic + fun updateSingleNoteWidgets(context: Context) { + val intent = Intent(context, SingleNoteWidget::class.java).apply { + setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE) + } + context.sendBroadcast(intent) + } } } diff --git a/app/src/main/res/layout/widget_note_list.xml b/app/src/main/res/layout/widget_note_list.xml index 844a56c98..c91ab2e55 100644 --- a/app/src/main/res/layout/widget_note_list.xml +++ b/app/src/main/res/layout/widget_note_list.xml @@ -17,7 +17,7 @@ Date: Tue, 22 Jul 2025 16:53:34 +0200 Subject: [PATCH 5/7] use category and create note intent Signed-off-by: alperozturk --- .../widget/notelist/NoteListWidgetFactory.kt | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt index 5d0f1dddf..351e8a0ce 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt @@ -127,11 +127,26 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i val openNoteIntent = getOpenNoteIntent(note) + var createNoteIntent: Intent? = null + data?.let { + val localAccount = repo.getAccountById(it.accountId) + createNoteIntent = getCreateNoteIntent(localAccount) + } + + val category = getCategoryTitle(context) + return RemoteViews(context.packageName, R.layout.widget_entry).apply { setOnClickFillInIntent(R.id.widget_note_list_entry, openNoteIntent) - setTextViewText(R.id.widget_entry_content_tv, - (note.title + getCategoryTitle(context)) - ) + + createNoteIntent?.let { + setOnClickFillInIntent(R.id.widget_entry_fav_icon, createNoteIntent) + } + + if (category != null) { + setTextViewText(R.id.widget_entry_content_tv, category) + } else { + setTextViewText(R.id.widget_entry_content_tv, note.title) + } val starIconId = if (note.favorite) { R.drawable.ic_star_yellow_24dp @@ -143,10 +158,6 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i } private fun getCategoryTitle(context: Context): String? { - if (data == null) { - return null - } - val widgetData = data ?: return null return when (widgetData.mode) { From f3832e864efc567cc8c5d7baa6cb983ddfc59914 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 22 Jul 2025 16:59:59 +0200 Subject: [PATCH 6/7] fix category Signed-off-by: alperozturk --- .../widget/notelist/NoteListWidgetFactory.kt | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt index 351e8a0ce..dd624636f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt @@ -133,8 +133,6 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i createNoteIntent = getCreateNoteIntent(localAccount) } - val category = getCategoryTitle(context) - return RemoteViews(context.packageName, R.layout.widget_entry).apply { setOnClickFillInIntent(R.id.widget_note_list_entry, openNoteIntent) @@ -142,11 +140,7 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i setOnClickFillInIntent(R.id.widget_entry_fav_icon, createNoteIntent) } - if (category != null) { - setTextViewText(R.id.widget_entry_content_tv, category) - } else { - setTextViewText(R.id.widget_entry_content_tv, note.title) - } + setTextViewText(R.id.widget_entry_content_tv, (note.title + data?.category)) val starIconId = if (note.favorite) { R.drawable.ic_star_yellow_24dp @@ -157,20 +151,6 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i } } - private fun getCategoryTitle(context: Context): String? { - val widgetData = data ?: return null - - return when (widgetData.mode) { - NotesListWidgetData.MODE_DISPLAY_STARRED -> context.getString(R.string.label_favorites) - NotesListWidgetData.MODE_DISPLAY_CATEGORY -> if ("" == widgetData.category) - context.getString(R.string.action_uncategorized) - else - widgetData.category - - else -> context.getString(R.string.app_name) - } - } - override fun getLoadingView(): RemoteViews? { return null } From 58c9dfb8722ae3a00580ee8bff93c7c2101e9e95 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 22 Jul 2025 17:18:32 +0200 Subject: [PATCH 7/7] fix category Signed-off-by: alperozturk --- .../widget/notelist/NoteListWidgetFactory.kt | 10 +++++- app/src/main/res/layout/widget_entry.xml | 32 ++++++++++++------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt index dd624636f..97f92ad94 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/widget/notelist/NoteListWidgetFactory.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log +import android.view.View import android.widget.RemoteViews import android.widget.RemoteViewsService.RemoteViewsFactory import androidx.core.net.toUri @@ -140,7 +141,14 @@ class NoteListWidgetFactory internal constructor(private val context: Context, i setOnClickFillInIntent(R.id.widget_entry_fav_icon, createNoteIntent) } - setTextViewText(R.id.widget_entry_content_tv, (note.title + data?.category)) + setTextViewText(R.id.widget_entry_title, note.title) + + if (note.category.isEmpty()) { + setViewVisibility(R.id.widget_entry_category, View.GONE) + } else { + setViewVisibility(R.id.widget_entry_category, View.VISIBLE) + setTextViewText(R.id.widget_entry_category, note.category) + } val starIconId = if (note.favorite) { R.drawable.ic_star_yellow_24dp diff --git a/app/src/main/res/layout/widget_entry.xml b/app/src/main/res/layout/widget_entry.xml index 56bcad6b1..bde69e01b 100644 --- a/app/src/main/res/layout/widget_entry.xml +++ b/app/src/main/res/layout/widget_entry.xml @@ -2,7 +2,7 @@ @@ -22,24 +23,33 @@ android:layout_height="@dimen/widget_note_list_fav_icon_height" android:layout_gravity="center_vertical" android:contentDescription="@string/widget_entry_fav_contentDescription" - android:foregroundGravity="center_vertical" android:paddingStart="@dimen/widget_note_list_inner_padding" android:paddingEnd="@dimen/widget_note_list_outer_padding" app:srcCompat="@drawable/ic_star_yellow_24dp" /> + tools:text="First note" /> +