MinAgoTask.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // LoopFollow
  2. // MinAgoTask.swift
  3. import Foundation
  4. import UIKit
  5. extension MainViewController {
  6. func scheduleMinAgoTask(initialDelay: TimeInterval = 1.0) {
  7. let firstRun = Date().addingTimeInterval(initialDelay)
  8. TaskScheduler.shared.scheduleTask(id: .minAgoUpdate, nextRun: firstRun) { [weak self] in
  9. guard let self = self else { return }
  10. self.minAgoTaskAction()
  11. }
  12. }
  13. func minAgoTaskAction() {
  14. guard bgData.count > 0, let lastBG = bgData.last else {
  15. DispatchQueue.main.async { [weak self] in
  16. guard let self = self else { return }
  17. self.MinAgoText.text = ""
  18. Observable.shared.minAgoText.value = ""
  19. Observable.shared.bgText.value = ""
  20. }
  21. TaskScheduler.shared.rescheduleTask(id: .minAgoUpdate, to: Date().addingTimeInterval(1))
  22. return
  23. }
  24. let bgSeconds = lastBG.date
  25. let now = Date()
  26. let secondsAgo = now.timeIntervalSince1970 - bgSeconds
  27. let formatter = DateComponentsFormatter()
  28. formatter.unitsStyle = .positional
  29. formatter.zeroFormattingBehavior = .dropLeading
  30. let shouldDisplaySeconds = secondsAgo >= 270 && secondsAgo < 720 // 4.5 to 12 minutes
  31. if shouldDisplaySeconds {
  32. formatter.allowedUnits = [.minute, .second]
  33. } else {
  34. formatter.allowedUnits = [.minute]
  35. }
  36. let formattedDuration = formatter.string(from: secondsAgo) ?? ""
  37. let minAgoDisplayText = formattedDuration + " min ago"
  38. // Update UI only if the display text has changed
  39. if minAgoDisplayText != Observable.shared.minAgoText.value {
  40. DispatchQueue.main.async { [weak self] in
  41. guard let self = self else { return }
  42. self.MinAgoText.text = minAgoDisplayText
  43. Observable.shared.minAgoText.value = minAgoDisplayText
  44. }
  45. }
  46. let deltaTime = secondsAgo / 60
  47. Observable.shared.bgStale.value = deltaTime >= 12
  48. // Apply strikethrough to BGText based on the staleness of the data
  49. // Also clear badge if bgvalue is stale
  50. let bgTextStr = BGText.text ?? ""
  51. let attributeString = NSMutableAttributedString(string: bgTextStr)
  52. attributeString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: attributeString.length))
  53. if Observable.shared.bgStale.value { // Data is stale
  54. attributeString.addAttribute(.strikethroughColor, value: UIColor.systemRed, range: NSRange(location: 0, length: attributeString.length))
  55. updateBadge(val: 0)
  56. } else { // Data is fresh
  57. attributeString.addAttribute(.strikethroughColor, value: UIColor.clear, range: NSRange(location: 0, length: attributeString.length))
  58. updateBadge(val: Observable.shared.bg.value ?? 0)
  59. }
  60. BGText.attributedText = attributeString
  61. // Determine the next run interval based on the current state
  62. let nextUpdateInterval: TimeInterval
  63. if shouldDisplaySeconds {
  64. // Update every second when showing seconds
  65. nextUpdateInterval = 1.0
  66. } else if secondsAgo >= 240, secondsAgo < 720 {
  67. // Schedule exactly at the transition point to start showing seconds
  68. nextUpdateInterval = 270.0 - secondsAgo
  69. } else {
  70. // Schedule exactly at the transition point to next minute
  71. let secondsToNextMinute = 60.0 - (secondsAgo.truncatingRemainder(dividingBy: 60.0))
  72. nextUpdateInterval = secondsToNextMinute
  73. }
  74. // Ensure the nextUpdateInterval is not negative or too small
  75. let safeNextInterval = max(nextUpdateInterval, 1.0)
  76. TaskScheduler.shared.rescheduleTask(id: .minAgoUpdate, to: Date().addingTimeInterval(safeNextInterval))
  77. }
  78. }