feat(widget): Add home screen widget with quick access actions
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
7
ios/ConduitWidget/Assets.xcassets/Contents.json
Normal file
7
ios/ConduitWidget/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
||||
17
ios/ConduitWidget/Assets.xcassets/HubIcon.imageset/Contents.json
vendored
Normal file
17
ios/ConduitWidget/Assets.xcassets/HubIcon.imageset/Contents.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
|
||||
2
ios/ConduitWidget/Assets.xcassets/HubIcon.imageset/hub.svg
vendored
Normal file
2
ios/ConduitWidget/Assets.xcassets/HubIcon.imageset/hub.svg
vendored
Normal 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 |
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
11
ios/ConduitWidget/ConduitWidget.entitlements
Normal file
11
ios/ConduitWidget/ConduitWidget.entitlements
Normal 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>
|
||||
|
||||
129
ios/ConduitWidget/ConduitWidget.swift
Normal file
129
ios/ConduitWidget/ConduitWidget.swift
Normal 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)
|
||||
}
|
||||
16
ios/ConduitWidget/ConduitWidgetBundle.swift
Normal file
16
ios/ConduitWidget/ConduitWidgetBundle.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
12
ios/ConduitWidget/Info.plist
Normal file
12
ios/ConduitWidget/Info.plist
Normal 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>
|
||||
|
||||
Reference in New Issue
Block a user