diff --git a/app/src/main/java/org/tasks/preferences/fragments/ScrollableWidget.kt b/app/src/main/java/org/tasks/preferences/fragments/ScrollableWidget.kt index 44862399a..bfb63c15d 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/ScrollableWidget.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/ScrollableWidget.kt @@ -4,9 +4,11 @@ import android.app.Activity import android.appwidget.AppWidgetManager import android.content.Intent import android.os.Bundle +import androidx.lifecycle.lifecycleScope import androidx.preference.* import com.todoroo.astrid.api.Filter import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.R import org.tasks.activities.FilterSelectionActivity @@ -93,10 +95,12 @@ class ScrollableWidget : InjectingPreferenceFragment() { findPreference(R.string.p_widget_filter) .setOnPreferenceClickListener { - val intent = Intent(context, FilterSelectionActivity::class.java) - intent.putExtra(FilterSelectionActivity.EXTRA_FILTER, getFilter()) - intent.putExtra(FilterSelectionActivity.EXTRA_RETURN_FILTER, true) - startActivityForResult(intent, REQUEST_FILTER) + lifecycleScope.launch { + val intent = Intent(context, FilterSelectionActivity::class.java) + intent.putExtra(FilterSelectionActivity.EXTRA_FILTER, getFilter()) + intent.putExtra(FilterSelectionActivity.EXTRA_RETURN_FILTER, true) + startActivityForResult(intent, REQUEST_FILTER) + } false } @@ -166,12 +170,12 @@ class ScrollableWidget : InjectingPreferenceFragment() { tintColorPreference(R.string.p_widget_color_v2, widgetPreferences.color) } - private fun updateFilter() { - findPreference(R.string.p_widget_filter).summary = getFilter()!!.listingTitle + private fun updateFilter() = lifecycleScope.launch { + findPreference(R.string.p_widget_filter).summary = getFilter().listingTitle } - private fun getFilter(): Filter? { - return defaultFilterProvider.getFilterFromPreferenceBlocking(widgetPreferences.filterId) + private suspend fun getFilter(): Filter { + return defaultFilterProvider.getFilterFromPreference(widgetPreferences.filterId) } private fun setupSlider(resId: Int, defValue: Int): SeekBarPreference { diff --git a/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.kt b/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.kt index 0cb2d1ebe..60f875e08 100644 --- a/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.kt +++ b/app/src/main/java/org/tasks/widget/ScrollableViewsFactory.kt @@ -12,12 +12,12 @@ import com.todoroo.astrid.api.Filter import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task import com.todoroo.astrid.subtasks.SubtasksHelper +import kotlinx.coroutines.runBlocking import org.tasks.BuildConfig import org.tasks.R import org.tasks.data.SubtaskInfo import org.tasks.data.TaskContainer import org.tasks.data.TaskListQuery.getQuery -import org.tasks.data.runBlocking import org.tasks.locale.Locale import org.tasks.preferences.DefaultFilterProvider import org.tasks.preferences.Preferences @@ -59,10 +59,10 @@ internal class ScrollableViewsFactory( override fun onCreate() {} override fun onDataSetChanged() { - updateSettings() - tasks = runBlocking { - taskDao.fetchTasks { - subtasks: SubtaskInfo -> getQuery(filter, subtasks) + runBlocking { + updateSettings() + tasks = taskDao.fetchTasks { subtasks: SubtaskInfo -> + getQuery(filter, subtasks) } } } @@ -239,7 +239,7 @@ internal class ScrollableViewsFactory( } } - private fun updateSettings() { + private suspend fun updateSettings() { val widgetPreferences = WidgetPreferences(context, preferences, widgetId) vPad = widgetPreferences.widgetSpacing hPad = context.resources.getDimension(R.dimen.widget_padding).toInt() @@ -256,7 +256,7 @@ internal class ScrollableViewsFactory( showCheckboxes = widgetPreferences.showCheckboxes() textSize = widgetPreferences.fontSize.toFloat() dueDateTextSize = max(10f, textSize - 2) - filter = defaultFilterProvider.getFilterFromPreferenceBlocking(widgetPreferences.filterId) + filter = defaultFilterProvider.getFilterFromPreference(widgetPreferences.filterId) showDividers = widgetPreferences.showDividers() showSubtasks = widgetPreferences.showSubtasks() isRtl = locale.directionality == View.LAYOUT_DIRECTION_RTL @@ -265,6 +265,5 @@ internal class ScrollableViewsFactory( init { val metrics = context.resources.displayMetrics indentPadding = (20 * metrics.density).toInt() - updateSettings() } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/widget/TasksWidget.java b/app/src/main/java/org/tasks/widget/TasksWidget.java deleted file mode 100644 index 11677646d..000000000 --- a/app/src/main/java/org/tasks/widget/TasksWidget.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.tasks.widget; - -import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; -import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; -import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.view.View; -import android.widget.RemoteViews; -import androidx.annotation.ColorInt; -import androidx.core.graphics.ColorUtils; -import com.todoroo.astrid.api.Filter; -import com.todoroo.astrid.dao.TaskDaoBlocking; -import dagger.hilt.android.AndroidEntryPoint; -import dagger.hilt.android.qualifiers.ApplicationContext; -import javax.inject.Inject; -import org.tasks.R; -import org.tasks.activities.FilterSelectionActivity; -import org.tasks.intents.TaskIntents; -import org.tasks.locale.Locale; -import org.tasks.preferences.DefaultFilterProvider; -import org.tasks.preferences.Preferences; -import org.tasks.themes.ThemeColor; -import timber.log.Timber; - -@AndroidEntryPoint -public class TasksWidget extends AppWidgetProvider { - - private static final int flags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP; - @Inject Preferences preferences; - @Inject DefaultFilterProvider defaultFilterProvider; - @Inject Locale locale; - @Inject TaskDaoBlocking taskDao; - @Inject @ApplicationContext Context context; - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - for (int id : appWidgetIds) { - try { - appWidgetManager.updateAppWidget(id, createScrollableWidget(context, id)); - } catch (Exception e) { - Timber.e(e); - } - } - } - - private RemoteViews createScrollableWidget(Context context, int id) { - WidgetPreferences widgetPreferences = new WidgetPreferences(context, preferences, id); - String filterId = widgetPreferences.getFilterId(); - ThemeColor color = new ThemeColor(context, widgetPreferences.getColor()); - RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.scrollable_widget); - remoteViews.setInt(R.id.widget, "setLayoutDirection", locale.getDirectionality()); - if (widgetPreferences.showHeader()) { - remoteViews.setViewVisibility(R.id.widget_header, View.VISIBLE); - remoteViews.setViewVisibility( - R.id.widget_change_list, widgetPreferences.showMenu() ? View.VISIBLE : View.GONE); - int widgetTitlePadding = - widgetPreferences.showMenu() - ? 0 - : (int) context.getResources().getDimension(R.dimen.widget_padding); - remoteViews.setViewPadding(R.id.widget_title, widgetTitlePadding, 0, 0, 0); - remoteViews.setViewVisibility( - R.id.widget_reconfigure, widgetPreferences.showSettings() ? View.VISIBLE : View.GONE); - remoteViews.setInt(R.id.widget_title, "setTextColor", color.getColorOnPrimary()); - remoteViews.setInt(R.id.widget_button, "setColorFilter", color.getColorOnPrimary()); - remoteViews.setInt(R.id.widget_reconfigure, "setColorFilter", color.getColorOnPrimary()); - remoteViews.setInt(R.id.widget_change_list, "setColorFilter", color.getColorOnPrimary()); - } else { - remoteViews.setViewVisibility(R.id.widget_header, View.GONE); - } - - remoteViews.setInt( - R.id.widget_header, - "setBackgroundColor", - ColorUtils.setAlphaComponent(color.getPrimaryColor(), widgetPreferences.getHeaderOpacity())); - int bgColor = getBackgroundColor(widgetPreferences.getThemeIndex()); - remoteViews.setInt( - R.id.list_view, - "setBackgroundColor", - ColorUtils.setAlphaComponent(bgColor, widgetPreferences.getRowOpacity())); - remoteViews.setInt( - R.id.empty_view, - "setBackgroundColor", - ColorUtils.setAlphaComponent(bgColor, widgetPreferences.getFooterOpacity())); - - Filter filter = defaultFilterProvider.getFilterFromPreferenceBlocking(filterId); - remoteViews.setTextViewText(R.id.widget_title, filter.listingTitle); - - Uri cacheBuster = Uri.parse("tasks://widget/" + System.currentTimeMillis()); - remoteViews.setRemoteAdapter( - R.id.list_view, - new Intent(context, ScrollableWidgetUpdateService.class) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id) - .setData(cacheBuster)); - - setRipple( - remoteViews, color, R.id.widget_button, R.id.widget_change_list, R.id.widget_reconfigure); - remoteViews.setOnClickPendingIntent(R.id.widget_title, getOpenListIntent(context, filter, id)); - remoteViews.setOnClickPendingIntent(R.id.widget_button, getNewTaskIntent(context, filter, id)); - remoteViews.setOnClickPendingIntent(R.id.widget_change_list, getChooseListIntent(context, filter, id)); - remoteViews.setOnClickPendingIntent( - R.id.widget_reconfigure, getWidgetConfigIntent(context, id)); - if (widgetPreferences.openOnFooterClick()) { - remoteViews.setOnClickPendingIntent(R.id.empty_view, getOpenListIntent(context, filter, id)); - } else { - remoteViews.setOnClickPendingIntent(R.id.empty_view, null); - } - remoteViews.setPendingIntentTemplate(R.id.list_view, getPendingIntentTemplate(context)); - return remoteViews; - } - - private void setRipple(RemoteViews rv, ThemeColor color, int... views) { - int drawableRes = - color.isDark() - ? R.drawable.widget_ripple_circle_light - : R.drawable.widget_ripple_circle_dark; - for (int view : views) { - rv.setInt(view, "setBackgroundResource", drawableRes); - } - } - - private @ColorInt int getBackgroundColor(int themeIndex) { - int background; - if (themeIndex == 1) { - background = android.R.color.black; - } else if (themeIndex == 2) { - background = R.color.md_background_dark; - } else { - background = android.R.color.white; - } - return context.getColor(background); - } - - private PendingIntent getPendingIntentTemplate(Context context) { - return PendingIntent.getActivity( - context, 0, new Intent(context, WidgetClickActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); - } - - private PendingIntent getOpenListIntent(Context context, Filter filter, int widgetId) { - Intent intent = TaskIntents.getTaskListIntent(context, filter); - intent.setFlags(flags); - intent.setAction("open_list"); - return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT); - } - - private PendingIntent getNewTaskIntent(Context context, Filter filter, int widgetId) { - Intent intent = TaskIntents.getNewTaskIntent(context, filter); - intent.setAction("new_task"); - return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT); - } - - private PendingIntent getWidgetConfigIntent(Context context, final int widgetId) { - Intent intent = new Intent(context, WidgetConfigActivity.class); - intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); - intent.setAction("widget_settings"); - return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT); - } - - private PendingIntent getChooseListIntent(Context context, Filter filter, int widgetId) { - Intent intent = new Intent(context, FilterSelectionActivity.class); - intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); - intent.putExtra(FilterSelectionActivity.EXTRA_FILTER, filter); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); - intent.setAction("choose_list"); - return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT); - } -} diff --git a/app/src/main/java/org/tasks/widget/TasksWidget.kt b/app/src/main/java/org/tasks/widget/TasksWidget.kt new file mode 100644 index 000000000..940709237 --- /dev/null +++ b/app/src/main/java/org/tasks/widget/TasksWidget.kt @@ -0,0 +1,157 @@ +package org.tasks.widget + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.view.View +import android.widget.RemoteViews +import androidx.annotation.ColorInt +import androidx.core.graphics.ColorUtils +import com.todoroo.astrid.api.Filter +import dagger.hilt.android.AndroidEntryPoint +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.runBlocking +import org.tasks.R +import org.tasks.activities.FilterSelectionActivity +import org.tasks.intents.TaskIntents +import org.tasks.locale.Locale +import org.tasks.preferences.DefaultFilterProvider +import org.tasks.preferences.Preferences +import org.tasks.themes.ThemeColor +import timber.log.Timber +import javax.inject.Inject + +@AndroidEntryPoint +class TasksWidget : AppWidgetProvider() { + @Inject lateinit var preferences: Preferences + @Inject lateinit var defaultFilterProvider: DefaultFilterProvider + @Inject lateinit var locale: Locale + @Inject @ApplicationContext lateinit var context: Context + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + for (id in appWidgetIds) { + try { + appWidgetManager.updateAppWidget(id, createScrollableWidget(context, id)) + } catch (e: Exception) { + Timber.e(e) + } + } + } + + private fun createScrollableWidget(context: Context, id: Int): RemoteViews { + val widgetPreferences = WidgetPreferences(context, preferences, id) + val filterId = widgetPreferences.filterId + val color = ThemeColor(context, widgetPreferences.color) + val remoteViews = RemoteViews(context.packageName, R.layout.scrollable_widget) + remoteViews.setInt(R.id.widget, "setLayoutDirection", locale.directionality) + if (widgetPreferences.showHeader()) { + remoteViews.setViewVisibility(R.id.widget_header, View.VISIBLE) + remoteViews.setViewVisibility( + R.id.widget_change_list, if (widgetPreferences.showMenu()) View.VISIBLE else View.GONE) + val widgetTitlePadding = if (widgetPreferences.showMenu()) 0 else context.resources.getDimension(R.dimen.widget_padding).toInt() + remoteViews.setViewPadding(R.id.widget_title, widgetTitlePadding, 0, 0, 0) + remoteViews.setViewVisibility( + R.id.widget_reconfigure, if (widgetPreferences.showSettings()) View.VISIBLE else View.GONE) + remoteViews.setInt(R.id.widget_title, "setTextColor", color.colorOnPrimary) + remoteViews.setInt(R.id.widget_button, "setColorFilter", color.colorOnPrimary) + remoteViews.setInt(R.id.widget_reconfigure, "setColorFilter", color.colorOnPrimary) + remoteViews.setInt(R.id.widget_change_list, "setColorFilter", color.colorOnPrimary) + } else { + remoteViews.setViewVisibility(R.id.widget_header, View.GONE) + } + remoteViews.setInt( + R.id.widget_header, + "setBackgroundColor", + ColorUtils.setAlphaComponent(color.primaryColor, widgetPreferences.headerOpacity)) + val bgColor = getBackgroundColor(widgetPreferences.themeIndex) + remoteViews.setInt( + R.id.list_view, + "setBackgroundColor", + ColorUtils.setAlphaComponent(bgColor, widgetPreferences.rowOpacity)) + remoteViews.setInt( + R.id.empty_view, + "setBackgroundColor", + ColorUtils.setAlphaComponent(bgColor, widgetPreferences.footerOpacity)) + val filter = runBlocking { defaultFilterProvider.getFilterFromPreference(filterId) } + remoteViews.setTextViewText(R.id.widget_title, filter.listingTitle) + val cacheBuster = Uri.parse("tasks://widget/" + System.currentTimeMillis()) + remoteViews.setRemoteAdapter( + R.id.list_view, + Intent(context, ScrollableWidgetUpdateService::class.java) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id) + .setData(cacheBuster)) + setRipple( + remoteViews, color, R.id.widget_button, R.id.widget_change_list, R.id.widget_reconfigure) + remoteViews.setOnClickPendingIntent(R.id.widget_title, getOpenListIntent(context, filter, id)) + remoteViews.setOnClickPendingIntent(R.id.widget_button, getNewTaskIntent(context, filter, id)) + remoteViews.setOnClickPendingIntent(R.id.widget_change_list, getChooseListIntent(context, filter, id)) + remoteViews.setOnClickPendingIntent( + R.id.widget_reconfigure, getWidgetConfigIntent(context, id)) + if (widgetPreferences.openOnFooterClick()) { + remoteViews.setOnClickPendingIntent(R.id.empty_view, getOpenListIntent(context, filter, id)) + } else { + remoteViews.setOnClickPendingIntent(R.id.empty_view, null) + } + remoteViews.setPendingIntentTemplate(R.id.list_view, getPendingIntentTemplate(context)) + return remoteViews + } + + private fun setRipple(rv: RemoteViews, color: ThemeColor, vararg views: Int) { + val drawableRes = if (color.isDark) R.drawable.widget_ripple_circle_light else R.drawable.widget_ripple_circle_dark + for (view in views) { + rv.setInt(view, "setBackgroundResource", drawableRes) + } + } + + @ColorInt + private fun getBackgroundColor(themeIndex: Int): Int { + val background: Int = when (themeIndex) { + 1 -> android.R.color.black + 2 -> R.color.md_background_dark + else -> android.R.color.white + } + return context.getColor(background) + } + + private fun getPendingIntentTemplate(context: Context): PendingIntent { + return PendingIntent.getActivity( + context, 0, Intent(context, WidgetClickActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT) + } + + private fun getOpenListIntent(context: Context, filter: Filter, widgetId: Int): PendingIntent { + val intent = TaskIntents.getTaskListIntent(context, filter) + intent.flags = flags + intent.action = "open_list" + return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + private fun getNewTaskIntent(context: Context, filter: Filter, widgetId: Int): PendingIntent { + val intent = TaskIntents.getNewTaskIntent(context, filter) + intent.action = "new_task" + return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + private fun getWidgetConfigIntent(context: Context, widgetId: Int): PendingIntent { + val intent = Intent(context, WidgetConfigActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId) + intent.action = "widget_settings" + return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + private fun getChooseListIntent(context: Context, filter: Filter, widgetId: Int): PendingIntent { + val intent = Intent(context, FilterSelectionActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + intent.putExtra(FilterSelectionActivity.EXTRA_FILTER, filter) + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId) + intent.action = "choose_list" + return PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + companion object { + private const val flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + } +} \ No newline at end of file