Skip to content

Commit

Permalink
Merge pull request #1192 from TortugaPower/fix-widgets
Browse files Browse the repository at this point in the history
Rework widgets to better support iOS 18
  • Loading branch information
GianniCarlo authored Oct 2, 2024
2 parents 5b73bcc + 1fed5e4 commit 80dc100
Show file tree
Hide file tree
Showing 20 changed files with 649 additions and 361 deletions.
52 changes: 48 additions & 4 deletions BookPlayer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@
638E64CE2B8E1CFD00DCFA3B /* SyncTasksCountService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638E64CD2B8E1CFD00DCFA3B /* SyncTasksCountService.swift */; };
638E64CF2B8E1CFD00DCFA3B /* SyncTasksCountService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638E64CD2B8E1CFD00DCFA3B /* SyncTasksCountService.swift */; };
6397206F2CA71D600045A4DB /* .swift-format in Resources */ = {isa = PBXBuildFile; fileRef = 6397206E2CA71D600045A4DB /* .swift-format */; };
639720722CAAF8290045A4DB /* LastPlayedProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639720712CAAF8290045A4DB /* LastPlayedProvider.swift */; };
639720742CAAFB010045A4DB /* WidgetLibraryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639720732CAAFB010045A4DB /* WidgetLibraryItem.swift */; };
639720752CAAFB010045A4DB /* WidgetLibraryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639720732CAAFB010045A4DB /* WidgetLibraryItem.swift */; };
639720832CAB0C380045A4DB /* LastPlayedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639720822CAB0C380045A4DB /* LastPlayedView.swift */; };
639720852CABB0D00045A4DB /* RecentBooksProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639720842CABB0D00045A4DB /* RecentBooksProvider.swift */; };
6397208A2CAC5C870045A4DB /* LastPlayedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639720892CAC5C870045A4DB /* LastPlayedModel.swift */; };
6399F94D2AA03C6C00A5C8EA /* BPSKANManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6399F94C2AA03C6C00A5C8EA /* BPSKANManager.swift */; };
639AC9892AD9F1D50053AFC6 /* BPDownloadURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639AC9882AD9F1D50053AFC6 /* BPDownloadURLSession.swift */; };
639AC98A2AD9F1D50053AFC6 /* BPDownloadURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639AC9882AD9F1D50053AFC6 /* BPDownloadURLSession.swift */; };
Expand Down Expand Up @@ -411,7 +417,6 @@
63B760FC2C33B77F00AA98C7 /* SupportProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B760FB2C33B77F00AA98C7 /* SupportProfileView.swift */; };
63C1A8AF2B09158600C4B418 /* BookStartPlaybackIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634E67432AFB2DF500595BAC /* BookStartPlaybackIntent.swift */; };
63C1A8B02B0915EE00C4B418 /* WidgetUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 418445C2258AE11E0072DD13 /* WidgetUtils.swift */; };
63C1A8B12B09165400C4B418 /* RecentBooksWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41ADD6D92570AC6300660C64 /* RecentBooksWidgetView.swift */; };
63C1A8B22B09166F00C4B418 /* WidgetEntries.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637DAB092AEB3E0D006DC2D1 /* WidgetEntries.swift */; };
63C6C2E62B5029BC00FFE0D8 /* SettingsAutolockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C6C2E52B5029BC00FFE0D8 /* SettingsAutolockView.swift */; };
63C6C2E82B5029FE00FFE0D8 /* SettingsAutolockViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C6C2E72B5029FE00FFE0D8 /* SettingsAutolockViewModel.swift */; };
Expand Down Expand Up @@ -1160,6 +1165,11 @@
638E64CA2B8E086400DCFA3B /* RealmManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmManager.swift; sourceTree = "<group>"; };
638E64CD2B8E1CFD00DCFA3B /* SyncTasksCountService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncTasksCountService.swift; sourceTree = "<group>"; };
6397206E2CA71D600045A4DB /* .swift-format */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".swift-format"; sourceTree = "<group>"; };
639720712CAAF8290045A4DB /* LastPlayedProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastPlayedProvider.swift; sourceTree = "<group>"; };
639720732CAAFB010045A4DB /* WidgetLibraryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetLibraryItem.swift; sourceTree = "<group>"; };
639720822CAB0C380045A4DB /* LastPlayedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastPlayedView.swift; sourceTree = "<group>"; };
639720842CABB0D00045A4DB /* RecentBooksProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentBooksProvider.swift; sourceTree = "<group>"; };
639720892CAC5C870045A4DB /* LastPlayedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastPlayedModel.swift; sourceTree = "<group>"; };
6399F94C2AA03C6C00A5C8EA /* BPSKANManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BPSKANManager.swift; sourceTree = "<group>"; };
639AC9882AD9F1D50053AFC6 /* BPDownloadURLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BPDownloadURLSession.swift; sourceTree = "<group>"; };
639E12C52B85AACF00C875F7 /* SyncTasksObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncTasksObject.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2013,6 +2023,7 @@
62793619272CD9800097837D /* Lightweight-Models */ = {
isa = PBXGroup;
children = (
639720732CAAFB010045A4DB /* WidgetLibraryItem.swift */,
9FB20EA429A281140021663B /* DownloadState.swift */,
41188D3026ED715D0017124E /* SimpleLibraryItem.swift */,
9FFCC08E289418CA00F4952E /* SimpleChapter.swift */,
Expand Down Expand Up @@ -2220,6 +2231,34 @@
path = PerformanceTests;
sourceTree = "<group>";
};
639720702CAAF8180045A4DB /* LastPlayed */ = {
isa = PBXGroup;
children = (
417D9993256DE3FB00C3B753 /* LastPlayedWidgetView.swift */,
639720822CAB0C380045A4DB /* LastPlayedView.swift */,
639720892CAC5C870045A4DB /* LastPlayedModel.swift */,
639720712CAAF8290045A4DB /* LastPlayedProvider.swift */,
);
path = LastPlayed;
sourceTree = "<group>";
};
639720772CAAFCAF0045A4DB /* Recent */ = {
isa = PBXGroup;
children = (
639720782CAAFCBB0045A4DB /* Deprecated */,
);
path = Recent;
sourceTree = "<group>";
};
639720782CAAFCBB0045A4DB /* Deprecated */ = {
isa = PBXGroup;
children = (
41ADD6D92570AC6300660C64 /* RecentBooksWidgetView.swift */,
639720842CABB0D00045A4DB /* RecentBooksProvider.swift */,
);
path = Deprecated;
sourceTree = "<group>";
};
63B2303B2B8CCDDB00AEECED /* Realm */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2266,8 +2305,8 @@
4106413E258725F1008EB8D0 /* TimeListened */,
637DAB092AEB3E0D006DC2D1 /* WidgetEntries.swift */,
418445C2258AE11E0072DD13 /* WidgetUtils.swift */,
417D9993256DE3FB00C3B753 /* LastPlayedWidgetView.swift */,
41ADD6D92570AC6300660C64 /* RecentBooksWidgetView.swift */,
639720702CAAF8180045A4DB /* LastPlayed */,
639720772CAAFCAF0045A4DB /* Recent */,
);
path = Phone;
sourceTree = "<group>";
Expand Down Expand Up @@ -3377,6 +3416,7 @@
41D20DB325D5F5A100AAEE30 /* MappingModel_v1_to_v2.xcmappingmodel in Sources */,
63C6C31A2B5E102200FFE0D8 /* SyncTask.swift in Sources */,
9F07B79929B770B7005A939D /* BPTaskUploadDelegate.swift in Sources */,
639720752CAAFB010045A4DB /* WidgetLibraryItem.swift in Sources */,
63B230432B8CCE8700AEECED /* Realm+BookPlayer.swift in Sources */,
4124AB1825DFE07E0007C839 /* DataMigrationManager.swift in Sources */,
41C3394A25E04091003ED2B0 /* MappingModel_v2_to_v3.xcmappingmodel in Sources */,
Expand Down Expand Up @@ -3416,6 +3456,7 @@
630826062AF525F1002ACE0D /* SharedWidgetContainerView.swift in Sources */,
4106414925872699008EB8D0 /* TimeListenedSmallView.swift in Sources */,
417D996F256D73B400C3B753 /* Intents.intentdefinition in Sources */,
6397208A2CAC5C870045A4DB /* LastPlayedModel.swift in Sources */,
417D9994256DE3FB00C3B753 /* LastPlayedWidgetView.swift in Sources */,
41A359C7276232E00020D5F5 /* MappingModel_v7_to_v8.xcmappingmodel in Sources */,
416A29AA2569658100605395 /* BookPlayerWidgets.swift in Sources */,
Expand All @@ -3435,7 +3476,10 @@
630826162AF6CABD002ACE0D /* SharedIconWidgetEntry.swift in Sources */,
9FF383D52A40F97000BBAC11 /* MappingModel_v8_to_v9.xcmappingmodel in Sources */,
634E67462AFC7DEF00595BAC /* BookStartPlaybackIntent.swift in Sources */,
639720832CAB0C380045A4DB /* LastPlayedView.swift in Sources */,
639720852CABB0D00045A4DB /* RecentBooksProvider.swift in Sources */,
630826072AF52831002ACE0D /* SharedWidget.swift in Sources */,
639720722CAAF8290045A4DB /* LastPlayedProvider.swift in Sources */,
630826022AF295AE002ACE0D /* CornerView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -3587,7 +3631,6 @@
9F5FBB08293EDCD8009F4B0E /* ItemDetailsViewController.swift in Sources */,
634BA5AD2C180F5E0015314D /* StoryViewModel.swift in Sources */,
9F2681B628898A7300359BD3 /* LoginDisclaimerView.swift in Sources */,
63C1A8B12B09165400C4B418 /* RecentBooksWidgetView.swift in Sources */,
9FD8D95829DC53750074C2D8 /* CoreServices.swift in Sources */,
9F4691F22800D58A00A8F0E8 /* CompleteAccountCoordinator.swift in Sources */,
9F00A5F6294F793F005EA316 /* ItemDetailsView.swift in Sources */,
Expand Down Expand Up @@ -3774,6 +3817,7 @@
639E12C62B85AACF00C875F7 /* SyncTasksObject.swift in Sources */,
9F56C84D287B734C00EA9751 /* BPLogger.swift in Sources */,
418CABB425EF28FC00D8C878 /* MappingModel_v3_to_v4.xcmappingmodel in Sources */,
639720742CAAFB010045A4DB /* WidgetLibraryItem.swift in Sources */,
41A1B121226F88C500EA0400 /* PlaybackRecord+CoreDataClass.swift in Sources */,
9F9F3B70280E4E4B004359DA /* SyncService.swift in Sources */,
41A1B104226E9DBA00EA0400 /* UIColor+BookPlayer.swift in Sources */,
Expand Down
40 changes: 35 additions & 5 deletions BookPlayer/Player/PlayerManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ final class PlayerManager: NSObject, PlayerManagerProtocol {
private var playTask: Task<(), Error>?
private var playerItem: AVPlayerItem?
private var loadChapterTask: Task<(), Never>?
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()
@Published var currentItem: PlayableItem?
@Published var currentSpeed: Float = 1.0

Expand Down Expand Up @@ -147,11 +149,14 @@ final class PlayerManager: NSObject, PlayerManagerProtocol {
isPlayingPublisher()
.removeDuplicates()
.sink { [weak self] isPlayingValue in
UserDefaults.sharedDefaults.set(
isPlayingValue,
forKey: Constants.UserDefaults.sharedWidgetIsPlaying
)
self?.widgetReloadService.reloadWidget(.lastPlayedWidget)
if isPlayingValue {
UserDefaults.sharedDefaults.set(
self?.currentItem?.relativePath,
forKey: Constants.UserDefaults.sharedWidgetNowPlayingPath
)
} else {
UserDefaults.sharedDefaults.removeObject(forKey: Constants.UserDefaults.sharedWidgetNowPlayingPath)
}
}.store(in: &disposeBag)
}

Expand Down Expand Up @@ -317,6 +322,31 @@ final class PlayerManager: NSObject, PlayerManagerProtocol {
}

loadChapterMetadata(item.currentChapter, autoplay: autoplay, forceRefreshURL: forceRefreshURL)
storeWidgetItem(item)
}

func storeWidgetItem(_ item: PlayableItem) {
var widgetItems: [WidgetLibraryItem] = [
WidgetLibraryItem(
relativePath: item.relativePath,
title: item.title,
details: item.author
)
]

if let itemsData = UserDefaults.sharedDefaults.data(forKey: Constants.UserDefaults.sharedWidgetLastPlayedItems),
let items = try? decoder.decode([WidgetLibraryItem].self, from: itemsData)
{
widgetItems.append(contentsOf: items.filter({ $0.relativePath != item.relativePath }))
widgetItems = Array(widgetItems.prefix(10))
}

guard let data = try? encoder.encode(widgetItems) else {
return
}

UserDefaults.sharedDefaults.set(data, forKey: Constants.UserDefaults.sharedWidgetLastPlayedItems)
widgetReloadService.reloadWidget(.lastPlayedWidget)
}

func loadChapterMetadata(_ chapter: PlayableChapter, autoplay: Bool? = nil, forceRefreshURL: Bool = false) {
Expand Down
40 changes: 29 additions & 11 deletions BookPlayer/Services/ActionParserService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ class ActionParserService {
}

if let valueString = action.getQueryValue(for: "interval"),
let interval = Double(valueString) {
let interval = Double(valueString)
{
playerManager.skip(-interval)
} else {
playerManager.rewind()
Expand All @@ -98,7 +99,8 @@ class ActionParserService {
}

if let valueString = action.getQueryValue(for: "interval"),
let interval = Double(valueString) {
let interval = Double(valueString)
{
playerManager.skip(interval)
} else {
playerManager.forward()
Expand Down Expand Up @@ -169,7 +171,8 @@ class ActionParserService {

private class func handleSleepAction(_ action: Action) {
guard let value = action.getQueryValue(for: "seconds"),
let seconds = Double(value) else {
let seconds = Double(value)
else {
return
}

Expand All @@ -190,8 +193,17 @@ class ActionParserService {
return
}

self.removeAction(action)
playerManager.playPause()
if let bookIdentifier = action.getQueryValue(for: "identifier"),
playerManager.currentItem?.relativePath != bookIdentifier
{
if let libraryCoordinator = AppDelegate.shared?.activeSceneDelegate?.mainCoordinator?.getLibraryCoordinator() {
self.removeAction(action)
libraryCoordinator.loadPlayer(bookIdentifier)
}
} else {
self.removeAction(action)
playerManager.playPause()
}
}

private class func handlePauseAction(_ action: Action) {
Expand All @@ -213,14 +225,16 @@ class ActionParserService {
}

if let value = action.getQueryValue(for: "showPlayer"),
let showPlayer = Bool(value),
showPlayer {
let showPlayer = Bool(value),
showPlayer
{
AppDelegate.shared?.showPlayer()
}

if let value = action.getQueryValue(for: "autoplay"),
let autoplay = Bool(value),
!autoplay {
let autoplay = Bool(value),
!autoplay
{
return
}

Expand All @@ -231,7 +245,8 @@ class ActionParserService {
}

if let loadedItem = playerManager.currentItem,
loadedItem.relativePath == bookIdentifier {
loadedItem.relativePath == bookIdentifier
{
self.removeAction(action)
playerManager.play()
return
Expand All @@ -254,7 +269,10 @@ class ActionParserService {
}

guard let url = URL(string: urlString) else {
libraryCoordinator.showAlert("error_title".localized, message: String.localizedStringWithFormat("invalid_url_title".localized, urlString))
libraryCoordinator.showAlert(
"error_title".localized,
message: String.localizedStringWithFormat("invalid_url_title".localized, urlString)
)
return
}

Expand Down
29 changes: 21 additions & 8 deletions BookPlayer/Settings/Themes Screen/ThemeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ final class ThemeManager: ThemeProvider {

var libraryService: LibraryServiceProtocol!
private var theme: SubscribableValue<SimpleTheme>!
private let encoder = JSONEncoder()

/// The current theme that is active
var currentTheme: SimpleTheme {
Expand All @@ -24,6 +25,10 @@ final class ThemeManager: ThemeProvider {
set {
self.setNewTheme(newValue)
self.libraryService.setLibraryTheme(with: newValue)

guard let themeData = try? encoder.encode(newValue) else { return }

UserDefaults.sharedDefaults.set(themeData, forKey: Constants.UserDefaults.sharedWidgetTheme)
}
}

Expand Down Expand Up @@ -57,13 +62,19 @@ final class ThemeManager: ThemeProvider {
self.theme = SubscribableValue<SimpleTheme>(value: defaultTheme)
}

NotificationCenter.default.addObserver(self, selector: #selector(self.brightnessChanged(_:)), name: UIScreen.brightnessDidChangeNotification, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(self.brightnessChanged(_:)),
name: UIScreen.brightnessDidChangeNotification,
object: nil
)
}

public class func getLocalThemes() -> [SimpleTheme] {
guard let themesFile = Bundle.main.url(forResource: "Themes", withExtension: "json"),
let data = try? Data(contentsOf: themesFile, options: .mappedIfSafe),
let themes = try? JSONDecoder().decode([SimpleTheme].self, from: data) else {
let data = try? Data(contentsOf: themesFile, options: .mappedIfSafe),
let themes = try? JSONDecoder().decode([SimpleTheme].self, from: data)
else {
return []
}

Expand Down Expand Up @@ -92,11 +103,13 @@ final class ThemeManager: ThemeProvider {
}

let newTheme = SimpleTheme(with: newTheme, useDarkVariant: self.useDarkVariant)
UIView.transition(with: window,
duration: 0.3,
options: [.transitionCrossDissolve],
animations: { self.theme.value = newTheme },
completion: nil)
UIView.transition(
with: window,
duration: 0.3,
options: [.transitionCrossDissolve],
animations: { self.theme.value = newTheme },
completion: nil
)
}

/// Subscribe to be notified when the theme changes. Handler will be
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "logo-nobackground.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "logo-nobackground@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "logo-nobackground@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions BookPlayerWidgets/BookPlayerWidgets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import WidgetKit
struct BookPlayerWidgetUI_Previews: PreviewProvider {
static var previews: some View {
Group {
LastPlayedWidgetView(entry: SimpleEntry(
LastPlayedWidgetView(entry: .init(
date: Date(),
title: "Test Book Title",
relativePath: nil
items: [
.init(relativePath: "path1", title: "Test Book Title")
],
currentlyPlaying: nil
))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
Expand All @@ -35,7 +37,6 @@ struct BookPlayerBundle: WidgetBundle {
var body: some Widget {
#if os(iOS)
LastPlayedWidget()
RecentBooksWidget()
TimeListenedWidget()
if #available(iOSApplicationExtension 16.1, *) {
SharedWidget()
Expand Down
Loading

0 comments on commit 80dc100

Please sign in to comment.