Skip to content

Commit

Permalink
[Fixes #232] Implement iOS 16 lock screen widget
Browse files Browse the repository at this point in the history
  • Loading branch information
vinhnx committed Sep 1, 2022
1 parent 2c6308d commit b7e75a9
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 21 deletions.
16 changes: 16 additions & 0 deletions Clendar.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
A332087A27B80A01003D6DE9 /* ClendarApp+WhatsNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = A332087927B80A01003D6DE9 /* ClendarApp+WhatsNew.swift */; };
A337CFB425D2F8A400FAB76A /* AppPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A337CFB325D2F8A400FAB76A /* AppPermissions.swift */; };
A33B6D6A25C6EF3000E0C4FA /* MailComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A33B6D6925C6EF3000E0C4FA /* MailComposer.swift */; };
A33DDEAE28C1103E000E79B6 /* LockScreenWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = A33DDEAD28C1103E000E79B6 /* LockScreenWidget.swift */; };
A33DDEB028C112A6000E79B6 /* SmallCircularWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A33DDEAF28C112A6000E79B6 /* SmallCircularWidgetView.swift */; };
A33F80D122467A85009CC46A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A33F80D022467A85009CC46A /* Assets.xcassets */; };
A33F80DF22467A85009CC46A /* ClendarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A33F80DE22467A85009CC46A /* ClendarTests.swift */; };
A33F80EA22467A85009CC46A /* ClendarUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A33F80E922467A85009CC46A /* ClendarUITests.swift */; };
Expand Down Expand Up @@ -364,6 +366,8 @@
A332087927B80A01003D6DE9 /* ClendarApp+WhatsNew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ClendarApp+WhatsNew.swift"; sourceTree = "<group>"; };
A337CFB325D2F8A400FAB76A /* AppPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPermissions.swift; sourceTree = "<group>"; };
A33B6D6925C6EF3000E0C4FA /* MailComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposer.swift; sourceTree = "<group>"; };
A33DDEAD28C1103E000E79B6 /* LockScreenWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenWidget.swift; sourceTree = "<group>"; };
A33DDEAF28C112A6000E79B6 /* SmallCircularWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallCircularWidgetView.swift; sourceTree = "<group>"; };
A33EE21425C6E3D900BE80F1 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ClendarWidget.strings"; sourceTree = "<group>"; };
A33EE22025C6E46D00BE80F1 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/ClendarWidget.strings; sourceTree = "<group>"; };
A33EE22C25C6E8B600BE80F1 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/ClendarWidget.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -595,6 +599,7 @@
A3064D36254CF0D300C7F228 /* Widget */ = {
isa = PBXGroup;
children = (
A33DDEAC28C11023000E79B6 /* Lock Screen */,
A3FF45B425CAEE0A005DAE94 /* Event List */,
A33F846425AF33F0001324A0 /* Components */,
A3AFBD6F255F87EF00760E5B /* Main */,
Expand Down Expand Up @@ -737,6 +742,15 @@
path = original;
sourceTree = "<group>";
};
A33DDEAC28C11023000E79B6 /* Lock Screen */ = {
isa = PBXGroup;
children = (
A33DDEAD28C1103E000E79B6 /* LockScreenWidget.swift */,
A33DDEAF28C112A6000E79B6 /* SmallCircularWidgetView.swift */,
);
path = "Lock Screen";
sourceTree = "<group>";
};
A33F80BD22467A82009CC46A = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1535,6 +1549,7 @@
A307DAA925ACBA9C00B5CE11 /* LunarDateInfoWidget.swift in Sources */,
A342117B254CF7E7008D9B8E /* DateInfoWidgetEntryView.swift in Sources */,
A38A4DC6254D751C00B35F98 /* AppInfo.swift in Sources */,
A33DDEB028C112A6000E79B6 /* SmallCircularWidgetView.swift in Sources */,
A38A4DCA254D752200B35F98 /* ClendarEvent.swift in Sources */,
A38A4DAF254D743100B35F98 /* UserDefaultsWrapper.swift in Sources */,
A307DAAE25ACBAD700B5CE11 /* LunarSmallDateWidgetView.swift in Sources */,
Expand Down Expand Up @@ -1563,6 +1578,7 @@
A3D6839F25A9A4BF009C31D5 /* SettingsManager.swift in Sources */,
A371156E25C51AEB00D65F59 /* Color+Extensions.swift in Sources */,
A371157C25C51B9000D65F59 /* View+Gradient.swift in Sources */,
A33DDEAE28C1103E000E79B6 /* LockScreenWidget.swift in Sources */,
A3684755255445F0004BDCC6 /* String+Extensions.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,16 @@
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "32">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/Clendar">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A307DAB925ADD6B300B5CE11"
BuildableName = "ClendarWatchApp.app"
BlueprintName = "ClendarWatchApp"
ReferencedContainer = "container:Clendar.xcodeproj">
</BuildableReference>
</RemoteRunnable>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,16 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/Clendar">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A307DAB925ADD6B300B5CE11"
BuildableName = "ClendarWatchApp.app"
BlueprintName = "ClendarWatchApp"
ReferencedContainer = "container:Clendar.xcodeproj">
</BuildableReference>
</RemoteRunnable>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down
2 changes: 2 additions & 0 deletions Clendar/Helper/Utils/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ struct Constants {
case dateInfoWidget = "DateInfoWidget"
case lunarDateInfoWidget = "LunarDateInfoWidget"
case eventListWidget = "EventListWidget"
case lockScreenWidgetCounter = "LockScreenWidgetCounter"
case lockScreenWidgetNextEvent = "LockScreenWidgetNextEvent"
}
}
65 changes: 65 additions & 0 deletions ClendarWidget/Widget/Lock Screen/LockScreenWidget.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// LockScreenWidget.swift
// ClendarWidgetExtension
//
// Created by Vinh Nguyen on 01/09/2022.
// Copyright © 2022 Vinh Nguyen. All rights reserved.
//

import SwiftUI
import WidgetKit

struct LockScreenWidgetCounter: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: Constants.WidgetKind.lockScreenWidgetCounter.rawValue,
provider: DateInfoWidgetTimelineProvider()
) { entry in buildContentView(entry) }
.supportedFamilies(widgetFamilies)
}

private func buildContentView(_ entry: WidgetEntry) -> some View {
if #available(iOSApplicationExtension 16.0, *) {
return LockScreenWidgetView(entry: entry, style: .counter)
.widgetAccentable()
} else {
return EmptyView()
}
}
}

struct LockScreenWidgetNextEvent: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: Constants.WidgetKind.lockScreenWidgetNextEvent.rawValue,
provider: DateInfoWidgetTimelineProvider()
) { entry in buildContentView(entry) }
.supportedFamilies(widgetFamilies)
}

private func buildContentView(_ entry: WidgetEntry) -> some View {
if #available(iOSApplicationExtension 16.0, *) {
return LockScreenWidgetView(entry: entry, style: .nextEvent)
.widgetAccentable()
} else {
return EmptyView()
}
}
}

private var widgetFamilies: [WidgetFamily] {
if #available(iOSApplicationExtension 16.0, *) {
return [
.accessoryInline,
.accessoryCircular,
.accessoryRectangular
]
} else {
return [
.systemSmall,
.systemMedium,
.systemLarge,
.systemExtraLarge
]
}
}
71 changes: 71 additions & 0 deletions ClendarWidget/Widget/Lock Screen/SmallCircularWidgetView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// File.swift
// ClendarWidgetExtension
//
// Created by Vinh Nguyen on 01/09/2022.
// Copyright © 2022 Vinh Nguyen. All rights reserved.
//

import SwiftUI
import WidgetKit

enum LockScreenWidgetViewStyle {
case nextEvent
case counter
}

struct LockScreenWidgetView: View {
@Environment(\.widgetFamily) private var widgetFamily

let entry: WidgetEntry
let style: LockScreenWidgetViewStyle

var body: some View {
if #available(iOSApplicationExtension 16.0, *) {
ViewThatFits {
switch widgetFamily {
case .accessoryCircular:
ViewThatFits(in: .vertical) {
VStack(alignment: .center) {
Text(DateFormatter.asString(entry.date, format: "MMM").localizedUppercase)
.font(.boldFontWithSize(15))
Text(entry.date.toFullDayString())
.font(.regularFontWithSize(13))
}
}
.widgetAccentable()

case .accessoryRectangular:
ViewThatFits(in: .vertical) {
VStack(alignment: .leading, spacing: 5) {
Text(entry.date.toFullDateString().localizedUppercase)
.font(.boldFontWithSize(12))

Text(entry.events.isEmpty ? "🎉" : message)
.lineLimit(2)
.font(.mediumFontWithSize(12))
}
}
default:
Text(entry.date.toMonthString().localizedUppercase)
.font(.boldFontWithSize(15))
Text(entry.date.toFullDayString())
.font(.regularFontWithSize(13))

}

}
.widgetAccentable()
} else {
Text(entry.date.toFullDayString())
.font(.boldFontWithSize(15))
}
}

private var message: String {
switch style {
case .nextEvent: return entry.events.first?.event?.title ?? ""
case .counter: return "\(entry.events.count) \(NSLocalizedString("Events", comment: ""))"
}
}
}
8 changes: 8 additions & 0 deletions ClendarWidget/Widget/Main/ClendarWidgetBundle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct ClendarWidgetBundle: WidgetBundle {
DateInfoWidgetBundle().body
LunarWidgetBundle().body
EventListWidgetBundle().body
LockScreenWidgetBundle().body
}
}

Expand All @@ -42,3 +43,10 @@ struct LunarWidgetBundle: WidgetBundle {
LunarDateInfoWidget()
}
}

struct LockScreenWidgetBundle: WidgetBundle {
var body: some Widget {
LockScreenWidgetCounter()
LockScreenWidgetNextEvent()
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b7e75a9

Please sign in to comment.