diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle
index 68f0bffa..13c9f317 100644
--- a/app/android/app/build.gradle
+++ b/app/android/app/build.gradle
@@ -1,6 +1,7 @@
plugins {
id "com.android.application"
id "kotlin-android"
+ id "org.jetbrains.kotlin.plugin.compose" version "2.1.20"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
@@ -49,10 +50,14 @@ android {
dependencies {
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- // implementation 'androidx.glance:glance-appwidget:1.0.0'
+ implementation 'androidx.glance:glance-appwidget:1.1.1'
implementation 'com.google.android.material:material:1.12.0'
}
+ buildFeatures {
+ compose true
+ }
+
signingConfigs {
release {
keyAlias System.getenv("KEY_ALIAS")
diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml
index e51e2308..a3e6341c 100644
--- a/app/android/app/src/main/AndroidManifest.xml
+++ b/app/android/app/src/main/AndroidManifest.xml
@@ -88,7 +88,7 @@
-
+
@@ -176,32 +176,17 @@
android:label="@string/mozac_feature_addons_addons"
android:theme="@style/Theme.AppCompat.Light"/>
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.
- */
-package eu.weblibre.gecko
-
-import android.appwidget.AppWidgetManager
-import android.content.Context
-import android.content.SharedPreferences
-import android.graphics.BitmapFactory
-import android.net.Uri
-import android.view.View
-import android.widget.RemoteViews
-import es.antonborri.home_widget.HomeWidgetBackgroundIntent
-import es.antonborri.home_widget.HomeWidgetLaunchIntent
-import es.antonborri.home_widget.HomeWidgetProvider
-
-class CompactWidgetProvider : HomeWidgetProvider() {
- override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
- appWidgetIds.forEach { widgetId ->
- val views = RemoteViews(context.packageName, R.layout.compact_widget).apply {
- val searchIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://search"))
- setOnClickPendingIntent(R.id.search_button, searchIntent)
-
- val assistantIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://assistant"))
- setOnClickPendingIntent(R.id.assistant_button, assistantIntent)
-
- val summarizerIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://summarizer"))
- setOnClickPendingIntent(R.id.summarizer_button, summarizerIntent)
- }
-
- appWidgetManager.updateAppWidget(widgetId, views)
- }
- }
-}
\ No newline at end of file
diff --git a/app/android/app/src/main/kotlin/eu/weblibre/gecko/FullWidgetProvider.kt b/app/android/app/src/main/kotlin/eu/weblibre/gecko/FullWidgetProvider.kt
deleted file mode 100644
index afde5820..00000000
--- a/app/android/app/src/main/kotlin/eu/weblibre/gecko/FullWidgetProvider.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2024-2025 Fabian Freund.
- *
- * This file is part of WebLibre
- * (see https://weblibre.eu).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package eu.weblibre.gecko
-
-import android.appwidget.AppWidgetManager
-import android.content.Context
-import android.content.SharedPreferences
-import android.graphics.BitmapFactory
-import android.net.Uri
-import android.view.View
-import android.widget.RemoteViews
-import es.antonborri.home_widget.HomeWidgetBackgroundIntent
-import es.antonborri.home_widget.HomeWidgetLaunchIntent
-import es.antonborri.home_widget.HomeWidgetProvider
-
-class FullWidgetProvider : HomeWidgetProvider() {
- override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
- appWidgetIds.forEach { widgetId ->
- val views = RemoteViews(context.packageName, R.layout.full_widget).apply {
- val searchIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://search"))
- setOnClickPendingIntent(R.id.search_button, searchIntent)
-
- val assistantIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://assistant"))
- setOnClickPendingIntent(R.id.assistant_button, assistantIntent)
-
- val summarizerIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://summarizer"))
- setOnClickPendingIntent(R.id.summarizer_button, summarizerIntent)
- }
-
- appWidgetManager.updateAppWidget(widgetId, views)
- }
- }
-}
\ No newline at end of file
diff --git a/app/android/app/src/main/kotlin/eu/weblibre/gecko/SearchBarWidgetProvider.kt b/app/android/app/src/main/kotlin/eu/weblibre/gecko/SearchBarWidgetProvider.kt
index 9bdd308e..d40f2720 100644
--- a/app/android/app/src/main/kotlin/eu/weblibre/gecko/SearchBarWidgetProvider.kt
+++ b/app/android/app/src/main/kotlin/eu/weblibre/gecko/SearchBarWidgetProvider.kt
@@ -1,47 +1,79 @@
-/*
- * Copyright (c) 2024-2025 Fabian Freund.
- *
- * This file is part of WebLibre
- * (see https://weblibre.eu).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
package eu.weblibre.gecko
-import android.appwidget.AppWidgetManager
import android.content.Context
-import android.content.SharedPreferences
-import android.graphics.BitmapFactory
-import android.net.Uri
-import android.view.View
-import android.widget.RemoteViews
-import es.antonborri.home_widget.HomeWidgetBackgroundIntent
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.glance.GlanceId
+import androidx.glance.GlanceModifier
+import androidx.glance.Image
+import androidx.glance.ImageProvider
+import androidx.glance.action.clickable
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.provideContent
+import androidx.glance.background
+import androidx.glance.layout.Alignment
+import androidx.glance.layout.Row
+import androidx.glance.layout.fillMaxWidth
+import androidx.glance.layout.padding
+import androidx.glance.layout.wrapContentHeight
+import androidx.glance.text.Text
+import androidx.glance.text.TextStyle
+import androidx.glance.unit.ColorProvider
import es.antonborri.home_widget.HomeWidgetLaunchIntent
-import es.antonborri.home_widget.HomeWidgetProvider
+import android.net.Uri
+import es.antonborri.home_widget.actionStartActivity
+import androidx.core.net.toUri
-class SearchBarWidgetProvider : HomeWidgetProvider() {
- override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
- appWidgetIds.forEach { widgetId ->
- val views = RemoteViews(context.packageName, R.layout.search_bar_widget).apply {
- val searchIntent = HomeWidgetLaunchIntent.getActivity(
- context,
- MainActivity::class.java,
- Uri.parse("widget://search"))
- setOnClickPendingIntent(R.id.search_button, searchIntent)
- }
+class SearchBarGlanceWidget : GlanceAppWidget() {
- appWidgetManager.updateAppWidget(widgetId, views)
+ override suspend fun provideGlance(context: Context, id: GlanceId) {
+ provideContent {
+ SearchBarContent(context)
}
}
-}
\ No newline at end of file
+}
+
+@Composable
+private fun SearchBarContent(context: Context) {
+ Row(
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ .wrapContentHeight()
+ .background(ImageProvider(R.drawable.search_text_field))
+ .padding(12.dp)
+ .clickable(onClick = actionStartActivity(context,
+ "widget://search".toUri())),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ // Start icon
+ Image(
+ provider = ImageProvider(R.drawable.icon_with_size),
+ contentDescription = "Search icon",
+ modifier = GlanceModifier.padding(end = 8.dp)
+ )
+
+ // Search text
+ Text(
+ text = "Search with WebLibre...",
+ style = TextStyle(
+ color = ColorProvider(Color(0xFF848388)),
+ fontSize = 16.sp
+ ),
+ modifier = GlanceModifier.defaultWeight()
+ )
+
+ // End icon (microphone)
+ Image(
+ provider = ImageProvider(R.drawable.mdi_icon_microphone_tint),
+ contentDescription = "Microphone icon",
+ modifier = GlanceModifier.padding(start = 8.dp)
+ )
+ }
+}
+
+class SearchBarWidgetReceiver : GlanceAppWidgetReceiver() {
+ override val glanceAppWidget: GlanceAppWidget = SearchBarGlanceWidget()
+}
diff --git a/app/android/app/src/main/res/layout/compact_widget.xml b/app/android/app/src/main/res/layout/compact_widget.xml
deleted file mode 100644
index 0cceeca4..00000000
--- a/app/android/app/src/main/res/layout/compact_widget.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/android/app/src/main/res/layout/full_widget.xml b/app/android/app/src/main/res/layout/full_widget.xml
deleted file mode 100644
index bdf9da6f..00000000
--- a/app/android/app/src/main/res/layout/full_widget.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/android/app/src/main/res/layout/search_bar_widget.xml b/app/android/app/src/main/res/layout/search_bar_widget.xml
deleted file mode 100644
index e0e2fcd0..00000000
--- a/app/android/app/src/main/res/layout/search_bar_widget.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
\ No newline at end of file
diff --git a/app/android/app/src/main/res/xml/compact_widget_info.xml b/app/android/app/src/main/res/xml/compact_widget_info.xml
deleted file mode 100644
index de8e2827..00000000
--- a/app/android/app/src/main/res/xml/compact_widget_info.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/android/app/src/main/res/xml/full_widget_info.xml b/app/android/app/src/main/res/xml/full_widget_info.xml
deleted file mode 100644
index 68235f3d..00000000
--- a/app/android/app/src/main/res/xml/full_widget_info.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/android/app/src/main/res/xml/search_bar_widget_info.xml b/app/android/app/src/main/res/xml/search_bar_widget_info.xml
index ba6dd532..3b312798 100644
--- a/app/android/app/src/main/res/xml/search_bar_widget_info.xml
+++ b/app/android/app/src/main/res/xml/search_bar_widget_info.xml
@@ -1,8 +1,7 @@
\ No newline at end of file
+ android:widgetCategory="home_screen" />
diff --git a/app/lib/features/geckoview/features/browser/domain/providers/intent.dart b/app/lib/features/geckoview/features/browser/domain/providers/intent.dart
index a1f5b613..dd0557f0 100644
--- a/app/lib/features/geckoview/features/browser/domain/providers/intent.dart
+++ b/app/lib/features/geckoview/features/browser/domain/providers/intent.dart
@@ -22,6 +22,7 @@ import 'dart:async';
import 'package:nullability/nullability.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:rxdart/rxdart.dart';
+import 'package:weblibre/core/routing/routes.dart';
import 'package:weblibre/data/models/received_intent_parameter.dart';
import 'package:weblibre/features/app_widget/domain/services/home_widget.dart';
import 'package:weblibre/features/geckoview/domain/providers.dart';
@@ -39,6 +40,8 @@ final _contentParserTransformer =
if (parsed != null) {
sink.add(parsed);
+ } else if (parameter.tool == 'search') {
+ sink.add(SharedText(SearchRoute.emptySearchText));
}
},
);