From 2a5111b9dbc7280c8b686685f78e4740010f9df4 Mon Sep 17 00:00:00 2001 From: Krystof Date: Sun, 24 Nov 2024 20:41:19 +0100 Subject: [PATCH] feat(app): widgets init --- .../metro-now.xcodeproj/project.pbxproj | 186 ++++++++++++++++++ .../AccentColor.colorset/Contents.json | 11 ++ .../AppIcon.appiconset/Contents.json | 35 ++++ .../widgets/Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 ++ apps/mobile/metro-now/widgets/Info.plist | 11 ++ apps/mobile/metro-now/widgets/widgets.swift | 103 ++++++++++ .../metro-now/widgets/widgetsBundle.swift | 16 ++ 8 files changed, 379 insertions(+) create mode 100644 apps/mobile/metro-now/widgets/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 apps/mobile/metro-now/widgets/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 apps/mobile/metro-now/widgets/Assets.xcassets/Contents.json create mode 100644 apps/mobile/metro-now/widgets/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 apps/mobile/metro-now/widgets/Info.plist create mode 100644 apps/mobile/metro-now/widgets/widgets.swift create mode 100644 apps/mobile/metro-now/widgets/widgetsBundle.swift diff --git a/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj b/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj index 4a174a0b..30ff9763 100644 --- a/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj +++ b/apps/mobile/metro-now/metro-now.xcodeproj/project.pbxproj @@ -10,6 +10,9 @@ 2D001BB92CC8099C00C6B4F8 /* metro-now Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 2D001BB82CC8099C00C6B4F8 /* metro-now Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 2D87C85F2CE8BACA00209DE6 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2D87C85E2CE8BACA00209DE6 /* Alamofire */; }; 2D8EBE2E2CE93DC9004D5F5B /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2D8EBE2D2CE93DC9004D5F5B /* Alamofire */; }; + 2DD9D1792CF3B8A70037CB95 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD9D1782CF3B8A70037CB95 /* WidgetKit.framework */; }; + 2DD9D17B2CF3B8A70037CB95 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD9D17A2CF3B8A70037CB95 /* SwiftUI.framework */; }; + 2DD9D1862CF3B8A90037CB95 /* widgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 2DD9D1762CF3B8A70037CB95 /* widgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -27,6 +30,13 @@ remoteGlobalIDString = 2D001BA72CC8099B00C6B4F8; remoteInfo = "metro-now"; }; + 2DD9D1842CF3B8A90037CB95 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2D001BA02CC8099B00C6B4F8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2DD9D1752CF3B8A70037CB95; + remoteInfo = widgetsExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -41,12 +51,26 @@ name = "Embed Watch Content"; runOnlyForDeploymentPostprocessing = 0; }; + 2DD9D1872CF3B8A90037CB95 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 2DD9D1862CF3B8A90037CB95 /* widgetsExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 2D001BA82CC8099B00C6B4F8 /* metro-now.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "metro-now.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D001BB82CC8099C00C6B4F8 /* metro-now Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "metro-now Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D7FEC772CE96F300073FF5B /* metro-nowTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "metro-nowTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2DD9D1762CF3B8A70037CB95 /* widgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = widgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 2DD9D1782CF3B8A70037CB95 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 2DD9D17A2CF3B8A70037CB95 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ @@ -91,6 +115,23 @@ ); target = 2D001BB72CC8099C00C6B4F8 /* metro-now Watch App */; }; + 2DD9D18B2CF3B8A90037CB95 /* Exceptions for "widgets" folder in "widgetsExtension" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 2DD9D1752CF3B8A70037CB95 /* widgetsExtension */; + }; + 2DFF3B692CFD3D9600D8AB90 /* Exceptions for "common" folder in "widgetsExtension" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + "components/route-label-view/get-color-by-route-name.utils.swift", + "components/route-label-view/route-name.view.swift", + "components/route-label-view/route-type.enum.swift", + utils/color.utils.swift, + ); + target = 2DD9D1752CF3B8A70037CB95 /* widgetsExtension */; + }; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -114,10 +155,19 @@ exceptions = ( 2D9601C92CC812EF000EF3D5 /* Exceptions for "common" folder in "metro-now Watch App" target */, 2D7FEC812CE96F830073FF5B /* Exceptions for "common" folder in "metro-nowTests" target */, + 2DFF3B692CFD3D9600D8AB90 /* Exceptions for "common" folder in "widgetsExtension" target */, ); path = common; sourceTree = ""; }; + 2DD9D17C2CF3B8A70037CB95 /* widgets */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 2DD9D18B2CF3B8A90037CB95 /* Exceptions for "widgets" folder in "widgetsExtension" target */, + ); + path = widgets; + sourceTree = ""; + }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -144,6 +194,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 2DD9D1732CF3B8A70037CB95 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2DD9D17B2CF3B8A70037CB95 /* SwiftUI.framework in Frameworks */, + 2DD9D1792CF3B8A70037CB95 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -154,6 +213,8 @@ 2D001BAA2CC8099B00C6B4F8 /* metro-now */, 2D001BBC2CC8099C00C6B4F8 /* metro-now Watch App */, 2D7FEC782CE96F300073FF5B /* metro-nowTests */, + 2DD9D17C2CF3B8A70037CB95 /* widgets */, + 2DD9D1772CF3B8A70037CB95 /* Frameworks */, 2D001BA92CC8099B00C6B4F8 /* Products */, ); sourceTree = ""; @@ -164,10 +225,20 @@ 2D001BA82CC8099B00C6B4F8 /* metro-now.app */, 2D001BB82CC8099C00C6B4F8 /* metro-now Watch App.app */, 2D7FEC772CE96F300073FF5B /* metro-nowTests.xctest */, + 2DD9D1762CF3B8A70037CB95 /* widgetsExtension.appex */, ); name = Products; sourceTree = ""; }; + 2DD9D1772CF3B8A70037CB95 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2DD9D1782CF3B8A70037CB95 /* WidgetKit.framework */, + 2DD9D17A2CF3B8A70037CB95 /* SwiftUI.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -179,11 +250,13 @@ 2D001BA52CC8099B00C6B4F8 /* Frameworks */, 2D001BA62CC8099B00C6B4F8 /* Resources */, 2D001BCB2CC8099D00C6B4F8 /* Embed Watch Content */, + 2DD9D1872CF3B8A90037CB95 /* Embed Foundation Extensions */, ); buildRules = ( ); dependencies = ( 2D001BBB2CC8099C00C6B4F8 /* PBXTargetDependency */, + 2DD9D1852CF3B8A90037CB95 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 2D001BAA2CC8099B00C6B4F8 /* metro-now */, @@ -243,6 +316,28 @@ productReference = 2D7FEC772CE96F300073FF5B /* metro-nowTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 2DD9D1752CF3B8A70037CB95 /* widgetsExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2DD9D18A2CF3B8A90037CB95 /* Build configuration list for PBXNativeTarget "widgetsExtension" */; + buildPhases = ( + 2DD9D1722CF3B8A70037CB95 /* Sources */, + 2DD9D1732CF3B8A70037CB95 /* Frameworks */, + 2DD9D1742CF3B8A70037CB95 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 2DD9D17C2CF3B8A70037CB95 /* widgets */, + ); + name = widgetsExtension; + packageProductDependencies = ( + ); + productName = widgetsExtension; + productReference = 2DD9D1762CF3B8A70037CB95 /* widgetsExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -263,6 +358,9 @@ CreatedOnToolsVersion = 16.1; TestTargetID = 2D001BA72CC8099B00C6B4F8; }; + 2DD9D1752CF3B8A70037CB95 = { + CreatedOnToolsVersion = 16.1; + }; }; }; buildConfigurationList = 2D001BA32CC8099B00C6B4F8 /* Build configuration list for PBXProject "metro-now" */; @@ -285,6 +383,7 @@ 2D001BA72CC8099B00C6B4F8 /* metro-now */, 2D001BB72CC8099C00C6B4F8 /* metro-now Watch App */, 2D7FEC762CE96F300073FF5B /* metro-nowTests */, + 2DD9D1752CF3B8A70037CB95 /* widgetsExtension */, ); }; /* End PBXProject section */ @@ -311,6 +410,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 2DD9D1742CF3B8A70037CB95 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -335,6 +441,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 2DD9D1722CF3B8A70037CB95 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -348,6 +461,11 @@ target = 2D001BA72CC8099B00C6B4F8 /* metro-now */; targetProxy = 2D7FEC7B2CE96F300073FF5B /* PBXContainerItemProxy */; }; + 2DD9D1852CF3B8A90037CB95 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2DD9D1752CF3B8A70037CB95 /* widgetsExtension */; + targetProxy = 2DD9D1842CF3B8A90037CB95 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -644,6 +762,65 @@ }; name = Release; }; + 2DD9D1882CF3B8A90037CB95 /* 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 = 6; + DEVELOPMENT_TEAM = R6WU5ABNG2; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = widgets/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = widgets; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 0.3.4; + PRODUCT_BUNDLE_IDENTIFIER = "com.krystof.metro-now.widgets"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2DD9D1892CF3B8A90037CB95 /* 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 = 6; + DEVELOPMENT_TEAM = R6WU5ABNG2; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = widgets/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = widgets; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 0.3.4; + PRODUCT_BUNDLE_IDENTIFIER = "com.krystof.metro-now.widgets"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -683,6 +860,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 2DD9D18A2CF3B8A90037CB95 /* Build configuration list for PBXNativeTarget "widgetsExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2DD9D1882CF3B8A90037CB95 /* Debug */, + 2DD9D1892CF3B8A90037CB95 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ diff --git a/apps/mobile/metro-now/widgets/Assets.xcassets/AccentColor.colorset/Contents.json b/apps/mobile/metro-now/widgets/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..b246f6b1 --- /dev/null +++ b/apps/mobile/metro-now/widgets/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors": [ + { + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/apps/mobile/metro-now/widgets/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/mobile/metro-now/widgets/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..208e83e1 --- /dev/null +++ b/apps/mobile/metro-now/widgets/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -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 + } +} diff --git a/apps/mobile/metro-now/widgets/Assets.xcassets/Contents.json b/apps/mobile/metro-now/widgets/Assets.xcassets/Contents.json new file mode 100644 index 00000000..dd65c04e --- /dev/null +++ b/apps/mobile/metro-now/widgets/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/apps/mobile/metro-now/widgets/Assets.xcassets/WidgetBackground.colorset/Contents.json b/apps/mobile/metro-now/widgets/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 00000000..b246f6b1 --- /dev/null +++ b/apps/mobile/metro-now/widgets/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors": [ + { + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/apps/mobile/metro-now/widgets/Info.plist b/apps/mobile/metro-now/widgets/Info.plist new file mode 100644 index 00000000..0f118fb7 --- /dev/null +++ b/apps/mobile/metro-now/widgets/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/apps/mobile/metro-now/widgets/widgets.swift b/apps/mobile/metro-now/widgets/widgets.swift new file mode 100644 index 00000000..0fdab14f --- /dev/null +++ b/apps/mobile/metro-now/widgets/widgets.swift @@ -0,0 +1,103 @@ +// metro-now +// https://github.com/krystxf/metro-now + +import SwiftUI +import WidgetKit + +struct Provider: TimelineProvider { + func placeholder(in _: Context) -> SimpleEntry { + SimpleEntry(date: Date()) + } + + func getSnapshot(in _: Context, completion: @escaping (SimpleEntry) -> Void) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + func getTimeline(in _: Context, completion: @escaping (Timeline) -> Void) { + 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) + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date +} + +struct widgetsEntryView: View { + var entry: Provider.Entry + @Environment(\.widgetFamily) var widgetFamily + + var body: some View { + VStack { + Text("🚇 metro-now") + .font(.headline) + Text("coming soon") + .font(.subheadline) + + Spacer() + VStack { + Text(widgetFamily.description.lowercased()) + Text("Last update: ") + Text(entry.date, style: .time) + } + .font(.footnote) + } + } +} + +struct widgets: Widget { + let kind: String = "widgets" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + if #available(iOS 17.0, *) { + widgetsEntryView(entry: entry) + .containerBackground(.fill.tertiary, for: .widget) + } else { + widgetsEntryView(entry: entry) + .padding() + .background() + } + } + .configurationDisplayName("My Widget") + .description("This is an example widget.") + } +} + +#Preview("small", as: .systemSmall) { + widgets() +} timeline: { + SimpleEntry(date: .now) + SimpleEntry(date: .now) +} + +#Preview("medium", as: .systemMedium) { + widgets() +} timeline: { + SimpleEntry(date: .now) + SimpleEntry(date: .now) +} + +#Preview("large", as: .systemLarge) { + widgets() +} timeline: { + SimpleEntry(date: .now) + SimpleEntry(date: .now) +} + +#Preview("extra large", as: .systemExtraLarge) { + widgets() +} timeline: { + SimpleEntry(date: .now) + SimpleEntry(date: .now) +} diff --git a/apps/mobile/metro-now/widgets/widgetsBundle.swift b/apps/mobile/metro-now/widgets/widgetsBundle.swift new file mode 100644 index 00000000..6bc7049c --- /dev/null +++ b/apps/mobile/metro-now/widgets/widgetsBundle.swift @@ -0,0 +1,16 @@ +// +// widgetsBundle.swift +// widgets +// +// Created by Kryštof Krátký on 24.11.2024. +// + +import SwiftUI +import WidgetKit + +@main +struct widgetsBundle: WidgetBundle { + var body: some Widget { + widgets() + } +}