feat(widget): Add home screen widget with quick access actions

This commit is contained in:
cogwheel0
2025-12-07 12:26:16 +05:30
parent b286a25910
commit 745ff01954
59 changed files with 1950 additions and 14 deletions

View File

@@ -119,6 +119,19 @@
android:exported="false"
android:foregroundServiceType="dataSync|microphone"/>
<!-- Home Screen Widget -->
<receiver
android:name=".ConduitWidgetProvider"
android:exported="true"
android:label="@string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/conduit_widget_info" />
</receiver>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data

View File

@@ -0,0 +1,107 @@
package app.cogwheel.conduit
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.net.Uri
import android.widget.RemoteViews
import es.antonborri.home_widget.HomeWidgetLaunchIntent
/**
* Home screen widget provider for Conduit.
*
* Provides quick actions:
* - New Chat: Start a fresh conversation
* - Mic: Start voice input
* - Camera: Take a photo and attach to chat
* - Photos: Pick from gallery and attach to chat
* - Clipboard: Paste clipboard content as prompt
*/
class ConduitWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onEnabled(context: Context) {
// Called when the first widget is created
}
override fun onDisabled(context: Context) {
// Called when the last widget is removed
}
companion object {
private const val ACTION_NEW_CHAT = "new_chat"
private const val ACTION_MIC = "mic"
private const val ACTION_CAMERA = "camera"
private const val ACTION_PHOTOS = "photos"
private const val ACTION_CLIPBOARD = "clipboard"
private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val views = RemoteViews(context.packageName, R.layout.conduit_widget)
// Set up click handlers using home_widget's launch intent
views.setOnClickPendingIntent(
R.id.widget_container,
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homewidget://$ACTION_NEW_CHAT")
)
)
views.setOnClickPendingIntent(
R.id.btn_new_chat,
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homewidget://$ACTION_NEW_CHAT")
)
)
views.setOnClickPendingIntent(
R.id.btn_mic,
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homewidget://$ACTION_MIC")
)
)
views.setOnClickPendingIntent(
R.id.btn_camera,
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homewidget://$ACTION_CAMERA")
)
)
views.setOnClickPendingIntent(
R.id.btn_photos,
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homewidget://$ACTION_PHOTOS")
)
)
views.setOnClickPendingIntent(
R.id.btn_clipboard,
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homewidget://$ACTION_CLIPBOARD")
)
)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container">
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container">
<path
android:fillColor="@android:color/white"
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2H5c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM14,18H7v-2h7v2zM17,14H7v-2h10v2zM17,10H7V8h10v2z" />
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Material Design Mic Icon - Material You -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container">
<path
android:fillColor="@android:color/white"
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11H5c0,3.41 2.72,6.23 6,6.72V21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Mic icon with accent color tint - Material You -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_mic_icon">
<path
android:fillColor="@android:color/white"
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11H5c0,3.41 2.72,6.23 6,6.72V21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container">
<path
android:fillColor="@android:color/white"
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Graphic equalizer icon for voice - Material You -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container">
<path
android:fillColor="@android:color/white"
android:pathData="M7,18h2V6H7v12zM11,22h2V2h-2v20zM3,14h2v-4H3v4zM15,18h2V6h-2v12zM19,10v4h2v-4h-2z" />
</vector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Widget background - Material You dynamic surface color -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/widget_surface" />
<corners android:radius="@dimen/widget_corner_radius" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Rounded button - Material You -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20FFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container" />
<corners android:radius="16dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Mic button inside pill - Material You lighter accent -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20FFFFFF">
<item>
<shape android:shape="oval">
<solid android:color="@color/widget_mic_background" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Pill-shaped primary button - Material You dynamic color (darker accent) -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#40FFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_primary_dark" />
<corners android:radius="24dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Primary button - Material You dynamic primary color -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#40FFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_primary" />
<corners android:radius="@dimen/widget_button_corner_radius" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Secondary button - Material You dynamic secondary container color -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20000000">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container" />
<corners android:radius="@dimen/widget_secondary_corner_radius" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Material Design Hub Icon (Filled) -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="#FFFFFF">
<path
android:fillColor="@android:color/white"
android:pathData="M240,920q-50,0 -85,-35t-35,-85q0,-50 35,-85t85,-35q14,0 26,3t23,8l57,-71q-28,-31 -39,-70t-5,-78l-81,-27q-17,25 -43,40t-58,15q-50,0 -85,-35T0,380q0,-50 35,-85t85,-35q50,0 85,35t35,85v8l81,28q20,-36 53.5,-61t75.5,-32v-87q-39,-11 -64.5,-42.5T360,120q0,-50 35,-85t85,-35q50,0 85,35t35,85q0,42 -26,73.5T510,236v87q42,7 75.5,32t53.5,61l81,-28v-8q0,-50 35,-85t85,-35q50,0 85,35t35,85q0,50 -35,85t-85,35q-32,0 -58.5,-15T739,445l-81,27q6,39 -5,77.5T614,620l57,70q11,-5 23,-7.5t26,-2.5q50,0 85,35t35,85q0,50 -35,85t-85,35q-50,0 -85,-35t-35,-85q0,-20 6.5,-38.5T624,728l-57,-71q-41,23 -87.5,23T392,657l-56,71q11,15 17.5,33.5T360,800q0,50 -35,85t-85,35Z" />
</vector>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,2l1.5,5.5L19,9l-5.5,1.5L12,16l-1.5,-5.5L5,9l5.5,-1.5L12,2z"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M19,15l0.94,2.06L22,18l-2.06,0.94L19,21l-0.94,-2.06L16,18l2.06,-0.94L19,15z"/>
</vector>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container_fallback">
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container_fallback">
<path
android:fillColor="@android:color/white"
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2H5c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM14,18H7v-2h7v2zM17,14H7v-2h10v2zM17,10H7V8h10v2z" />
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Material Design Mic Icon -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container_fallback">
<path
android:fillColor="@android:color/white"
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11H5c0,3.41 2.72,6.23 6,6.72V21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
</vector>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Mic icon with accent color tint -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_mic_icon_fallback">
<path
android:fillColor="@android:color/white"
android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11H5c0,3.41 2.72,6.23 6,6.72V21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container_fallback">
<path
android:fillColor="@android:color/white"
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Graphic equalizer icon for voice -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/widget_on_secondary_container_fallback">
<path
android:fillColor="@android:color/white"
android:pathData="M7,18h2V6H7v12zM11,22h2V2h-2v20zM3,14h2v-4H3v4zM15,18h2V6h-2v12zM19,10v4h2v-4h-2z" />
</vector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Widget background - Material 3 surface with large corner radius -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/widget_surface_fallback" />
<corners android:radius="@dimen/widget_corner_radius" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Rounded button - ChatGPT style -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20FFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container_fallback" />
<corners android:radius="16dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Mic button inside pill - lighter accent background -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20FFFFFF">
<item>
<shape android:shape="oval">
<solid android:color="@color/widget_mic_background_fallback" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Pill-shaped primary button - Material 3 style with darker accent -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#40FFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_primary_dark_fallback" />
<corners android:radius="24dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Primary button - Material 3 filled button style -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#40FFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_primary_fallback" />
<corners android:radius="@dimen/widget_button_corner_radius" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Secondary button - Material 3 tonal button style -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20000000">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container_fallback" />
<corners android:radius="@dimen/widget_secondary_corner_radius" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Widget preview shown in the widget picker - Material 3 style -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background -->
<item>
<shape android:shape="rectangle">
<solid android:color="@color/widget_surface_fallback" />
<corners android:radius="@dimen/widget_corner_radius" />
</shape>
</item>
<!-- Primary button preview -->
<item
android:left="16dp"
android:top="16dp"
android:right="16dp"
android:bottom="72dp">
<shape android:shape="rectangle">
<solid android:color="@color/widget_primary_fallback" />
<corners android:radius="@dimen/widget_button_corner_radius" />
</shape>
</item>
<!-- Secondary buttons preview -->
<item
android:left="16dp"
android:top="80dp"
android:right="176dp"
android:bottom="16dp">
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container_fallback" />
<corners android:radius="@dimen/widget_secondary_corner_radius" />
</shape>
</item>
<item
android:left="96dp"
android:top="80dp"
android:right="96dp"
android:bottom="16dp">
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container_fallback" />
<corners android:radius="@dimen/widget_secondary_corner_radius" />
</shape>
</item>
<item
android:left="176dp"
android:top="80dp"
android:right="16dp"
android:bottom="16dp">
<shape android:shape="rectangle">
<solid android:color="@color/widget_secondary_container_fallback" />
<corners android:radius="@dimen/widget_secondary_corner_radius" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ChatGPT-style widget design -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widget_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:background="@drawable/widget_background"
android:clipToOutline="true">
<!-- Main "Ask Conduit" Pill -->
<LinearLayout
android:id="@+id/btn_new_chat"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@drawable/widget_button_pill"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="20dp"
android:layout_marginBottom="12dp">
<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:src="@drawable/ic_hub"
android:importantForAccessibility="no"
android:layout_marginEnd="12dp"
tools:ignore="UseAppTint" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/widget_ask_conduit"
android:textColor="@color/widget_on_primary"
android:textSize="18sp"
android:fontFamily="sans-serif-medium" />
</LinearLayout>
<!-- 4 Circular Icon Buttons Row -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center"
android:baselineAligned="false">
<!-- Camera Button -->
<FrameLayout
android:id="@+id/btn_camera"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginEnd="6dp"
android:background="@drawable/widget_button_circle">
<ImageView
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:src="@drawable/ic_widget_camera"
android:importantForAccessibility="no"
tools:ignore="UseAppTint" />
</FrameLayout>
<!-- Photos Button -->
<FrameLayout
android:id="@+id/btn_photos"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginHorizontal="6dp"
android:background="@drawable/widget_button_circle">
<ImageView
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:src="@drawable/ic_widget_photos"
android:importantForAccessibility="no"
tools:ignore="UseAppTint" />
</FrameLayout>
<!-- Voice/Mic Button -->
<FrameLayout
android:id="@+id/btn_mic"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginHorizontal="6dp"
android:background="@drawable/widget_button_circle">
<ImageView
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:src="@drawable/ic_widget_waveform"
android:importantForAccessibility="no"
tools:ignore="UseAppTint" />
</FrameLayout>
<!-- Clipboard Button -->
<FrameLayout
android:id="@+id/btn_clipboard"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginStart="6dp"
android:background="@drawable/widget_button_circle">
<ImageView
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:src="@drawable/ic_widget_clipboard"
android:importantForAccessibility="no"
tools:ignore="UseAppTint" />
</FrameLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Material 3 Widget Colors (Dark Mode) -->
<!-- Primary colors for main button -->
<color name="widget_primary">@android:color/system_accent1_200</color>
<color name="widget_primary_dark">@android:color/system_accent1_400</color>
<color name="widget_on_primary">@android:color/system_accent1_800</color>
<!-- Mic button colors (lighter accent inside pill) -->
<color name="widget_mic_background">@android:color/system_accent1_200</color>
<color name="widget_mic_icon">@android:color/system_accent1_800</color>
<!-- Secondary container colors for action buttons -->
<color name="widget_secondary_container">@android:color/system_accent2_700</color>
<color name="widget_on_secondary_container">@android:color/system_accent2_100</color>
<!-- Surface colors for widget background -->
<color name="widget_surface">@android:color/system_neutral1_900</color>
<color name="widget_surface_variant">@android:color/system_neutral2_700</color>
<!-- Fallback colors for pre-Android 12 -->
<color name="widget_primary_fallback">#D0BCFF</color>
<color name="widget_primary_dark_fallback">#9A82DB</color>
<color name="widget_mic_background_fallback">#D0BCFF</color>
<color name="widget_mic_icon_fallback">#4A3880</color>
<color name="widget_secondary_container_fallback">#4A4458</color>
<color name="widget_on_secondary_container_fallback">#E8DEF8</color>
<color name="widget_surface_fallback">#1C1B1F</color>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Widget dimensions (same for both modes) -->
<dimen name="widget_padding">12dp</dimen>
<dimen name="widget_button_spacing">6dp</dimen>
<dimen name="widget_corner_radius">24dp</dimen>
<dimen name="widget_button_corner_radius">16dp</dimen>
<dimen name="widget_secondary_corner_radius">12dp</dimen>
</resources>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Material 3 Widget Colors (Light Mode) -->
<!-- Primary colors for main button -->
<color name="widget_primary">@android:color/system_accent1_600</color>
<color name="widget_primary_dark">@android:color/system_accent1_800</color>
<color name="widget_on_primary">@android:color/white</color>
<!-- Mic button colors (lighter accent inside pill) -->
<color name="widget_mic_background">@android:color/system_accent1_100</color>
<color name="widget_mic_icon">@android:color/system_accent1_700</color>
<!-- Secondary container colors for action buttons -->
<color name="widget_secondary_container">@android:color/system_accent2_100</color>
<color name="widget_on_secondary_container">@android:color/system_accent1_700</color>
<!-- Surface colors for widget background -->
<color name="widget_surface">@android:color/system_neutral1_10</color>
<color name="widget_surface_variant">@android:color/system_neutral2_100</color>
<!-- Fallback colors for pre-Android 12 -->
<color name="widget_primary_fallback">#6750A4</color>
<color name="widget_primary_dark_fallback">#4A3880</color>
<color name="widget_mic_background_fallback">#E8DEF8</color>
<color name="widget_mic_icon_fallback">#6750A4</color>
<color name="widget_secondary_container_fallback">#E8DEF8</color>
<color name="widget_on_secondary_container_fallback">#1D192B</color>
<color name="widget_surface_fallback">#FFFBFE</color>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Widget dimensions following Material 3 guidelines -->
<dimen name="widget_padding">12dp</dimen>
<dimen name="widget_button_spacing">6dp</dimen>
<dimen name="widget_corner_radius">24dp</dimen>
<dimen name="widget_button_corner_radius">16dp</dimen>
<dimen name="widget_secondary_corner_radius">12dp</dimen>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Conduit</string>
<!-- Widget strings -->
<string name="widget_name">Conduit</string>
<string name="widget_description">Quick access to Conduit chat with camera, photos, and clipboard shortcuts</string>
<string name="widget_ask_conduit">Ask Conduit</string>
<string name="widget_camera">Camera</string>
<string name="widget_photos">Photos</string>
<string name="widget_clipboard">Clipboard</string>
<string name="widget_mic">Voice</string>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="250dp"
android:minHeight="110dp"
android:targetCellWidth="3"
android:targetCellHeight="2"
android:minResizeWidth="180dp"
android:minResizeHeight="110dp"
android:maxResizeWidth="400dp"
android:maxResizeHeight="200dp"
android:updatePeriodMillis="0"
android:initialLayout="@layout/conduit_widget"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"
android:previewImage="@drawable/widget_preview"
android:description="@string/widget_description"
android:widgetFeatures="reconfigurable" />