Commit 7ca65c2c by Dmitriy Stepanets

Finished radar time line animation

parent f14dbb96
......@@ -60,6 +60,7 @@
CD39F2F525DE9571009FE398 /* ArrowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD39F2F425DE9571009FE398 /* ArrowButton.swift */; };
CD3F6E6925FA59D4002DB99B /* ForecastDetailPeriodButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD3F6E6825FA59D4002DB99B /* ForecastDetailPeriodButton.swift */; };
CD3F6E6C25FA5A90002DB99B /* PeriodButtonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD3F6E6B25FA5A90002DB99B /* PeriodButtonProtocol.swift */; };
CD43DF032636C6640010C9F7 /* CACornerMask+All.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD43DF022636C6640010C9F7 /* CACornerMask+All.swift */; };
CD4742D0261200500061AC95 /* TodayAlertCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4742CF261200500061AC95 /* TodayAlertCell.swift */; };
CD55E0BB2615EE2400CC4DC7 /* PollutantView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD55E0BA2615EE2400CC4DC7 /* PollutantView.swift */; };
CD593BC226088A5900C93428 /* TimePeriodOffsetHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD593BC126088A5900C93428 /* TimePeriodOffsetHolder.swift */; };
......@@ -128,7 +129,6 @@
CDD0F1E52572425200CF5017 /* SF-Pro.ttf in Resources */ = {isa = PBXBuildFile; fileRef = CDD0F1E42572425200CF5017 /* SF-Pro.ttf */; };
CDD0F1E82572429E00CF5017 /* AppFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD0F1E72572429E00CF5017 /* AppFont.swift */; };
CDD0F1EE25725BCF00CF5017 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD0F1ED25725BCF00CF5017 /* ThemeManager.swift */; };
CDD17E2E263300CF00E92B6A /* Date+TimeZoneConvert.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD17E2D263300CF00E92B6A /* Date+TimeZoneConvert.swift */; };
CDD75F0D25DE68B10099ACDB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CDD75F0F25DE68B10099ACDB /* Localizable.strings */; };
CDDE8D7C262EED3C00267931 /* MapLegendSevereView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDE8D7B262EED3C00267931 /* MapLegendSevereView.swift */; };
CDDE8D7F262EED4D00267931 /* MapLegendWeatherView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDE8D7E262EED4D00267931 /* MapLegendWeatherView.swift */; };
......@@ -269,6 +269,7 @@
CD39F2F425DE9571009FE398 /* ArrowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowButton.swift; sourceTree = "<group>"; };
CD3F6E6825FA59D4002DB99B /* ForecastDetailPeriodButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastDetailPeriodButton.swift; sourceTree = "<group>"; };
CD3F6E6B25FA5A90002DB99B /* PeriodButtonProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeriodButtonProtocol.swift; sourceTree = "<group>"; };
CD43DF022636C6640010C9F7 /* CACornerMask+All.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CACornerMask+All.swift"; sourceTree = "<group>"; };
CD4742CF261200500061AC95 /* TodayAlertCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayAlertCell.swift; sourceTree = "<group>"; };
CD55E0BA2615EE2400CC4DC7 /* PollutantView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollutantView.swift; sourceTree = "<group>"; };
CD593BC126088A5900C93428 /* TimePeriodOffsetHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimePeriodOffsetHolder.swift; sourceTree = "<group>"; };
......@@ -337,7 +338,6 @@
CDD0F1E42572425200CF5017 /* SF-Pro.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Pro.ttf"; sourceTree = "<group>"; };
CDD0F1E72572429E00CF5017 /* AppFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppFont.swift; sourceTree = "<group>"; };
CDD0F1ED25725BCF00CF5017 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
CDD17E2D263300CF00E92B6A /* Date+TimeZoneConvert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeZoneConvert.swift"; sourceTree = "<group>"; };
CDD75F0E25DE68B10099ACDB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
CDDE8D7B262EED3C00267931 /* MapLegendSevereView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLegendSevereView.swift; sourceTree = "<group>"; };
CDDE8D7E262EED4D00267931 /* MapLegendWeatherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLegendWeatherView.swift; sourceTree = "<group>"; };
......@@ -536,7 +536,7 @@
CDF4808E261727E00076E9F5 /* CLAuthorizationStatus+Localized.swift */,
CDF48091261729680076E9F5 /* UIApplication+Settings.swift */,
CD67616C262587D30079D273 /* UITabBarController+Hide.swift */,
CDD17E2D263300CF00E92B6A /* Date+TimeZoneConvert.swift */,
CD43DF022636C6640010C9F7 /* CACornerMask+All.swift */,
);
path = Extensions;
sourceTree = "<group>";
......@@ -1334,6 +1334,7 @@
CDD0F1E82572429E00CF5017 /* AppFont.swift in Sources */,
CE8962AA26175DF500CA274A /* CoreAirQuality.swift in Sources */,
CE28475D2615A5B3006C8DC5 /* Health.swift in Sources */,
CD43DF032636C6640010C9F7 /* CACornerMask+All.swift in Sources */,
CEF9599F2601DF3300975FAA /* AdLogger.swift in Sources */,
CDC6124F25E7964700188DA7 /* TodayDayTimesCell.swift in Sources */,
CD593BC226088A5900C93428 /* TimePeriodOffsetHolder.swift in Sources */,
......@@ -1443,7 +1444,6 @@
CD55E0BB2615EE2400CC4DC7 /* PollutantView.swift in Sources */,
CDDE8D7C262EED3C00267931 /* MapLegendSevereView.swift in Sources */,
CD6761882625C3360079D273 /* RadarViewModel.swift in Sources */,
CDD17E2E263300CF00E92B6A /* Date+TimeZoneConvert.swift in Sources */,
CDF8F12A262089A200DB384A /* MapTimeView.swift in Sources */,
CEC526FA25E7959A00DA58A5 /* WeatherSource.swift in Sources */,
CDF4808F261727E00076E9F5 /* CLAuthorizationStatus+Localized.swift in Sources */,
......
......@@ -3,22 +3,4 @@
uuid = "55281C35-FE9F-4CED-865E-FBED0E7393F6"
type = "0"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "03921A78-9DF4-4BDE-88B6-E44035BF9063"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "1Weather/Extensions/Calendar+TimeZone.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "21"
endingLineNumber = "21"
landmarkName = "isNow(fromDate:timeZone:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
//
// CACornerMask+All.swift
// 1Weather
//
// Created by Dmitry Stepanets on 26.04.2021.
//
import UIKit
extension CACornerMask {
static var all:CACornerMask {
return [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
}
}
//
// Date+TimeZoneConvert.swift
// 1Weather
//
// Created by Dmitry Stepanets on 23.04.2021.
//
import Foundation
extension Date {
func convert(from initTimeZone: TimeZone, to targetTimeZone: TimeZone) -> Date {
let delta = TimeInterval(targetTimeZone.secondsFromGMT(for: self) - initTimeZone.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}
}
......@@ -6,6 +6,7 @@
//
import UIKit
import Swarm
public enum SevereLayerType:String, CaseIterable, RadarLayerType {
case fire = "radar.severeLayer.fire"
......@@ -28,6 +29,33 @@ public enum SevereLayerType:String, CaseIterable, RadarLayerType {
return self.rawValue.localized()
}
var swarmLayer:SwarmGroup {
switch self {
case .fire:
return .fire
case .floods:
return .flood
case .fog:
return .fog
case .freezing:
return .freezing
case .hurricaneTropical:
return .hurricaneAndTropical
case .hurricaneTropicalTracks:
return .hurricaneTracks
case .ice:
return .ice
case .snow:
return .snow
case .stormTornados:
return .stormAndTornadoes
case .wind:
return .wind
case .winter:
return .winter
}
}
var values:[String] {
switch self {
case .fire:
......
......@@ -11,6 +11,11 @@ class MapCurrentTimeView: UIView {
private let imageView = UIImageView()
private let valueLabel = UILabel()
private let timeLabel = UILabel()
private static var timeFormatter:DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "h:mm a"
return fmt
}()
init() {
super.init(frame: .zero)
......@@ -20,6 +25,12 @@ class MapCurrentTimeView: UIView {
prepareLabels()
}
public func configure(timeItem:MapTimeControlItem) {
MapCurrentTimeView.timeFormatter.timeZone = timeItem.timeZone
valueLabel.text = ""
timeLabel.text = MapCurrentTimeView.timeFormatter.string(from: timeItem.date)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
......@@ -49,6 +60,7 @@ private extension MapCurrentTimeView {
valueLabel.setContentHuggingPriority(.fittingSizeLevel, for: .vertical)
addSubview(valueLabel)
timeLabel.textAlignment = .center
timeLabel.font = AppFont.SFPro.bold(size: 10)
timeLabel.textColor = .white
timeLabel.text = "2:50 PM"
......
......@@ -10,4 +10,5 @@ import Foundation
struct MapTimeControlItem {
let value:String
let date:Date
let timeZone:TimeZone
}
......@@ -8,6 +8,17 @@
import UIKit
import SnapKit
protocol MapTimeControlViewDelegate:class {
func didSelectPlayButton()
func didSelectPauseButton()
func didSelect(item:MapTimeControlItem)
}
private enum PlayButtonState {
case play
case pause
}
class MapTimeControlView: UIView {
//Private
private let container = UIView()
......@@ -17,7 +28,11 @@ class MapTimeControlView: UIView {
private let currenTimeView = MapCurrentTimeView()
private let currentTimeDashLine = CAShapeLayer()
private let progresView = UIView()
private var progressWidthConstraint:Constraint?
private var currentItems = [MapTimeControlItem]()
private var playButtonState = PlayButtonState.pause
//Public
weak var delegate:MapTimeControlViewDelegate?
init() {
super.init(frame: .zero)
......@@ -26,8 +41,8 @@ class MapTimeControlView: UIView {
prepareContainer()
preparePlayButton()
prepareStackView()
prepareCurrentTimeView()
prepareProgressView()
prepareCurrentTimeView()
updateUI()
}
......@@ -65,15 +80,68 @@ class MapTimeControlView: UIView {
}
public func configure(items:[MapTimeControlItem], timeZone:TimeZone) {
//Reduce count if needed
if items.count > 5 {
var modifiedItems = items
while modifiedItems.count > 5 {
let centerIndex = modifiedItems.count / 2
modifiedItems.remove(at: centerIndex)
}
self.currentItems = modifiedItems
}
else {
self.currentItems = items
}
stackView.removeAll()
items.forEach {
self.currentItems.forEach {
let view = MapTimeView(item: $0)
stackView.addArrangedSubview(view)
}
stackView.layoutIfNeeded()
}
public func updateProgress(value:CGFloat) {
var progress = max(0, value)
progress = min(1, progress)
currenTimeView.isHidden = false
currentTimeDashLine.isHidden = false
progresView.layer.maskedCorners = progress < 1 ? [.layerMinXMinYCorner, .layerMinXMaxYCorner] : .all
updateCurrentViewWith(proress: progress)
currenTimeView.snp.updateConstraints { (update) in
switch progress {
case 0:
update.centerX.equalTo(progresView.snp.right).inset(-50)
case 1:
update.centerX.equalTo(progresView.snp.right).offset(-10)
default:
update.centerX.equalTo(progresView.snp.right)
}
}
if progress == 0 {
progresView.snp.remakeConstraints { (remake) in
remake.left.top.bottom.equalToSuperview()
remake.width.equalToSuperview().multipliedBy(0)
}
return
}
progresView.snp.remakeConstraints {(remake) in
remake.left.top.bottom.equalToSuperview()
remake.width.equalToSuperview().multipliedBy(progress)
}
}
private func updateCurrentViewWith(proress:CGFloat) {
let targetIndex = Int(CGFloat(currentItems.count - 1) * proress)
let item = currentItems[targetIndex]
currenTimeView.configure(timeItem: item)
}
private func updateUI() {
container.backgroundColor = ThemeManager.currentTheme.mapControlsColor
......@@ -86,7 +154,16 @@ class MapTimeControlView: UIView {
}
@objc private func handlePlayButton() {
switch playButtonState {
case .play:
playButton.setImage(UIImage(named: "pause_icon"), for: .normal)
delegate?.didSelectPlayButton()
self.playButtonState = .pause
case .pause:
playButton.setImage(UIImage(named: "play_icon"), for: .normal)
delegate?.didSelectPauseButton()
self.playButtonState = .play
}
}
}
......@@ -111,7 +188,7 @@ private extension MapTimeControlView {
}
func preparePlayButton() {
playButton.setImage(UIImage(named: "play_icon"), for: .normal)
playButton.setImage(UIImage(named: "pause_icon"), for: .normal)
playButton.tintColor = ThemeManager.currentTheme.graphTintColor
playButton.layer.shadowColor = UIColor.black.withAlphaComponent(0.12).cgColor
playButton.layer.shadowOffset = .init(width: 0, height: 3)
......@@ -145,14 +222,16 @@ private extension MapTimeControlView {
}
func prepareCurrentTimeView() {
currenTimeView.isHidden = true
addSubview(currenTimeView)
currenTimeView.snp.makeConstraints { (make) in
make.top.equalToSuperview()
make.bottom.equalTo(container.snp.top)
make.centerX.equalToSuperview()
make.centerX.equalTo(progresView.snp.right)
}
//Dash line
currentTimeDashLine.isHidden = true
currentTimeDashLine.lineWidth = 1
currentTimeDashLine.strokeColor = ThemeManager.currentTheme.graphTintColor.cgColor
currentTimeDashLine.lineDashPattern = [2,2]
......@@ -161,13 +240,12 @@ private extension MapTimeControlView {
func prepareProgressView() {
progresView.layer.cornerRadius = container.layer.cornerRadius
progresView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
progresView.backgroundColor = ThemeManager.currentTheme.graphTintColor.withAlphaComponent(0.2)
container.insertSubview(progresView, belowSubview: playButton)
progresView.snp.makeConstraints { (make) in
make.left.top.bottom.equalToSuperview()
self.progressWidthConstraint = make.width.equalToSuperview().multipliedBy(0.5).constraint
make.width.equalToSuperview().multipliedBy(0)
}
}
}
......@@ -10,7 +10,7 @@ import UIKit
class MapTimeView: UIView {
private let valueLabel = UILabel()
private let timeLabel = UILabel()
private static let timeFormatter:DateFormatter = {
private static var timeFormatter:DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "h:mm"
return fmt
......@@ -23,6 +23,7 @@ class MapTimeView: UIView {
updateUI()
valueLabel.text = item.value
MapTimeView.timeFormatter.timeZone = item.timeZone
timeLabel.text = MapTimeView.timeFormatter.string(from: item.date)
}
......@@ -50,11 +51,9 @@ class MapTimeView: UIView {
//MARK:- Prepare
private extension MapTimeView {
func prepareLabels() {
valueLabel.text = "45°"
valueLabel.font = AppFont.SFPro.regular(size: 10)
addSubview(valueLabel)
timeLabel.text = "2:00"
timeLabel.textAlignment = .center
timeLabel.font = AppFont.SFPro.regular(size: 14)
timeLabel.setContentCompressionResistancePriority(.fittingSizeLevel, for: .vertical)
......
......@@ -156,6 +156,7 @@ extension RadarMapLayersController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
cellFactory.didSelectRow(indexPath: indexPath)
tableView.reloadData()
self.handleCloseButton()
}
}
......
......@@ -32,7 +32,6 @@ class RadarViewController: UIViewController {
if let overlay = swarmOverlay {
overlay.startUpdating(block: { [weak self] (dataAvailable, updateError) in
self?.swarmRenderer?.setNeedsDisplay()
// print("[SWARM] Updating: \(String(describing: self?.updateDateLabel()))")
})
mapView.addOverlay(overlay, level: .aboveRoads)
swarmRenderer?.setNeedsDisplay() // forces overlay to update to latest radar view
......@@ -116,34 +115,42 @@ class RadarViewController: UIViewController {
return
}
var rawOverlay:SwarmOverlay?
if let weatherLayer = selectedLayer.layer as? WeatherLayerType {
let overlay = SwarmManager.sharedManager.overlayForGroup(.none, baseLayer: weatherLayer.swarmLayer)
rawOverlay = SwarmManager.sharedManager.overlayForBaseLayer(weatherLayer.swarmLayer)
// This is needed to use enhanced styles for international radar
if weatherLayer.swarmLayer == .satellite {
overlay.style = "enhanced"
rawOverlay?.style = "enhanced"
}
}
if let severeLayer = selectedLayer.layer as? SevereLayerType {
rawOverlay = SwarmManager.sharedManager.overlayForGroup(severeLayer.swarmLayer, baseLayer: .radar)
}
guard let overlay = rawOverlay else { return }
// set this offset to 1 to animate at lower zoom level (loads fewer tiles, faster), 0 is normal
overlay.loopZoomOffset = 0
overlay.alpha = 0.85
//overlay.debug = true
overlay.queryTimes {[weak self] (_, error) in
guard let self = self else { return }
// set this offset to 1 to animate at lower zoom level (loads fewer tiles, faster), 0 is normal
overlay.loopZoomOffset = 0
overlay.alpha = 0.85
// overlay.debug = true
self.swarmOverlay = overlay
overlay.queryTimes {[weak self] (_, error) in
guard let self = self else { return }
self.swarmOverlay = overlay
//Update timeline
if let validTimes = overlay.validTimes as? [String:AnyObject] {
let dates = validTimes.map{$0.value}.first as? [String]
if let stringArray = dates {
let items = self.radarViewModel.buildTimelineValuesFor(validTimes: stringArray)
if let timeZone = self.radarViewModel.location?.timeZone {
self.mapTimeControlView.configure(items: items, timeZone: timeZone)
}
//Update timeline
if let validTimes = overlay.validTimes as? [String:AnyObject] {
let dates = validTimes.map{$0.value}.first as? [String]
if let stringArray = dates {
let items = self.radarViewModel.buildTimelineValuesFor(validTimes: stringArray)
if let timeZone = self.radarViewModel.location?.timeZone {
self.mapTimeControlView.configure(items: items, timeZone: timeZone)
self.mapTimeControlView.updateProgress(value: 0)
}
}
// _ = self.updateDateLabel()
}
}
}
......@@ -156,18 +163,15 @@ class RadarViewController: UIViewController {
private func beginLoop() {
guard let overlay = swarmOverlay else { return }
// progressView.isHidden = false
// progressView.progress = 0.0
// playButton.setImage(UIImage(named: "pause_white"), for: .normal)
// playButton.accessibilityLabel = "Pause".localized
DispatchQueue.global(qos: .userInitiated).async {
/*self.progress*/ _ = overlay.fetchTilesForAnimation(self.mapView.visibleMapRect, readyBlock: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.swarmOverlay?.startAnimating({(_) in
// let _ = self?.updateDateLabel() ?? ""
// print("Animation: \(time)")
self?.swarmRenderer?.setNeedsDisplay()//setNeedsDisplayInMapRect((self?.mapView.visibleMapRect)!)
strongSelf.swarmOverlay?.startAnimating({ (_) in
self?.swarmRenderer?.setNeedsDisplay()
},
{ (currentFrame, totalFrames) in
strongSelf.mapTimeControlView.updateProgress(value: CGFloat(currentFrame) / CGFloat(totalFrames))
})
})
}
......@@ -175,11 +179,8 @@ class RadarViewController: UIViewController {
private func endLoop() {
DispatchQueue.global(qos: .userInitiated).async {
self.swarmOverlay?.stopAnimating(jumpToLastFrame: true)
self.swarmOverlay?.stopAnimating(jumpToLastFrame: false)
}
// progressView.isHidden = true
// playButton.setImage(UIImage(named: "play_white"), for: .normal)
// playButton.accessibilityLabel = "Play".localized
swarmRenderer?.setNeedsDisplay(mapView.visibleMapRect)
}
......@@ -335,6 +336,7 @@ private extension RadarViewController {
}
func prepareMapTimeControl() {
mapTimeControlView.delegate = self
view.insertSubview(mapTimeControlView, belowSubview: legendView)
mapTimeControlView.snp.makeConstraints { (make) in
make.left.equalToSuperview().inset(4)
......@@ -354,6 +356,7 @@ extension RadarViewController: RadarViewModelDelegate {
func viewModel(model: RadarViewModel, didSelectLayer layer: RadarLayer) {
pinnedLayersView.selectLayer(radarLayer: layer)
legendView.configure(radarLayer: layer)
setOverlay()
}
func viewModelPinnedLayersDidChange(model: RadarViewModel) {
......@@ -399,3 +402,18 @@ extension RadarViewController: MapPinnedLayersViewDelegate {
radarViewModel.select(layerId: layerId)
}
}
//MARK:- MapTimeControleView Delegate
extension RadarViewController: MapTimeControlViewDelegate {
func didSelectPlayButton() {
beginLoop()
}
func didSelectPauseButton() {
endLoop()
}
func didSelect(item: MapTimeControlItem) {
//
}
}
......@@ -106,8 +106,7 @@ class RadarViewModel: ViewModelProtocol {
continue
}
let timeZoneDate = validDate.convert(from: locationTimeZone, to: TimeZone(secondsFromGMT: 0)!)
items.append(.init(value: "", date: timeZoneDate))
items.append(.init(value: "", date: validDate, timeZone: locationTimeZone))
// for hourlyWeather in hourly {
// if validDate == hourlyWeather.date {
......
import Foundation
import UIKit
let far = Measurement<UnitTemperature>(value: 50, unit: .fahrenheit)
let fmt = MeasurementFormatter()
fmt.unitStyle = .long
fmt.unitOptions = .providedUnit
fmt.string(from: far.converted(to: .kelvin))
......@@ -315,12 +315,17 @@ extension SwarmOverlay {
public func stopUpdating() { updateTimer?.invalidate(); updateTimer = nil }
public func startAnimating(_ onFrameChanged: @escaping ((UIImage?)->Void)) {
public func startAnimating(_ onFrameChanged: @escaping ((UIImage?)->Void),
_ onProgress:((_ currentFrame:Int,_ totalFrames:Int) -> Void)? = nil) {
frameTimer?.invalidate()
frameTimer = Timer.repeatingBlockTimer(0.4) { [weak self] in
guard let strongSelf = self else { return }
var nextFrame = strongSelf.index + 1
if nextFrame == strongSelf.loopTimes.count && strongSelf.frameDwell == 0 {
onProgress?(nextFrame, strongSelf.loopTimes.count)
}
if (nextFrame >= strongSelf.loopTimes.count) {
strongSelf.frameDwell = strongSelf.frameDwell + 1
......@@ -329,17 +334,23 @@ extension SwarmOverlay {
}
}
if nextFrame >= strongSelf.loopTimes.count { strongSelf.frameDwell = 0; nextFrame = 0 }
if nextFrame >= strongSelf.loopTimes.count { strongSelf.frameDwell = 0; nextFrame = 0}
strongSelf.index = nextFrame
onFrameChanged(strongSelf.renderedImageCache.object(forKey: strongSelf.currentFrameTimestamp as AnyObject) as? UIImage)
onProgress?(nextFrame, strongSelf.loopTimes.count)
}
}
public func stopAnimating(jumpToLastFrame: Bool = false) {
frameTimer?.invalidate(); frameTimer = nil
frameTimer?.invalidate()
frameTimer = nil
cancelLoading()
if jumpToLastFrame {frameDwell = dwellCount; index = loopTimes.count - 1 }
if jumpToLastFrame {
frameDwell = dwellCount
index = loopTimes.count - 1
}
}
public func pauseForMove() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment