diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 27e8ef43b1d9..d0be3d123124 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2880,6 +2880,10 @@ C9FE383829C206AE00D39841 /* LockScreenWidgetViewModelMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE382A29C204E700D39841 /* LockScreenWidgetViewModelMapper.swift */; }; C9FE383929C2077700D39841 /* LockScreenSingleStatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE382B29C204E700D39841 /* LockScreenSingleStatViewModel.swift */; }; C9FE383A29C207F600D39841 /* HomeWidgetData+StatsURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE382129C2040600D39841 /* HomeWidgetData+StatsURL.swift */; }; + C9FE384029C2A3D200D39841 /* LockScreenTodayViewsStatWidgetConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE383C29C2A3D100D39841 /* LockScreenTodayViewsStatWidgetConfig.swift */; }; + C9FE384129C2A3D200D39841 /* LockScreenTodayViewsStatWidgetConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE383C29C2A3D100D39841 /* LockScreenTodayViewsStatWidgetConfig.swift */; }; + C9FE384629C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE383F29C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift */; }; + C9FE384729C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE383F29C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift */; }; CB1FD8D826E4BBAA00EDAF06 /* SharePostTypePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB48172926E0D93D008C2D9B /* SharePostTypePickerViewController.swift */; }; CB48172A26E0D93D008C2D9B /* SharePostTypePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB48172926E0D93D008C2D9B /* SharePostTypePickerViewController.swift */; }; CBF6201326E8FB520061A1F8 /* RemotePost+ShareData.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF6201226E8FB520061A1F8 /* RemotePost+ShareData.swift */; }; @@ -8119,6 +8123,8 @@ C9FE382B29C204E700D39841 /* LockScreenSingleStatViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockScreenSingleStatViewModel.swift; sourceTree = ""; }; C9FE383029C2053300D39841 /* LockScreenSingleStatView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockScreenSingleStatView.swift; sourceTree = ""; }; C9FE383629C2067E00D39841 /* WidgetsViewModelMapperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetsViewModelMapperTests.swift; sourceTree = ""; }; + C9FE383C29C2A3D100D39841 /* LockScreenTodayViewsStatWidgetConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockScreenTodayViewsStatWidgetConfig.swift; sourceTree = ""; }; + C9FE383F29C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockScreenStatsWidgetConfig.swift; sourceTree = ""; }; CB1DAFB7DE085F2FF0314622 /* Pods-WordPressShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressShareExtension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressShareExtension/Pods-WordPressShareExtension.debug.xcconfig"; sourceTree = ""; }; CB1FD8D926E605CF00EDAF06 /* Extensions 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Extensions 4.xcdatamodel"; sourceTree = ""; }; CB48172926E0D93D008C2D9B /* SharePostTypePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharePostTypePickerViewController.swift; sourceTree = ""; }; @@ -15662,6 +15668,7 @@ isa = PBXGroup; children = ( C9C21D7629BECFC1009F68E5 /* LockScreenStatsWidget.swift */, + C9FE383B29C2A3A300D39841 /* Configs */, C9FE382929C204D700D39841 /* Models */, C9C21D8829BF4998009F68E5 /* Views */, C9FE382529C204A500D39841 /* ViewProvider */, @@ -15711,6 +15718,15 @@ path = Widgets; sourceTree = ""; }; + C9FE383B29C2A3A300D39841 /* Configs */ = { + isa = PBXGroup; + children = ( + C9FE383F29C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift */, + C9FE383C29C2A3D100D39841 /* LockScreenTodayViewsStatWidgetConfig.swift */, + ); + path = Configs; + sourceTree = ""; + }; CC098B8116A9EB0400450976 /* HTML */ = { isa = PBXGroup; children = ( @@ -20477,6 +20493,7 @@ 0107E0B828F97D5000DE87DB /* KeychainUtils.swift in Sources */, 0107E0B928F97D5000DE87DB /* BuildConfiguration.swift in Sources */, 0107E0BA28F97D5000DE87DB /* TodayWidgetStats.swift in Sources */, + C9FE384129C2A3D200D39841 /* LockScreenTodayViewsStatWidgetConfig.swift in Sources */, 0107E16128FFE99300DE87DB /* WidgetConfiguration.swift in Sources */, 0107E0BB28F97D5000DE87DB /* StatsWidgetsService.swift in Sources */, 0107E0BC28F97D5000DE87DB /* StatsWidgetsView.swift in Sources */, @@ -20505,6 +20522,7 @@ 0107E18A29000E1500DE87DB /* MurielColor.swift in Sources */, 0107E0D028F97D5000DE87DB /* WordPressHomeWidgetThisWeek.swift in Sources */, C9FE382D29C204E700D39841 /* LockScreenWidgetViewModelMapper.swift in Sources */, + C9FE384729C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift in Sources */, 0107E0D128F97D5000DE87DB /* SingleStatView.swift in Sources */, 0107E0D228F97D5000DE87DB /* UnconfiguredView.swift in Sources */, 0107E1852900059300DE87DB /* LocalizationConfiguration.swift in Sources */, @@ -22342,6 +22360,7 @@ 83A1B19A28AFE47C00E737AC /* KeychainUtils.swift in Sources */, 3F6BC06D25B24787007369D3 /* BuildConfiguration.swift in Sources */, 3F1FD2502548AD8B0060C53A /* TodayWidgetStats.swift in Sources */, + C9FE384029C2A3D200D39841 /* LockScreenTodayViewsStatWidgetConfig.swift in Sources */, 0107E16A28FFED1800DE87DB /* WidgetConfiguration.swift in Sources */, 3F2F0C16256C6B2C003351C7 /* StatsWidgetsService.swift in Sources */, 3F526D572539FAC60069706C /* StatsWidgetsView.swift in Sources */, @@ -22370,6 +22389,7 @@ 0107E18B29000E1700DE87DB /* MurielColor.swift in Sources */, 3F8B138F25D09AA5004FAC0A /* WordPressHomeWidgetThisWeek.swift in Sources */, C9FE382C29C204E700D39841 /* LockScreenWidgetViewModelMapper.swift in Sources */, + C9FE384629C2A3D200D39841 /* LockScreenStatsWidgetConfig.swift in Sources */, 3F5689F0254209790048A9E4 /* SingleStatView.swift in Sources */, 3FAA18CC25797B85002B1911 /* UnconfiguredView.swift in Sources */, 0107E1872900065500DE87DB /* LocalizationConfiguration.swift in Sources */, diff --git a/WordPress/WordPressStatsWidgets/LockScreenWidgets/Configs/LockScreenStatsWidgetConfig.swift b/WordPress/WordPressStatsWidgets/LockScreenWidgets/Configs/LockScreenStatsWidgetConfig.swift new file mode 100644 index 000000000000..2f6144f51f2e --- /dev/null +++ b/WordPress/WordPressStatsWidgets/LockScreenWidgets/Configs/LockScreenStatsWidgetConfig.swift @@ -0,0 +1,13 @@ +import WidgetKit + +protocol LockScreenStatsWidgetConfig { + associatedtype WidgetData: HomeWidgetData + associatedtype ViewProvider: LockScreenStatsWidgetsViewProvider + + var supportFamilies: [WidgetFamily] { get } + var displayName: String { get } + var description: String { get } + var kind: String { get } + var placeholderContent: WidgetData { get } + var viewProvider: ViewProvider { get } +} diff --git a/WordPress/WordPressStatsWidgets/LockScreenWidgets/Configs/LockScreenTodayViewsStatWidgetConfig.swift b/WordPress/WordPressStatsWidgets/LockScreenWidgets/Configs/LockScreenTodayViewsStatWidgetConfig.swift new file mode 100644 index 000000000000..1a257bcb1e18 --- /dev/null +++ b/WordPress/WordPressStatsWidgets/LockScreenWidgets/Configs/LockScreenTodayViewsStatWidgetConfig.swift @@ -0,0 +1,48 @@ +import WidgetKit + +@available(iOS 16.0, *) +struct LockScreenTodayViewsStatWidgetConfig: LockScreenStatsWidgetConfig { + typealias WidgetData = HomeWidgetTodayData + typealias ViewProvider = LockScreenSingleStatWidgetViewProvider + + var supportFamilies: [WidgetFamily] { + guard AppConfiguration.isJetpack, FeatureFlag.lockScreenWidget.enabled else { + return [] + } + return [.accessoryRectangular] + } + + var displayName: String { + LocalizableStrings.viewsInTodayTitle + } + + var description: String { + LocalizableStrings.todayPreviewDescription + } + + var kind: String { + AppConfiguration.Widget.Stats.lockScreenTodayViewsKind + } + + var placeholderContent: HomeWidgetTodayData { + HomeWidgetTodayData( + siteID: 0, + siteName: "My WordPress Site", + url: "", + timeZone: TimeZone.current, + date: Date(), + stats: TodayWidgetStats( + views: 649, + visitors: 572, + likes: 16, + comments: 8 + ) + ) + } + + var viewProvider: ViewProvider { + LockScreenSingleStatWidgetViewProvider( + title: LocalizableStrings.viewsInTodayTitle + ) + } +} diff --git a/WordPress/WordPressStatsWidgets/LockScreenWidgets/LockScreenStatsWidget.swift b/WordPress/WordPressStatsWidgets/LockScreenWidgets/LockScreenStatsWidget.swift index 2dbf80c2313d..b4b7f288038c 100644 --- a/WordPress/WordPressStatsWidgets/LockScreenWidgets/LockScreenStatsWidget.swift +++ b/WordPress/WordPressStatsWidgets/LockScreenWidgets/LockScreenStatsWidget.swift @@ -2,46 +2,36 @@ import WidgetKit import SwiftUI @available(iOS 16.0, *) -struct LockScreenStatsWidget: Widget { - private let placeholderContent = HomeWidgetTodayData( - siteID: 0, - siteName: "My WordPress Site", - url: "", - timeZone: TimeZone.current, - date: Date(), - stats: TodayWidgetStats(views: 649, - visitors: 572, - likes: 16, - comments: 8)) +struct LockScreenStatsWidget: Widget { + private let config: T + + init(config: T) { + self.config = config + } + + @available(*, deprecated, renamed: "init(config:)") + init() { + fatalError("Please use init(config: SingleStatWidgetConfig) to provide the config") + } var body: some WidgetConfiguration { IntentConfiguration( - kind: AppConfiguration.Widget.Stats.lockScreenTodayViewsKind, + kind: config.kind, intent: SelectSiteIntent.self, - provider: SiteListProvider( + provider: SiteListProvider( service: StatsWidgetsService(), - placeholderContent: placeholderContent, + placeholderContent: config.placeholderContent, + // TODO: remove widgetKind in creating lock screen widget provider and entry PR widgetKind: .today ) ) { (entry: StatsWidgetEntry) -> LockScreenStatsWidgetsView in return LockScreenStatsWidgetsView( timelineEntry: entry, - viewProvider: LockScreenSingleStatWidgetViewProvider() + viewProvider: config.viewProvider ) } - .configurationDisplayName(LocalizableStrings.todayWidgetTitle) - .description(LocalizableStrings.todayPreviewDescription) - .supportedFamilies(supportedFamilies()) - } -} - -@available(iOS 16.0, *) -extension LockScreenStatsWidget { - // TODO: Move to widget config after PR #20317 merged - func supportedFamilies() -> [WidgetFamily] { - guard AppConfiguration.isJetpack, FeatureFlag.lockScreenWidget.enabled else { - return [] - } - return [.accessoryRectangular] + .configurationDisplayName(config.displayName) + .description(config.description) + .supportedFamilies(config.supportFamilies) } } diff --git a/WordPress/WordPressStatsWidgets/LockScreenWidgets/ViewProvider/LockScreenSingleStatWidgetViewProvider.swift b/WordPress/WordPressStatsWidgets/LockScreenWidgets/ViewProvider/LockScreenSingleStatWidgetViewProvider.swift index 590b347d25b0..b71361f0cb91 100644 --- a/WordPress/WordPressStatsWidgets/LockScreenWidgets/ViewProvider/LockScreenSingleStatWidgetViewProvider.swift +++ b/WordPress/WordPressStatsWidgets/LockScreenWidgets/ViewProvider/LockScreenSingleStatWidgetViewProvider.swift @@ -3,11 +3,16 @@ import SwiftUI @available(iOS 16.0, *) struct LockScreenSingleStatWidgetViewProvider: LockScreenStatsWidgetsViewProvider { typealias SiteSelectedView = LockScreenSingleStatView + typealias LoggedOutView = Text + typealias NoSiteView = Text + typealias NoDataView = Text + + let title: String func buildSiteSelectedView(_ data: HomeWidgetData) -> LockScreenSingleStatView { let mapper = LockScreenWidgetViewModelMapper(data: data) let viewModel = mapper.getLockScreenSingleStatViewModel( - title: LocalizableStrings.viewsInTodayTitle + title: title ) return LockScreenSingleStatView(viewModel: viewModel) } @@ -16,4 +21,19 @@ struct LockScreenSingleStatWidgetViewProvider: LockScreenStatsWidgetsViewProvide let mapper = LockScreenWidgetViewModelMapper(data: data) return mapper.getStatsURL() } + + // TODO: Build view for loggedOut status + func buildLoggedOutView() -> Text { + Text("Build Later") + } + + // TODO: Build view for noSite status + func buildNoSiteView() -> Text { + Text("Build Later") + } + + // TODO: Build view for noData status + func buildNoDataView() -> Text { + Text("Build Later") + } } diff --git a/WordPress/WordPressStatsWidgets/LockScreenWidgets/Views/LockScreenStatsWidgetsView.swift b/WordPress/WordPressStatsWidgets/LockScreenWidgets/Views/LockScreenStatsWidgetsView.swift index 12fdc0d8bb19..6b2cd60437fe 100644 --- a/WordPress/WordPressStatsWidgets/LockScreenWidgets/Views/LockScreenStatsWidgetsView.swift +++ b/WordPress/WordPressStatsWidgets/LockScreenWidgets/Views/LockScreenStatsWidgetsView.swift @@ -3,10 +3,22 @@ import WidgetKit protocol LockScreenStatsWidgetsViewProvider { associatedtype SiteSelectedView: View + associatedtype LoggedOutView: View + associatedtype NoSiteView: View + associatedtype NoDataView: View @ViewBuilder func buildSiteSelectedView(_ data: HomeWidgetData) -> SiteSelectedView + @ViewBuilder + func buildLoggedOutView() -> LoggedOutView + + @ViewBuilder + func buildNoSiteView() -> NoSiteView + + @ViewBuilder + func buildNoDataView() -> NoDataView + func statsURL(_ data: HomeWidgetData) -> URL? } @@ -21,9 +33,22 @@ struct LockScreenStatsWidgetsView: View { viewProvider .buildSiteSelectedView(data) .widgetURL(viewProvider.statsURL(data)) - default: - // TODO: Build view for loggedOut, noSite, noData status - Text("Build Later") + case .loggedOut: + viewProvider + .buildLoggedOutView() + .widgetURL(nil) + case .noSite: + viewProvider + .buildNoSiteView() + .widgetURL(nil) + case .noData: + viewProvider + .buildNoDataView() + .widgetURL(nil) + case .disabled: + // TODO: Remove disabled case when adding lock screen TimeLineProvider and Entry + // Lock Screen widget should not have disable status + EmptyView() } } } diff --git a/WordPress/WordPressStatsWidgets/StatsWidgets.swift b/WordPress/WordPressStatsWidgets/StatsWidgets.swift index b5c01a91571f..d415471dd090 100644 --- a/WordPress/WordPressStatsWidgets/StatsWidgets.swift +++ b/WordPress/WordPressStatsWidgets/StatsWidgets.swift @@ -8,7 +8,7 @@ struct WordPressStatsWidgets: WidgetBundle { WordPressHomeWidgetThisWeek() WordPressHomeWidgetAllTime() if #available(iOS 16.0, *) { - LockScreenStatsWidget() + LockScreenStatsWidget(config: LockScreenTodayViewsStatWidgetConfig()) } } } diff --git a/WordPress/WordPressStatsWidgets/Views/Localization/LocalizableStrings.swift b/WordPress/WordPressStatsWidgets/Views/Localization/LocalizableStrings.swift index def04a1540ce..719250f13ab5 100644 --- a/WordPress/WordPressStatsWidgets/Views/Localization/LocalizableStrings.swift +++ b/WordPress/WordPressStatsWidgets/Views/Localization/LocalizableStrings.swift @@ -16,7 +16,7 @@ enum LocalizableStrings { value: "This Week", comment: "Title of this week widget") - // Lock Screen Widgets content + // Lock Screen Widgets title static let viewsInTodayTitle = AppLocalizedString("widget.lockscreen.todayview.label", value: "Views Today", comment: "Title of the one-liner information consist of views field and today date range in lock screen today views widget")