offline + виджет
This commit is contained in:
parent
4c090d4295
commit
11fdf3186b
18
FavoritesWidget/AppIntent.swift
Normal file
18
FavoritesWidget/AppIntent.swift
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// AppIntent.swift
|
||||||
|
// FavoritesWidget
|
||||||
|
//
|
||||||
|
// Created by Platon on 08.08.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
|
struct ConfigurationAppIntent: WidgetConfigurationIntent {
|
||||||
|
static var title: LocalizedStringResource { "Configuration" }
|
||||||
|
static var description: IntentDescription { "This is an example widget." }
|
||||||
|
|
||||||
|
// An example configurable parameter.
|
||||||
|
@Parameter(title: "Favorite Emoji", default: "😃")
|
||||||
|
var favoriteEmoji: String
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
6
FavoritesWidget/Assets.xcassets/Contents.json
Normal file
6
FavoritesWidget/Assets.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
88
FavoritesWidget/FavoritesWidget.swift
Normal file
88
FavoritesWidget/FavoritesWidget.swift
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// FavoritesWidget.swift
|
||||||
|
// FavoritesWidget
|
||||||
|
//
|
||||||
|
// Created by Platon on 08.08.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct Provider: AppIntentTimelineProvider {
|
||||||
|
func placeholder(in context: Context) -> SimpleEntry {
|
||||||
|
SimpleEntry(date: Date(), configuration: ConfigurationAppIntent())
|
||||||
|
}
|
||||||
|
|
||||||
|
func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
|
||||||
|
SimpleEntry(date: Date(), configuration: configuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> {
|
||||||
|
var entries: [SimpleEntry] = []
|
||||||
|
|
||||||
|
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
|
||||||
|
let currentDate = Date()
|
||||||
|
for hourOffset in 0 ..< 5 {
|
||||||
|
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
|
||||||
|
let entry = SimpleEntry(date: entryDate, configuration: configuration)
|
||||||
|
entries.append(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Timeline(entries: entries, policy: .atEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func relevances() async -> WidgetRelevances<ConfigurationAppIntent> {
|
||||||
|
// // Generate a list containing the contexts this widget is relevant in.
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SimpleEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let configuration: ConfigurationAppIntent
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FavoritesWidgetEntryView : View {
|
||||||
|
var entry: Provider.Entry
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Text("Time:")
|
||||||
|
Text(entry.date, style: .time)
|
||||||
|
|
||||||
|
Text("Favorite Emoji:")
|
||||||
|
Text(entry.configuration.favoriteEmoji)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FavoritesWidget: Widget {
|
||||||
|
let kind: String = "FavoritesWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in
|
||||||
|
FavoritesWidgetEntryView(entry: entry)
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ConfigurationAppIntent {
|
||||||
|
fileprivate static var smiley: ConfigurationAppIntent {
|
||||||
|
let intent = ConfigurationAppIntent()
|
||||||
|
intent.favoriteEmoji = "😀"
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate static var starEyes: ConfigurationAppIntent {
|
||||||
|
let intent = ConfigurationAppIntent()
|
||||||
|
intent.favoriteEmoji = "🤩"
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
FavoritesWidget()
|
||||||
|
} timeline: {
|
||||||
|
SimpleEntry(date: .now, configuration: .smiley)
|
||||||
|
SimpleEntry(date: .now, configuration: .starEyes)
|
||||||
|
}
|
||||||
18
FavoritesWidget/FavoritesWidgetBundle.swift
Normal file
18
FavoritesWidget/FavoritesWidgetBundle.swift
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// FavoritesWidgetBundle.swift
|
||||||
|
// FavoritesWidget
|
||||||
|
//
|
||||||
|
// Created by Platon on 08.08.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct FavoritesWidgetBundle: WidgetBundle {
|
||||||
|
var body: some Widget {
|
||||||
|
FavoritesWidget()
|
||||||
|
FavoritesWidgetControl()
|
||||||
|
FavoritesWidgetLiveActivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
77
FavoritesWidget/FavoritesWidgetControl.swift
Normal file
77
FavoritesWidget/FavoritesWidgetControl.swift
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// FavoritesWidgetControl.swift
|
||||||
|
// FavoritesWidget
|
||||||
|
//
|
||||||
|
// Created by Platon on 08.08.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppIntents
|
||||||
|
import SwiftUI
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
|
struct FavoritesWidgetControl: ControlWidget {
|
||||||
|
static let kind: String = "com.mkch.MobileMkch.FavoritesWidget"
|
||||||
|
|
||||||
|
var body: some ControlWidgetConfiguration {
|
||||||
|
AppIntentControlConfiguration(
|
||||||
|
kind: Self.kind,
|
||||||
|
provider: Provider()
|
||||||
|
) { value in
|
||||||
|
ControlWidgetToggle(
|
||||||
|
"Start Timer",
|
||||||
|
isOn: value.isRunning,
|
||||||
|
action: StartTimerIntent(value.name)
|
||||||
|
) { isRunning in
|
||||||
|
Label(isRunning ? "On" : "Off", systemImage: "timer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.displayName("Timer")
|
||||||
|
.description("A an example control that runs a timer.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FavoritesWidgetControl {
|
||||||
|
struct Value {
|
||||||
|
var isRunning: Bool
|
||||||
|
var name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Provider: AppIntentControlValueProvider {
|
||||||
|
func previewValue(configuration: TimerConfiguration) -> Value {
|
||||||
|
FavoritesWidgetControl.Value(isRunning: false, name: configuration.timerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func currentValue(configuration: TimerConfiguration) async throws -> Value {
|
||||||
|
let isRunning = true // Check if the timer is running
|
||||||
|
return FavoritesWidgetControl.Value(isRunning: isRunning, name: configuration.timerName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TimerConfiguration: ControlConfigurationIntent {
|
||||||
|
static let title: LocalizedStringResource = "Timer Name Configuration"
|
||||||
|
|
||||||
|
@Parameter(title: "Timer Name", default: "Timer")
|
||||||
|
var timerName: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StartTimerIntent: SetValueIntent {
|
||||||
|
static let title: LocalizedStringResource = "Start a timer"
|
||||||
|
|
||||||
|
@Parameter(title: "Timer Name")
|
||||||
|
var name: String
|
||||||
|
|
||||||
|
@Parameter(title: "Timer is running")
|
||||||
|
var value: Bool
|
||||||
|
|
||||||
|
init() {}
|
||||||
|
|
||||||
|
init(_ name: String) {
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult {
|
||||||
|
// Start the timer…
|
||||||
|
return .result()
|
||||||
|
}
|
||||||
|
}
|
||||||
80
FavoritesWidget/FavoritesWidgetLiveActivity.swift
Normal file
80
FavoritesWidget/FavoritesWidgetLiveActivity.swift
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
//
|
||||||
|
// FavoritesWidgetLiveActivity.swift
|
||||||
|
// FavoritesWidget
|
||||||
|
//
|
||||||
|
// Created by Platon on 08.08.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ActivityKit
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct FavoritesWidgetAttributes: ActivityAttributes {
|
||||||
|
public struct ContentState: Codable, Hashable {
|
||||||
|
// Dynamic stateful properties about your activity go here!
|
||||||
|
var emoji: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed non-changing properties about your activity go here!
|
||||||
|
var name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FavoritesWidgetLiveActivity: Widget {
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
ActivityConfiguration(for: FavoritesWidgetAttributes.self) { context in
|
||||||
|
// Lock screen/banner UI goes here
|
||||||
|
VStack {
|
||||||
|
Text("Hello \(context.state.emoji)")
|
||||||
|
}
|
||||||
|
.activityBackgroundTint(Color.cyan)
|
||||||
|
.activitySystemActionForegroundColor(Color.black)
|
||||||
|
|
||||||
|
} dynamicIsland: { context in
|
||||||
|
DynamicIsland {
|
||||||
|
// Expanded UI goes here. Compose the expanded UI through
|
||||||
|
// various regions, like leading/trailing/center/bottom
|
||||||
|
DynamicIslandExpandedRegion(.leading) {
|
||||||
|
Text("Leading")
|
||||||
|
}
|
||||||
|
DynamicIslandExpandedRegion(.trailing) {
|
||||||
|
Text("Trailing")
|
||||||
|
}
|
||||||
|
DynamicIslandExpandedRegion(.bottom) {
|
||||||
|
Text("Bottom \(context.state.emoji)")
|
||||||
|
// more content
|
||||||
|
}
|
||||||
|
} compactLeading: {
|
||||||
|
Text("L")
|
||||||
|
} compactTrailing: {
|
||||||
|
Text("T \(context.state.emoji)")
|
||||||
|
} minimal: {
|
||||||
|
Text(context.state.emoji)
|
||||||
|
}
|
||||||
|
.widgetURL(URL(string: "http://www.apple.com"))
|
||||||
|
.keylineTint(Color.red)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FavoritesWidgetAttributes {
|
||||||
|
fileprivate static var preview: FavoritesWidgetAttributes {
|
||||||
|
FavoritesWidgetAttributes(name: "World")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FavoritesWidgetAttributes.ContentState {
|
||||||
|
fileprivate static var smiley: FavoritesWidgetAttributes.ContentState {
|
||||||
|
FavoritesWidgetAttributes.ContentState(emoji: "😀")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate static var starEyes: FavoritesWidgetAttributes.ContentState {
|
||||||
|
FavoritesWidgetAttributes.ContentState(emoji: "🤩")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview("Notification", as: .content, using: FavoritesWidgetAttributes.preview) {
|
||||||
|
FavoritesWidgetLiveActivity()
|
||||||
|
} contentStates: {
|
||||||
|
FavoritesWidgetAttributes.ContentState.smiley
|
||||||
|
FavoritesWidgetAttributes.ContentState.starEyes
|
||||||
|
}
|
||||||
11
FavoritesWidget/Info.plist
Normal file
11
FavoritesWidget/Info.plist
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>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.widgetkit-extension</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
5
FavoritesWidgetExtension.entitlements
Normal file
5
FavoritesWidgetExtension.entitlements
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?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/>
|
||||||
|
</plist>
|
||||||
8
MobileMkch/MobileMkch.entitlements
Normal file
8
MobileMkch/MobileMkch.entitlements
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?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/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Loading…
x
Reference in New Issue
Block a user