diff --git a/Sabbath School.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Sabbath School.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/Sabbath School.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/Sabbath School.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Sabbath School.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644
index 00000000..bb480cc1
--- /dev/null
+++ b/Sabbath School.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -0,0 +1,60 @@
+{
+ "originHash" : "ac3e275717da5797aaa46aa4c566f1fd11beece107238572bcd9a8171edb13a0",
+ "pins" : [
+ {
+ "identity" : "alamofire",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/Alamofire/Alamofire.git",
+ "state" : {
+ "revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad",
+ "version" : "5.8.1"
+ }
+ },
+ {
+ "identity" : "cache",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/hyperoslo/Cache.git",
+ "state" : {
+ "revision" : "ad6abdf2a3a866288a7dad2c4e13379406002a81",
+ "version" : "6.2.0"
+ }
+ },
+ {
+ "identity" : "libwebp-xcode",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SDWebImage/libwebp-Xcode.git",
+ "state" : {
+ "revision" : "b2b1d20a90b14d11f6ef4241da6b81c1d3f171e4",
+ "version" : "1.3.2"
+ }
+ },
+ {
+ "identity" : "sdwebimage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SDWebImage/SDWebImage.git",
+ "state" : {
+ "revision" : "b8523c1642f3c142b06dd98443ea7c48343a4dfd",
+ "version" : "5.19.3"
+ }
+ },
+ {
+ "identity" : "sdwebimageswiftui",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SDWebImage/SDWebImageSwiftUI.git",
+ "state" : {
+ "revision" : "53573d6dd017e354c0e7d8f1c86b77ef1383c996",
+ "version" : "2.2.7"
+ }
+ },
+ {
+ "identity" : "sdwebimagewebpcoder",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SDWebImage/SDWebImageWebPCoder.git",
+ "state" : {
+ "revision" : "f534cfe830a7807ecc3d0332127a502426cfa067",
+ "version" : "0.14.6"
+ }
+ }
+ ],
+ "version" : 3
+}
diff --git a/Sabbath School.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Sabbath School.xcworkspace/xcshareddata/swiftpm/Package.resolved
index cc48e550..bb480cc1 100644
--- a/Sabbath School.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Sabbath School.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,4 +1,5 @@
{
+ "originHash" : "ac3e275717da5797aaa46aa4c566f1fd11beece107238572bcd9a8171edb13a0",
"pins" : [
{
"identity" : "alamofire",
@@ -14,8 +15,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/hyperoslo/Cache.git",
"state" : {
- "revision" : "c7f4d633049c3bd649a353bad36f6c17e9df085f",
- "version" : "6.0.0"
+ "revision" : "ad6abdf2a3a866288a7dad2c4e13379406002a81",
+ "version" : "6.2.0"
}
},
{
@@ -32,8 +33,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage.git",
"state" : {
- "revision" : "936f1c7067728d16c362ba4fb93c17df78b5fd79",
- "version" : "5.18.2"
+ "revision" : "b8523c1642f3c142b06dd98443ea7c48343a4dfd",
+ "version" : "5.19.3"
}
},
{
@@ -41,8 +42,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImageSwiftUI.git",
"state" : {
- "revision" : "e837c37d45449fbd3b4745c10c5b5274e73edead",
- "version" : "2.2.3"
+ "revision" : "53573d6dd017e354c0e7d8f1c86b77ef1383c996",
+ "version" : "2.2.7"
}
},
{
@@ -50,10 +51,10 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImageWebPCoder.git",
"state" : {
- "revision" : "3819cb70faa2454b54d8364779bfacd8c216a6e2",
- "version" : "0.13.0"
+ "revision" : "f534cfe830a7807ecc3d0332127a502426cfa067",
+ "version" : "0.14.6"
}
}
],
- "version" : 2
+ "version" : 3
}
diff --git a/Sabbath School/Application/AppDelegate.swift b/Sabbath School/Application/AppDelegate.swift
index 0cb50288..83898a79 100644
--- a/Sabbath School/Application/AppDelegate.swift
+++ b/Sabbath School/Application/AppDelegate.swift
@@ -157,8 +157,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}
- func launchQuarterlies() {
- let quarterlyController = QuarterlyWireFrame.createQuarterlyModule()
+ func launchQuarterlies(initiateOpen: Bool = false) {
+ let quarterlyController = QuarterlyWireFrame.createQuarterlyModule(initiateOpen: initiateOpen)
Configuration.window?.rootViewController = quarterlyController
Configuration.window?.makeKeyAndVisible()
}
diff --git a/Sabbath School/Lesson/Interactor/LessonInteractor.swift b/Sabbath School/Lesson/Interactor/LessonInteractor.swift
index 5eda4537..9396d77b 100644
--- a/Sabbath School/Lesson/Interactor/LessonInteractor.swift
+++ b/Sabbath School/Lesson/Interactor/LessonInteractor.swift
@@ -57,7 +57,7 @@ class LessonInteractor: LessonInteractorInputProtocol {
self.publishingInfoStorage = APICache.storage?.transformCodable(ofType: PublishingInfoData.self)
}
- func retrieveQuarterlyInfo(quarterlyIndex: String) {
+ func retrieveQuarterlyInfo(quarterlyIndex: String, completion: @escaping (QuarterlyInfo?) -> Void) {
let parsedIndex = Helper.parseIndex(index: quarterlyIndex)
let url = "\(Constants.API.URL)/\(parsedIndex.lang)/quarterlies/\(parsedIndex.quarter)/index.json"
@@ -66,12 +66,14 @@ class LessonInteractor: LessonInteractorInputProtocol {
if (try? self.storage?.existsObject(forKey: url)) != nil {
if let quarterlyInfo = try? self.storage?.entry(forKey: url) {
cachedObject = quarterlyInfo.object
+ completion(quarterlyInfo.object)
self.presenter?.didRetrieveQuarterlyInfo(quarterlyInfo: quarterlyInfo.object)
}
}
API.session.request(url).responseDecodable(of: QuarterlyInfo.self, decoder: Helper.SSJSONDecoder()) { response in
guard let quarterlyInfo = response.value else {
+ completion(nil)
self.presenter?.onError(response.error)
return
}
@@ -80,6 +82,7 @@ class LessonInteractor: LessonInteractorInputProtocol {
return
}
+ completion(quarterlyInfo)
self.presenter?.didRetrieveQuarterlyInfo(quarterlyInfo: quarterlyInfo)
try? self.storage?.setObject(quarterlyInfo, forKey: url)
}
diff --git a/Sabbath School/Lesson/Presenter/LessonPresenter.swift b/Sabbath School/Lesson/Presenter/LessonPresenter.swift
index ad29ed98..4b9bc29e 100644
--- a/Sabbath School/Lesson/Presenter/LessonPresenter.swift
+++ b/Sabbath School/Lesson/Presenter/LessonPresenter.swift
@@ -30,7 +30,7 @@ class LessonPresenter: LessonPresenterProtocol {
func configure() {
interactor?.configure()
- interactor?.retrieveQuarterlyInfo(quarterlyIndex: quarterlyIndex!)
+ interactor?.retrieveQuarterlyInfo(quarterlyIndex: quarterlyIndex!, completion: { _ in })
interactor?.retrievePublishingInfo()
}
diff --git a/Sabbath School/Lesson/Protocols/LessonProtocols.swift b/Sabbath School/Lesson/Protocols/LessonProtocols.swift
index 51415b42..69e2389c 100644
--- a/Sabbath School/Lesson/Protocols/LessonProtocols.swift
+++ b/Sabbath School/Lesson/Protocols/LessonProtocols.swift
@@ -66,7 +66,7 @@ protocol LessonInteractorInputProtocol: AnyObject {
var presenter: LessonInteractorOutputProtocol? { get set }
func configure()
- func retrieveQuarterlyInfo(quarterlyIndex: String)
+ func retrieveQuarterlyInfo(quarterlyIndex: String, completion: @escaping (QuarterlyInfo?) -> Void)
func retrievePublishingInfo()
func retrieveRead(readIndex: String, quarterlyIndex: String?)
}
diff --git a/Sabbath School/Quarterly/Controller/QuarterlyController.swift b/Sabbath School/Quarterly/Controller/QuarterlyController.swift
index b0dad094..eb716e43 100644
--- a/Sabbath School/Quarterly/Controller/QuarterlyController.swift
+++ b/Sabbath School/Quarterly/Controller/QuarterlyController.swift
@@ -40,7 +40,8 @@ class QuarterlyController: QuarterlyControllerCommon {
let lastQuarterlyIndex = Preferences.currentQuarterly()
let languageCode = lastQuarterlyIndex.components(separatedBy: "-")
if let code = languageCode.first, Preferences.currentLanguage().code == code {
- presenter?.presentLessonScreen(quarterlyIndex: lastQuarterlyIndex, initiateOpenToday: false)
+ presenter?.presentLessonScreen(quarterlyIndex: lastQuarterlyIndex, initiateOpenToday: initiateOpen ?? false
+ )
}
}
setupNavigationBar()
diff --git a/Sabbath School/Quarterly/WireFrame/QuarterlyWireFrame.swift b/Sabbath School/Quarterly/WireFrame/QuarterlyWireFrame.swift
index fcf12b91..6269f3bd 100644
--- a/Sabbath School/Quarterly/WireFrame/QuarterlyWireFrame.swift
+++ b/Sabbath School/Quarterly/WireFrame/QuarterlyWireFrame.swift
@@ -57,6 +57,7 @@ class SplitVc : UISplitViewController, UISplitViewControllerDelegate {
class QuarterlyWireFrame: QuarterlyWireFrameProtocol {
class func createQuarterlyModule(initiateOpen: Bool = false) -> ASDKNavigationController {
let controller: QuarterlyControllerProtocol = QuarterlyController()
+ controller.initiateOpen = initiateOpen
let presenter: QuarterlyPresenterProtocol & QuarterlyInteractorOutputProtocol = QuarterlyPresenter()
let wireFrame: QuarterlyWireFrameProtocol = QuarterlyWireFrame()
let interactor: QuarterlyInteractorInputProtocol = QuarterlyInteractor()
diff --git a/Sabbath School/Siri/Intents/ListenTodaySabbathSchoolIntent.swift b/Sabbath School/Siri/Intents/ListenTodaySabbathSchoolIntent.swift
new file mode 100644
index 00000000..5af4dce5
--- /dev/null
+++ b/Sabbath School/Siri/Intents/ListenTodaySabbathSchoolIntent.swift
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2021 Adventech
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import AppIntents
+import UIKit
+import SwiftAudio
+
+@available(iOS 16.0, *)
+struct ListenTodaySabbathSchoolIntent: AudioStartingIntent {
+
+ static var title: LocalizedStringResource = "Starting Sabbath School"
+ static var openAppWhenRun: Bool = false
+
+ @MainActor
+ func perform() async throws -> some IntentResult {
+ let lastQuarterlyIndex = Preferences.currentQuarterly()
+ retrieveAudio(quarterlyIndex: lastQuarterlyIndex)
+
+ return .result(value: true)
+ }
+
+ func retrieveAudio(quarterlyIndex: String) {
+ let audioInteractor = AudioInteractor()
+ let lessonInteractor = LessonInteractor()
+
+ lessonInteractor.retrieveQuarterlyInfo(quarterlyIndex: quarterlyIndex) { quarterlyInfo in
+ audioInteractor.retrieveAudio(quarterlyIndex: quarterlyIndex) { audio in
+ let finalAudio = audio.filter { $0.targetIndex.starts(with: getTodaysLessonIndex(dataSource: quarterlyInfo)) }
+
+ let audioItems: [AudioItem] = finalAudio.map { $0.audioItem() }
+
+ AudioPlayback.configure()
+ try? AudioPlayback.shared.add(items: audioItems, playWhenReady: false)
+ try? AudioPlayback.shared.jumpToItem(atIndex: 1, playWhenReady: true)
+
+ AudioPlayback.play()
+ }
+ }
+ }
+
+
+ func getTodaysLessonIndex(dataSource: QuarterlyInfo?) -> String {
+ guard let lessons = dataSource?.lessons else { return "" }
+ let today = Date()
+ let weekday = Calendar.current.component(.weekday, from: today)
+ let hour = Calendar.current.component(.hour, from: today)
+ var prevLessonIndex: String? = nil
+
+ for lesson in lessons {
+ let start = Calendar.current.compare(lesson.startDate, to: today, toGranularity: .day)
+ let end = Calendar.current.compare(lesson.endDate, to: today, toGranularity: .day)
+ let fallsBetween = ((start == .orderedAscending) || (start == .orderedSame)) && ((end == .orderedDescending) || (end == .orderedSame))
+
+ if fallsBetween {
+ if (weekday == 7 && hour < 12 && prevLessonIndex != nil) {
+ return prevLessonIndex!
+ } else {
+ return lesson.index
+ }
+ }
+ prevLessonIndex = lesson.index
+ }
+
+ if let firstLesson = lessons.first {
+ return firstLesson.index
+ }
+
+ return ""
+ }
+}
diff --git a/Sabbath School/Siri/Intents/ReadTodaySabbathSchoolIntent.swift b/Sabbath School/Siri/Intents/ReadTodaySabbathSchoolIntent.swift
new file mode 100644
index 00000000..d2d1ea95
--- /dev/null
+++ b/Sabbath School/Siri/Intents/ReadTodaySabbathSchoolIntent.swift
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Adventech
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import AppIntents
+import UIKit
+
+@available(iOS 16.0, *)
+struct ReadTodaySabbathSchoolIntent: AppIntent {
+
+ static var title: LocalizedStringResource = "Starting Sabbath School"
+ static var openAppWhenRun: Bool = true
+
+ @MainActor
+ func perform() async throws -> some IntentResult {
+ let appDelegate = UIApplication.shared.delegate as? AppDelegate
+ appDelegate?.launchQuarterlies(initiateOpen: true)
+
+ return .result(value: true)
+ }
+}
diff --git a/Sabbath School/Siri/SabbathSchoolShortcuts.swift b/Sabbath School/Siri/SabbathSchoolShortcuts.swift
new file mode 100644
index 00000000..b43e4ffd
--- /dev/null
+++ b/Sabbath School/Siri/SabbathSchoolShortcuts.swift
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021 Adventech
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import Intents
+import AppIntents
+
+@available(iOS 16.0, *)
+struct SabbathSchoolShortcuts: AppShortcutsProvider {
+ static var appShortcuts: [AppShortcut] {
+ AppShortcut(
+ intent: ListenTodaySabbathSchoolIntent(),
+ phrases: [
+ "Listen \(.applicationName)",
+ "Play \(.applicationName)"
+ ]
+ )
+ }
+}
+
+//@available(iOS 16.0, *)
+//struct SabbathSchoolShortcuts1: AppShortcutsProvider {
+// static var appShortcuts: [AppShortcut] {
+// AppShortcut(
+// intent: ReadTodaySabbathSchoolIntent(),
+// phrases: [
+// "Read \(.applicationName)"
+// ]
+// )
+// }
+//}