feat: add PlatformWidget extension target
All checks were successful
Security Checks / dependency-audit (push) Successful in 13s
Security Checks / secret-scanning (push) Successful in 4s
Security Checks / dockerfile-lint (push) Successful in 3s

This commit is contained in:
2026-04-04 11:19:18 -05:00
parent c13259c2b5
commit a4ebe77973
10 changed files with 297 additions and 0 deletions

3
ios/Platform/AGENTS.md Normal file
View File

@@ -0,0 +1,3 @@
# AGENTS.md
- If using XcodeBuildMCP, use the installed XcodeBuildMCP skill before calling XcodeBuildMCP tools.

View File

@@ -52,8 +52,36 @@
A10047 /* FeedManagementSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10047 /* FeedManagementSheet.swift */; };
A10048 /* ScrollViewDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10048 /* ScrollViewDriver.swift */; };
F20549752F805F5800AE8DF5 /* ConfettiSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = F20549742F805F5800AE8DF5 /* ConfettiSwiftUI */; };
W10001 /* PlatformWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = W10010 /* PlatformWidgetBundle.swift */; };
W10002 /* PlatformWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = W10011 /* PlatformWidget.swift */; };
W10003 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = W10012 /* Assets.xcassets */; };
W10004 /* PlatformWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = W10020 /* PlatformWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
W10030 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = G10010 /* Project object */;
proxyType = 1;
remoteGlobalIDString = W10040;
remoteInfo = PlatformWidgetExtension;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
W10050 /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
W10004 /* PlatformWidgetExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
B10001 /* PlatformApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformApp.swift; sourceTree = "<group>"; };
B10002 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -101,6 +129,10 @@
B10048 /* ScrollViewDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewDriver.swift; sourceTree = "<group>"; };
C10001 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
D10001 /* Platform.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Platform.app; sourceTree = BUILT_PRODUCTS_DIR; };
W10010 /* PlatformWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformWidgetBundle.swift; sourceTree = "<group>"; };
W10011 /* PlatformWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformWidget.swift; sourceTree = "<group>"; };
W10012 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
W10020 /* PlatformWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PlatformWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -112,6 +144,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
W10060 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -119,6 +158,7 @@
isa = PBXGroup;
children = (
F10002 /* Platform */,
W10070 /* PlatformWidget */,
F10020 /* Products */,
);
sourceTree = "<group>";
@@ -283,10 +323,21 @@
isa = PBXGroup;
children = (
D10001 /* Platform.app */,
W10020 /* PlatformWidgetExtension.appex */,
);
name = Products;
sourceTree = "<group>";
};
W10070 /* PlatformWidget */ = {
isa = PBXGroup;
children = (
W10010 /* PlatformWidgetBundle.swift */,
W10011 /* PlatformWidget.swift */,
W10012 /* Assets.xcassets */,
);
path = PlatformWidget;
sourceTree = "<group>";
};
F10021 /* Feedback */ = {
isa = PBXGroup;
children = (
@@ -353,18 +404,45 @@
G10002 /* Sources */,
E10001 /* Frameworks */,
G10003 /* Resources */,
W10050 /* Embed Foundation Extensions */,
);
buildRules = (
);
dependencies = (
W10031 /* PBXTargetDependency */,
);
name = Platform;
productName = Platform;
productReference = D10001 /* Platform.app */;
productType = "com.apple.product-type.application";
};
W10040 /* PlatformWidgetExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = W10080 /* Build configuration list for PBXNativeTarget "PlatformWidgetExtension" */;
buildPhases = (
W10041 /* Sources */,
W10060 /* Frameworks */,
W10042 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = PlatformWidgetExtension;
productName = PlatformWidgetExtension;
productReference = W10020 /* PlatformWidgetExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */
/* Begin PBXTargetDependency section */
W10031 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = W10040 /* PlatformWidgetExtension */;
targetProxy = W10030 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXProject section */
G10010 /* Project object */ = {
isa = PBXProject;
@@ -376,6 +454,9 @@
G10001 = {
CreatedOnToolsVersion = 15.4;
};
W10040 = {
CreatedOnToolsVersion = 15.4;
};
};
};
buildConfigurationList = H10001 /* Build configuration list for PBXProject "Platform" */;
@@ -395,6 +476,7 @@
projectRoot = "";
targets = (
G10001 /* Platform */,
W10040 /* PlatformWidgetExtension */,
);
};
/* End PBXProject section */
@@ -408,6 +490,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
W10042 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
W10003 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -461,6 +551,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
W10041 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
W10001 /* PlatformWidgetBundle.swift in Sources */,
W10002 /* PlatformWidget.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
@@ -641,6 +740,58 @@
};
name = Release;
};
W10081 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = CRN5A2VZ79;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = PlatformWidget;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.quadjourney.Platform.PlatformWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
W10082 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = CRN5A2VZ79;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = PlatformWidget;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.quadjourney.Platform.PlatformWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -662,6 +813,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
W10080 /* Build configuration list for PBXNativeTarget "PlatformWidgetExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
W10081 /* Debug */,
W10082 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,15 @@
{
"originHash" : "0813d8074328ac339b3ad4d9e895dca3cbd4327633fce793259860c9993a0805",
"pins" : [
{
"identity" : "confettiswiftui",
"kind" : "remoteSourceControl",
"location" : "https://github.com/simibac/ConfettiSwiftUI",
"state" : {
"revision" : "9ae5bc2ce2149980884d4612321c3a266d6bf82c",
"version" : "3.0.0"
}
}
],
"version" : 3
}

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,62 @@
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
var entries: [SimpleEntry] = []
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
}
struct PlatformWidgetEntryView: View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("Platform")
.font(.headline)
Text(entry.date, style: .time)
.font(.caption)
}
}
}
struct PlatformWidget: Widget {
let kind: String = "PlatformWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
PlatformWidgetEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
}
.configurationDisplayName("Platform")
.description("Platform widget.")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
#Preview(as: .systemSmall) {
PlatformWidget()
} timeline: {
SimpleEntry(date: .now)
}

View File

@@ -0,0 +1,9 @@
import WidgetKit
import SwiftUI
@main
struct PlatformWidgetBundle: WidgetBundle {
var body: some Widget {
PlatformWidget()
}
}