From 4316139f52cd6047d2737bd4b6841cc89376ff4f Mon Sep 17 00:00:00 2001 From: Cristian Monforte Date: Thu, 3 Jun 2021 23:30:17 +0200 Subject: [PATCH 001/105] initial configuration: - widget manifest - configuration activity - widget class --- app/src/main/AndroidManifest.xml | 17 ++++++ .../app/WidgetThemeConfiguration.kt | 29 ++++++++++ .../app/browser/BrowserTabFragment.kt | 3 +- .../WidgetThemeConfigurationComponent.kt | 53 ++++++++++++++++++ .../widget/SearchAndFavoritesWidget.kt | 24 ++++++++ .../search_favorites_widget_preview.png | Bin 0 -> 33375 bytes .../layout/activity_widget_configuration.xml | 50 +++++++++++++++++ .../res/xml/search_favorites_widget_info.xml | 30 ++++++++++ 8 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt create mode 100644 app/src/main/java/com/duckduckgo/app/di/component/WidgetThemeConfigurationComponent.kt create mode 100644 app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt create mode 100644 app/src/main/res/drawable-nodpi/search_favorites_widget_preview.png create mode 100644 app/src/main/res/layout/activity_widget_configuration.xml create mode 100644 app/src/main/res/xml/search_favorites_widget_info.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 193cef9f5e8f..8a372a699c47 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -324,6 +324,14 @@ android:label="@string/globalPrivacyControlActivityTitle" android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity" /> + + + + + + @@ -348,6 +356,15 @@ android:resource="@xml/search_widget_info_light" /> + + + + + + + diff --git a/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt b/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt new file mode 100644 index 000000000000..41b9d982bece --- /dev/null +++ b/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app + +import android.os.Bundle +import com.duckduckgo.app.browser.R +import com.duckduckgo.app.global.DuckDuckGoActivity + +class WidgetThemeConfiguration : DuckDuckGoActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_widget_configuration) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt index 1b28cf825d9e..bebb58b13988 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt @@ -118,6 +118,7 @@ import com.duckduckgo.app.tabs.model.TabEntity import com.duckduckgo.app.tabs.ui.GridViewColumnCalculator import com.duckduckgo.app.tabs.ui.TabSwitcherActivity import com.duckduckgo.app.widget.ui.AddWidgetInstructionsActivity +import com.duckduckgo.widget.SearchAndFavoritesWidget import com.duckduckgo.widget.SearchWidgetLight import com.google.android.material.snackbar.Snackbar import dagger.android.support.AndroidSupportInjection @@ -1488,7 +1489,7 @@ class BrowserTabFragment : @SuppressLint("NewApi") private fun launchAddWidget() { val context = context ?: return - val provider = ComponentName(context, SearchWidgetLight::class.java) + val provider = ComponentName(context, SearchAndFavoritesWidget::class.java) AppWidgetManager.getInstance(context).requestPinAppWidget(provider, null, null) } diff --git a/app/src/main/java/com/duckduckgo/app/di/component/WidgetThemeConfigurationComponent.kt b/app/src/main/java/com/duckduckgo/app/di/component/WidgetThemeConfigurationComponent.kt new file mode 100644 index 000000000000..bc7f39810918 --- /dev/null +++ b/app/src/main/java/com/duckduckgo/app/di/component/WidgetThemeConfigurationComponent.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.app.di.component + +import com.duckduckgo.app.di.ActivityScoped +import com.duckduckgo.di.scopes.ActivityObjectGraph +import com.duckduckgo.di.scopes.AppObjectGraph +import com.duckduckgo.app.WidgetThemeConfiguration +import com.squareup.anvil.annotations.ContributesTo +import com.squareup.anvil.annotations.MergeSubcomponent +import dagger.Binds +import dagger.Module +import dagger.Subcomponent +import dagger.android.AndroidInjector +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@ActivityScoped +@MergeSubcomponent( + scope = ActivityObjectGraph::class +) +interface WidgetThemeConfigurationComponent : AndroidInjector { + @Subcomponent.Factory + interface Factory : AndroidInjector.Factory +} + +@ContributesTo(AppObjectGraph::class) +interface WidgetThemeConfigurationComponentProvider { + fun provideWidgetThemeConfigurationComponentFactory(): WidgetThemeConfigurationComponent.Factory +} + +@Module +@ContributesTo(AppObjectGraph::class) +abstract class WidgetThemeConfigurationBindingModule { + @Binds + @IntoMap + @ClassKey(WidgetThemeConfiguration::class) + abstract fun bindWidgetThemeConfigurationComponentFactory(factory: WidgetThemeConfigurationComponent.Factory): AndroidInjector.Factory<*> +} \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt b/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt new file mode 100644 index 000000000000..797de6928ba3 --- /dev/null +++ b/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.widget + +import android.appwidget.AppWidgetProvider + + +class SearchAndFavoritesWidget() : AppWidgetProvider() { + +} \ No newline at end of file diff --git a/app/src/main/res/drawable-nodpi/search_favorites_widget_preview.png b/app/src/main/res/drawable-nodpi/search_favorites_widget_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..9593999303800407f28d2bbce6491ec691b2d8bc GIT binary patch literal 33375 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 I#ZRIC2Xa_;`2YX_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_widget_configuration.xml b/app/src/main/res/layout/activity_widget_configuration.xml new file mode 100644 index 000000000000..686f6c63c5d6 --- /dev/null +++ b/app/src/main/res/layout/activity_widget_configuration.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/search_favorites_widget_info.xml b/app/src/main/res/xml/search_favorites_widget_info.xml new file mode 100644 index 000000000000..89f00562116a --- /dev/null +++ b/app/src/main/res/xml/search_favorites_widget_info.xml @@ -0,0 +1,30 @@ + + + + + + From ca76749ab0ad32299db39f504c863f1bad382c27 Mon Sep 17 00:00:00 2001 From: Cristian Monforte Date: Tue, 8 Jun 2021 18:57:59 +0200 Subject: [PATCH 002/105] Favorites widget created: - search bar with clickable intent - grid of items for favorites (using WidgetService) --- app/src/main/AndroidManifest.xml | 4 + .../app/WidgetThemeConfiguration.kt | 42 ++++++- .../com/duckduckgo/app/di/AppComponent.kt | 3 + .../widget/FavoritesWidgetService.kt | 114 ++++++++++++++++++ .../widget/SearchAndFavoritesWidget.kt | 104 +++++++++++++++- .../search_widget_favorites_background.xml | 20 +++ ...earch_widget_favorites_item_background.xml | 20 +++ .../res/layout/search_favorites_widget.xml | 78 ++++++++++++ .../res/layout/view_favorite_widget_item.xml | 48 ++++++++ .../res/xml/search_favorites_widget_info.xml | 13 +- 10 files changed, 438 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/com/duckduckgo/widget/FavoritesWidgetService.kt create mode 100644 app/src/main/res/drawable/search_widget_favorites_background.xml create mode 100644 app/src/main/res/drawable/search_widget_favorites_item_background.xml create mode 100644 app/src/main/res/layout/search_favorites_widget.xml create mode 100644 app/src/main/res/layout/view_favorite_widget_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8a372a699c47..4460e3ea92e9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -336,6 +336,10 @@ android:name="com.duckduckgo.app.job.AppConfigurationJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> + + diff --git a/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt b/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt index 41b9d982bece..d4f1ef1e6be2 100644 --- a/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt +++ b/app/src/main/java/com/duckduckgo/app/WidgetThemeConfiguration.kt @@ -16,14 +16,54 @@ package com.duckduckgo.app +import android.appwidget.AppWidgetManager +import android.content.Intent import android.os.Bundle +import android.widget.Toast import com.duckduckgo.app.browser.R +import com.duckduckgo.app.browser.databinding.ActivityWidgetConfigurationBinding import com.duckduckgo.app.global.DuckDuckGoActivity class WidgetThemeConfiguration : DuckDuckGoActivity() { + private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_widget_configuration) + val binding = ActivityWidgetConfigurationBinding.inflate(layoutInflater) + setContentView(binding.root) + val extras = intent.extras + extras?.let { + appWidgetId = it.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + } + + val resultValue = Intent() + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + setResult(RESULT_CANCELED, resultValue) + + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + finish() + } + + binding.widgetConfigAddWidgetButton.setOnClickListener { + val themeSelected = binding.widgetConfigThemeRadioGroup.checkedRadioButtonId + when (themeSelected) { + R.id.widgetConfigThemeLight -> { + Toast.makeText(this, "Light", Toast.LENGTH_LONG).show() + } + R.id.widgetConfigThemeDark -> { + Toast.makeText(this, "Dark", Toast.LENGTH_LONG).show() + } + } + storeAndSubmitConfiguration() + } + } + + private fun storeAndSubmitConfiguration() { + + val resultValue = Intent() + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + setResult(RESULT_OK, resultValue) + finish() } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/di/AppComponent.kt b/app/src/main/java/com/duckduckgo/app/di/AppComponent.kt index 79b0625646b2..a93e2676dcb6 100644 --- a/app/src/main/java/com/duckduckgo/app/di/AppComponent.kt +++ b/app/src/main/java/com/duckduckgo/app/di/AppComponent.kt @@ -32,6 +32,7 @@ import com.duckduckgo.app.surrogates.di.ResourceSurrogateModule import com.duckduckgo.app.trackerdetection.di.TrackerDetectionModule import com.duckduckgo.app.usage.di.AppUsageModule import com.duckduckgo.di.scopes.AppObjectGraph +import com.duckduckgo.widget.FavoritesWidgetService import com.duckduckgo.widget.SearchWidget import com.squareup.anvil.annotations.MergeComponent import dagger.BindsInstance @@ -98,6 +99,8 @@ interface AppComponent : AndroidInjector { fun inject(searchWidget: SearchWidget) + fun inject(favoritesWidgetItemFactory: FavoritesWidgetService.FavoritesWidgetItemFactory) + // accessor to Retrofit instance for test only only for test @Named("api") fun retrofit(): Retrofit diff --git a/app/src/main/java/com/duckduckgo/widget/FavoritesWidgetService.kt b/app/src/main/java/com/duckduckgo/widget/FavoritesWidgetService.kt new file mode 100644 index 000000000000..4af7683ca46f --- /dev/null +++ b/app/src/main/java/com/duckduckgo/widget/FavoritesWidgetService.kt @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.widget + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.RemoteViews +import android.widget.RemoteViewsService +import com.duckduckgo.app.bookmarks.model.FavoritesDataRepository +import com.duckduckgo.app.bookmarks.model.FavoritesRepository +import com.duckduckgo.app.browser.BrowserActivity +import com.duckduckgo.app.browser.R +import com.duckduckgo.app.global.DuckDuckGoApplication +import com.duckduckgo.app.systemsearch.SystemSearchActivity +import timber.log.Timber +import javax.inject.Inject + +class FavoritesWidgetService: RemoteViewsService() { + + override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { + return FavoritesWidgetItemFactory(this.applicationContext, intent) + } + + class FavoritesWidgetItemFactory(val context: Context, intent: Intent): RemoteViewsFactory { + + @Inject + lateinit var favoritesDataRepository: FavoritesRepository + + private val appWidgetId = intent.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID) + + private val domains = mutableListOf() + + override fun onCreate() { + inject(context) + } + + override fun onDataSetChanged() { + domains.clear() + domains.addAll(favoritesDataRepository.favoritesBlockingGet().map { it.title }) + } + + override fun onDestroy() { + } + + override fun getCount(): Int { + Timber.i("SearchAndFavoritesWidget - getCount") + return domains.size + } + + override fun getViewAt(position: Int): RemoteViews { + Timber.i("SearchAndFavoritesWidget - getViewAt") + val item = domains[position] + val remoteViews = RemoteViews(context.packageName, R.layout.view_favorite_widget_item) + remoteViews.setTextViewText(R.id.quickAccessTitle, item) + configureClickListener(remoteViews, item) + return remoteViews + } + + private fun configureClickListener(remoteViews: RemoteViews, item: String) { + val bundle = Bundle() + bundle.putString(Intent.EXTRA_TEXT, item) + bundle.putBoolean(BrowserActivity.NEW_SEARCH_EXTRA, false) + bundle.putBoolean(BrowserActivity.NOTIFY_DATA_CLEARED_EXTRA, false) + val intent = Intent() + intent.putExtras(bundle) + remoteViews.setOnClickFillInIntent(R.id.quickAccessFaviconContainer, intent) + } + + override fun getLoadingView(): RemoteViews { + return RemoteViews(context.packageName, R.layout.view_favorite_widget_item) + } + + override fun getViewTypeCount(): Int { + return 1 + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun hasStableIds(): Boolean { + return true + } + + private fun buildPendingIntent(context: Context): PendingIntent { + val intent = SystemSearchActivity.fromWidget(context) + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + private fun inject(context: Context) { + val application = context.applicationContext as DuckDuckGoApplication + application.daggerAppComponent.inject(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt b/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt index 797de6928ba3..1616b7a75e7a 100644 --- a/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt +++ b/app/src/main/java/com/duckduckgo/widget/SearchAndFavoritesWidget.kt @@ -16,9 +16,111 @@ package com.duckduckgo.widget +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.os.Bundle +import android.view.View +import android.widget.RemoteViews +import com.duckduckgo.app.browser.BrowserActivity +import com.duckduckgo.app.browser.R +import com.duckduckgo.app.systemsearch.SystemSearchActivity +import timber.log.Timber -class SearchAndFavoritesWidget() : AppWidgetProvider() { +class SearchAndFavoritesWidget(val layoutId: Int = R.layout.search_favorites_widget) : AppWidgetProvider() { + companion object { + const val ACTION_FAVORITE = "com.duckduckgo.widget.actionFavorite" + const val EXTRA_ITEM_URL = "EXTRA_ITEM_URL" + } + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + Timber.i("SearchAndFavoritesWidget - onUpdate") + appWidgetIds.forEach { id -> + updateWidget(context, appWidgetManager, id, null) + } + super.onUpdate(context, appWidgetManager, appWidgetIds) + } + + override fun onAppWidgetOptionsChanged(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, newOptions: Bundle) { + Timber.i("SearchAndFavoritesWidget - onAppWidgetOptionsChanged") + updateWidget(context, appWidgetManager, appWidgetId, newOptions) + super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions) + } + + override fun onDeleted(context: Context?, appWidgetIds: IntArray?) { + Timber.i("SearchAndFavoritesWidget - onDeleted") + super.onDeleted(context, appWidgetIds) + } + + override fun onEnabled(context: Context?) { + Timber.i("SearchAndFavoritesWidget - onEnabled") + super.onEnabled(context) + } + + override fun onDisabled(context: Context?) { + Timber.i("SearchAndFavoritesWidget - onDisabled") + super.onDisabled(context) + } + + override fun onRestored(context: Context?, oldWidgetIds: IntArray?, newWidgetIds: IntArray?) { + Timber.i("SearchAndFavoritesWidget - onRestored") + super.onRestored(context, oldWidgetIds, newWidgetIds) + } + + override fun onReceive(context: Context, intent: Intent) { + Timber.i("SearchAndFavoritesWidget - onReceive") + val instance = AppWidgetManager.getInstance(context) + val componentName = ComponentName(context, SearchAndFavoritesWidget::class.java) + instance.notifyAppWidgetViewDataChanged(instance.getAppWidgetIds(componentName), R.id.favoritesGrid) + + super.onReceive(context, intent) + } + + private fun updateWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, newOptions: Bundle?) { + val appWidgetOptions = appWidgetManager.getAppWidgetOptions(appWidgetId) + var minWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) //portrait + var maxWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) //landscape + var minHeight = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) //landscape + var maxHeight = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) //portrait + + if(newOptions != null) { + minWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) //portrait + maxWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) //landscape + minHeight = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) //landscape + maxHeight = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) //portrait + } + + val remoteViews = RemoteViews(context.packageName, layoutId) + + val favoriteItemClickIntent = Intent(context, BrowserActivity::class.java) + val favoriteClickPendingIntent = PendingIntent.getActivity(context, 0, favoriteItemClickIntent, 0) + + remoteViews.setOnClickPendingIntent(R.id.widgetSearchBarContainer, buildPendingIntent(context)) + + val adapterIntent = Intent(context, FavoritesWidgetService::class.java) + adapterIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + adapterIntent.setData(Uri.parse(adapterIntent.toUri(Intent.URI_INTENT_SCHEME))) + remoteViews.setRemoteAdapter(appWidgetId, R.id.favoritesGrid, adapterIntent) + remoteViews.setPendingIntentTemplate(R.id.favoritesGrid, favoriteClickPendingIntent) + + if(minWidth <= 110) { + remoteViews.setViewVisibility(R.id.searchInputBox, View.GONE) + } else { + remoteViews.setViewVisibility(R.id.searchInputBox, View.VISIBLE) + } + + appWidgetManager.updateAppWidget(appWidgetId, remoteViews) + //appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.favoritesGrid) + } + + private fun buildPendingIntent(context: Context): PendingIntent { + val intent = SystemSearchActivity.fromWidget(context) + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/search_widget_favorites_background.xml b/app/src/main/res/drawable/search_widget_favorites_background.xml new file mode 100644 index 000000000000..6ee2f183a609 --- /dev/null +++ b/app/src/main/res/drawable/search_widget_favorites_background.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/search_widget_favorites_item_background.xml b/app/src/main/res/drawable/search_widget_favorites_item_background.xml new file mode 100644 index 000000000000..9d82b6c11141 --- /dev/null +++ b/app/src/main/res/drawable/search_widget_favorites_item_background.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/search_favorites_widget.xml b/app/src/main/res/layout/search_favorites_widget.xml new file mode 100644 index 000000000000..9794ae8bc8f6 --- /dev/null +++ b/app/src/main/res/layout/search_favorites_widget.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_favorite_widget_item.xml b/app/src/main/res/layout/view_favorite_widget_item.xml new file mode 100644 index 000000000000..e5c817f689c6 --- /dev/null +++ b/app/src/main/res/layout/view_favorite_widget_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/search_favorites_widget_info.xml b/app/src/main/res/xml/search_favorites_widget_info.xml index 89f00562116a..4856ad5c6584 100644 --- a/app/src/main/res/xml/search_favorites_widget_info.xml +++ b/app/src/main/res/xml/search_favorites_widget_info.xml @@ -18,13 +18,14 @@ From 5bfdb417e70ba9dbd5bd42661de33de7457aaa53 Mon Sep 17 00:00:00 2001 From: Cristian Monforte Date: Tue, 8 Jun 2021 18:58:12 +0200 Subject: [PATCH 003/105] Configuration screen layout --- .../res/layout/activity_widget_configuration.xml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/activity_widget_configuration.xml b/app/src/main/res/layout/activity_widget_configuration.xml index 686f6c63c5d6..7bb73b4824f7 100644 --- a/app/src/main/res/layout/activity_widget_configuration.xml +++ b/app/src/main/res/layout/activity_widget_configuration.xml @@ -31,20 +31,24 @@ android:src="@drawable/search_favorites_widget_preview"/> - + +