diff --git a/Main.storyboard b/Main.storyboard
index 233009b6..01d8dbd2 100755
--- a/Main.storyboard
+++ b/Main.storyboard
@@ -3,7 +3,7 @@
-
+
diff --git a/Thrive Church Official App.xcodeproj/project.pbxproj b/Thrive Church Official App.xcodeproj/project.pbxproj
index 27e6fd79..69a1fc80 100644
--- a/Thrive Church Official App.xcodeproj/project.pbxproj
+++ b/Thrive Church Official App.xcodeproj/project.pbxproj
@@ -1019,12 +1019,12 @@
CODE_SIGN_ENTITLEMENTS = "Thrive Church Official App.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- CURRENT_PROJECT_VERSION = 1.7.6.8;
+ CURRENT_PROJECT_VERSION = 1.7.7.3;
DEVELOPMENT_TEAM = 87ME42WJYA;
INFOPLIST_FILE = "$(SRCROOT)/Thrive Community Church/Properties/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- MARKETING_VERSION = 1.7.6;
+ MARKETING_VERSION = 1.7.7;
PRODUCT_BUNDLE_IDENTIFIER = "com.thrive-fl.ThriveCommunityChurch";
PRODUCT_NAME = "Thrive Church Official App";
PROVISIONING_PROFILE = "";
@@ -1044,12 +1044,12 @@
CODE_SIGN_ENTITLEMENTS = "Thrive Church Official App.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- CURRENT_PROJECT_VERSION = 1.7.6.8;
+ CURRENT_PROJECT_VERSION = 1.7.7.3;
DEVELOPMENT_TEAM = 87ME42WJYA;
INFOPLIST_FILE = "$(SRCROOT)/Thrive Community Church/Properties/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- MARKETING_VERSION = 1.7.6;
+ MARKETING_VERSION = 1.7.7;
PRODUCT_BUNDLE_IDENTIFIER = "com.thrive-fl.ThriveCommunityChurch";
PRODUCT_NAME = "Thrive Church Official App";
PROVISIONING_PROFILE = "";
diff --git a/Thrive Community Church/Extensions/DoubleExtension.swift b/Thrive Community Church/Extensions/DoubleExtension.swift
index 79076fc5..1352c36c 100644
--- a/Thrive Community Church/Extensions/DoubleExtension.swift
+++ b/Thrive Community Church/Extensions/DoubleExtension.swift
@@ -32,13 +32,6 @@ extension Double {
return (Double(self) / 1024 / 1024)
}
- /// return a number of seconds into a number of hours minutes and seconds
- func secondsToHoursMinutesSeconds() -> (Double, Double, Double) {
- let (hr, minf) = modf (self / 3600)
- let (min, secf) = modf (60 * minf)
- return (hr, min, 60 * secf)
- }
-
/// return a duration in minutes or hours for the length of a number of seconds
func formatDurationForUI(displayAsPositional: Bool = false) -> String? {
diff --git a/Thrive Community Church/Extensions/UIColorExtension.swift b/Thrive Community Church/Extensions/UIColorExtension.swift
index cc5f0cb8..c324f0b2 100644
--- a/Thrive Community Church/Extensions/UIColorExtension.swift
+++ b/Thrive Community Church/Extensions/UIColorExtension.swift
@@ -16,5 +16,6 @@ extension UIColor {
static var lighterBlueGray = UIColor(red: 70/255, green: 106/255, blue: 134/255, alpha: 1)
static var bgDarkBlue = UIColor(red: 27/255, green: 41/255, blue: 51/255, alpha: 1)
static var almostBlack = UIColor(red: 25/255, green: 25/255, blue: 25/255, alpha: 1)
+ static var transparentAlmostBlack = UIColor(red: 25/255, green: 25/255, blue: 25/255, alpha: 0.5)
static var darkGrey = UIColor(red: 63/255, green: 63/255, blue: 63/255, alpha: 1)
}
diff --git a/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewController.swift b/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewController.swift
index d9a55307..d4c09010 100644
--- a/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewController.swift
+++ b/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewController.swift
@@ -21,6 +21,7 @@ MFMailComposeViewControllerDelegate {
var apiUrl: String = "nil"
var secondsRemaining: Double?
var expireTime: Date?
+ var nextLive: Date?
var timer = Timer()
var loading: Bool = false
var pollingData: LivePollingResponse?
@@ -29,6 +30,7 @@ MFMailComposeViewControllerDelegate {
var playedMessage: Bool = false
private var alreadySelected: Bool = false
var seriesMapping = [String: SermonSeries]()
+ var countdownTimer: Timer? = nil
// Loading View
var footerView: CustomFooterView?
@@ -59,10 +61,26 @@ MFMailComposeViewControllerDelegate {
let backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.bgDarkBlue
- view.translatesAutoresizingMaskIntoConstraints = true
+ view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
+ let countdownBannerView: UIView = {
+ let view = UIView()
+ view.backgroundColor = .clear
+ view.translatesAutoresizingMaskIntoConstraints = false
+ return view
+ }()
+
+ let countdownBannerLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont(name: "Avenir-Medium", size: 15)
+ label.textColor = .lessLightLightGray
+ label.textAlignment = .center
+ label.translatesAutoresizingMaskIntoConstraints = false
+ return label
+ }()
+
let retryButton: UIButton = {
let button = UIButton()
button.setTitle("Retry?", for: .normal)
@@ -376,6 +394,101 @@ MFMailComposeViewControllerDelegate {
}
}
+ func removeTimer() {
+ self.countdownTimer?.invalidate()
+ self.countdownTimer = nil
+ self.countdownTimer = Timer()
+ }
+
+ func setBannerTime(nextLive: Date) {
+ view.addSubview(countdownBannerView)
+
+ let now = Date()
+ let nowDateFormatter = DateFormatter()
+ nowDateFormatter.locale = Locale(identifier: "en_US_POSIX")
+ nowDateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
+ nowDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
+ let nowString = nowDateFormatter.string(from: now)
+
+ let nowDate = nowDateFormatter.date(from: nowString) ?? Date()
+
+ let remaining: TimeInterval = nextLive.timeIntervalSince(nowDate)
+
+ if (remaining.isZero || remaining.isLess(than: 0.0)) {
+ return
+ }
+
+ let formatter = DateComponentsFormatter()
+ formatter.allowedUnits = [.day, .hour, .minute, .second]
+ formatter.unitsStyle = .abbreviated
+
+ let formattedString = formatter.string(from: remaining)!
+
+ countdownBannerLabel.text = "We're live in \(formattedString)"
+
+ NSLayoutConstraint.activate([
+ countdownBannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+ countdownBannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+ countdownBannerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
+ countdownBannerView.heightAnchor.constraint(equalToConstant: 22)
+ ])
+
+ let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.dark)
+ let blurEffectView = UIVisualEffectView(effect: blurEffect)
+ blurEffectView.frame = countdownBannerView.bounds
+ blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ countdownBannerView.addSubview(blurEffectView)
+
+
+ countdownBannerView.addSubview(countdownBannerLabel)
+ NSLayoutConstraint.activate([
+ countdownBannerLabel.centerYAnchor.constraint(equalTo: countdownBannerView.centerYAnchor),
+ countdownBannerLabel.centerXAnchor.constraint(equalTo: countdownBannerView.centerXAnchor)
+ ])
+
+ startTimerCountdownForNextLive(remaining: remaining)
+ }
+
+ func startTimerCountdownForNextLive(remaining: TimeInterval) {
+
+
+ self.countdownTimer = Timer.scheduledTimer(timeInterval: 1.0,
+ target: self,
+ selector: #selector(self.processCountdownTimerChange),
+ userInfo: nil, repeats: true)
+
+ // make the timer tick even when the user is scrolling
+ RunLoop.current.add(self.countdownTimer!, forMode: .common)
+ }
+
+ @objc func processCountdownTimerChange() {
+
+ let now = Date()
+
+ let remaining: TimeInterval = nextLive?.timeIntervalSince(now) ?? 0
+
+ if (remaining.isZero || remaining.isLess(than: 0.0)) {
+ self.countdownBannerView.isHidden = true
+ self.removeTimer()
+ self.livestreamButton.isEnabled = true
+
+ // let's check after 30s if the stream is "really active"
+ // this allows the stream to expire after it should but gives the server 30s
+ // to set the stream as acive
+ DispatchQueue.main.asyncAfter(wallDeadline: .now() + 30, execute: {
+ self.pollForLiveData()
+ })
+ }
+
+ let formatter = DateComponentsFormatter()
+ formatter.allowedUnits = [.day, .hour, .minute, .second]
+ formatter.unitsStyle = .abbreviated
+
+ let formattedString = formatter.string(from: remaining)!
+
+ countdownBannerLabel.text = "We're live in \(formattedString)"
+ }
+
func setupViews() {
view.addSubview(backgroundView)
view.addSubview(apiErrorMessage)
diff --git a/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewControllerRepoExtension.swift b/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewControllerRepoExtension.swift
index 60d98fba..3bdd8cbf 100644
--- a/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewControllerRepoExtension.swift
+++ b/Thrive Community Church/MainViewControllers/Listen/Controllers/ListenCollectionViewControllerRepoExtension.swift
@@ -183,6 +183,18 @@ extension ListenCollectionViewController {
else {
// maybe we can have an async thread here running that checks to see if every minute,
// we are getting close to beginning a live stream? (thoughts)
+
+ DispatchQueue.main.async {
+ // get the next time from the API
+ let nowDateFormatter = DateFormatter()
+ nowDateFormatter.locale = Locale(identifier: "en_US_POSIX")
+ nowDateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
+ nowDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
+
+ self.nextLive = nowDateFormatter.date(from: livestream.NextLive ?? "") ?? Date()
+
+ self.setBannerTime(nextLive: self.nextLive!)
+ }
}
})
}
@@ -205,7 +217,6 @@ extension ListenCollectionViewController {
return
}
-
do {
//let JSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
diff --git a/Thrive Community Church/MainViewControllers/Listen/Controllers/SeriesViewController.swift b/Thrive Community Church/MainViewControllers/Listen/Controllers/SeriesViewController.swift
index 36c1e5bc..cccbf950 100644
--- a/Thrive Community Church/MainViewControllers/Listen/Controllers/SeriesViewController.swift
+++ b/Thrive Community Church/MainViewControllers/Listen/Controllers/SeriesViewController.swift
@@ -231,6 +231,14 @@ class SeriesViewController: UIViewController, UITableViewDelegate, UITableViewDa
let selectedMessage = messages[indexPath.row]
messageForDownload = selectedMessage
+ // tapping on an item that has no options doesn't do anything
+ if selectedMessage.AudioUrl == nil && selectedMessage.VideoUrl == nil &&
+ selectedMessage.PassageRef == nil
+ {
+ self.seriesTable.deselectRow(indexPath: indexPath)
+ return
+ }
+
let alert = UIAlertController(title: "\(series?.Name ?? "") - Week \(selectedMessage.WeekNum ?? 0)",
message: "Please select an action",
preferredStyle: .actionSheet)
diff --git a/Thrive Community Church/MainViewControllers/Listen/Models/LivestreamingResponse.swift b/Thrive Community Church/MainViewControllers/Listen/Models/LivestreamingResponse.swift
index 20fe913f..231ccefb 100644
--- a/Thrive Community Church/MainViewControllers/Listen/Models/LivestreamingResponse.swift
+++ b/Thrive Community Church/MainViewControllers/Listen/Models/LivestreamingResponse.swift
@@ -15,4 +15,5 @@ class LivestreamingResponse: NSObject, Decodable {
var Title: String?
var SpecialEventTimes: String?
var IsSpecialEvent: Bool = false
+ var NextLive: String?
}
diff --git a/VersionHistory.md b/VersionHistory.md
index 69b29d6c..437fbe06 100644
--- a/VersionHistory.md
+++ b/VersionHistory.md
@@ -1,8 +1,16 @@
# 1.7
-### Rev. 6 (current)
+### Rev. 7 (current)
- Oct. 17, 2020
+ Dec 27, 2020
+
+ - You'll now be able to see how long until we go live!
+
+
+
+### Rev. 6
+
+ Oct 17, 2020
- Sign up to receive notifications from us right on your phone!
- Fixing an issue with users who attempt to listen to sermon audio from recently played when they only have 1 recently played item