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

@@ -0,0 +1,21 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.929",
"green" : "0.227",
"red" : "0.486"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,7 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,17 @@
{
"images" : [
{
"filename" : "hub.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}

View File

@@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M240-40q-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-580q0-50 35-85t85-35q50 0 85 35t35 85v8l81 28q20-36 53.5-61t75.5-32v-87q-39-11-64.5-42.5T360-840q0-50 35-85t85-35q50 0 85 35t35 85q0 42-26 73.5T510-724v87q42 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-515l-81 27q6 39-5 77.5T614-340l57 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-232l-57-71q-41 23-87.5 23T392-303l-56 71q11 15 17.5 33.5T360-160q0 50-35 85t-85 35Z" fill="currentColor"/></svg>

After

Width:  |  Height:  |  Size: 719 B

View File

@@ -0,0 +1,39 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.961",
"green" : "0.961",
"red" : "0.961"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.118",
"green" : "0.118",
"red" : "0.118"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.app.cogwheel.conduit</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,129 @@
//
// ConduitWidget.swift
// ConduitWidget
//
// Created by cogwheel on 07/12/25.
//
import WidgetKit
import SwiftUI
// MARK: - Timeline Entry
struct ConduitEntry: TimelineEntry {
let date: Date
}
// MARK: - Timeline Provider
struct ConduitProvider: TimelineProvider {
func placeholder(in context: Context) -> ConduitEntry {
ConduitEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (ConduitEntry) -> Void) {
let entry = ConduitEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<ConduitEntry>) -> Void) {
let entry = ConduitEntry(date: Date())
let timeline = Timeline(entries: [entry], policy: .never)
completion(timeline)
}
}
// MARK: - Widget View
struct ConduitWidgetEntryView: View {
var entry: ConduitProvider.Entry
@Environment(\.widgetFamily) var family
@Environment(\.colorScheme) var colorScheme
var body: some View {
VStack(spacing: 12) {
// Main "Ask Conduit" pill - ChatGPT style
Link(destination: URL(string: "homewidget://new_chat")!) {
HStack(spacing: 12) {
Image("HubIcon")
.renderingMode(.template)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 28, height: 28)
.foregroundStyle(.white.opacity(0.9))
Text("Ask Conduit")
.font(.system(size: 18, weight: .medium, design: .rounded))
.foregroundStyle(.white.opacity(0.9))
Spacer()
}
.padding(.horizontal, 20)
.frame(maxWidth: .infinity)
.frame(height: 56)
.background(
Capsule()
.fill(.white.opacity(0.15))
)
}
.buttonStyle(.plain)
// 4 circular icon buttons - ChatGPT style, fill width
HStack(spacing: 8) {
CircularIconButton(symbol: "camera", url: "homewidget://camera")
CircularIconButton(symbol: "photo.on.rectangle.angled", url: "homewidget://photos")
CircularIconButton(symbol: "waveform", url: "homewidget://mic")
CircularIconButton(symbol: "doc.on.clipboard", url: "homewidget://clipboard")
}
}
.padding(16)
}
}
// MARK: - Circular Icon Button (ChatGPT Style)
struct CircularIconButton: View {
let symbol: String
let url: String
var body: some View {
Link(destination: URL(string: url)!) {
Image(systemName: symbol)
.font(.system(size: 24, weight: .medium))
.foregroundStyle(.white.opacity(0.9))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(.white.opacity(0.15))
)
}
.buttonStyle(.plain)
}
}
// MARK: - Widget Configuration
struct ConduitWidget: Widget {
let kind: String = "ConduitWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: ConduitProvider()) { entry in
if #available(iOS 17.0, *) {
ConduitWidgetEntryView(entry: entry)
.containerBackground(.clear, for: .widget)
} else {
ConduitWidgetEntryView(entry: entry)
}
}
.configurationDisplayName("Conduit")
.description("Quick access to chat, camera, photos, and voice.")
.supportedFamilies([.systemMedium])
.contentMarginsDisabled()
}
}
// MARK: - Preview
#Preview(as: .systemMedium) {
ConduitWidget()
} timeline: {
ConduitEntry(date: .now)
}

View File

@@ -0,0 +1,16 @@
//
// ConduitWidgetBundle.swift
// ConduitWidget
//
// Created by cogwheel on 07/12/25.
//
import WidgetKit
import SwiftUI
@main
struct ConduitWidgetBundle: WidgetBundle {
var body: some Widget {
ConduitWidget()
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>