Commit 867a91f2 by Dmitriy Stepanets

Finished RadarController UI

parent 2d2dd5f8
No preview for this file type
......@@ -69,6 +69,14 @@
CD593BDC2608CDF100C93428 /* Date+Now.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD593BDB2608CDF100C93428 /* Date+Now.swift */; };
CD647D0225ED07D60034578B /* TodayViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD647D0125ED07D60034578B /* TodayViewModel.swift */; };
CD647D0625ED08050034578B /* ViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD647D0525ED08050034578B /* ViewModelProtocol.swift */; };
CD67616A262575CD0079D273 /* MapLegendGradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD676169262575CD0079D273 /* MapLegendGradientView.swift */; };
CD67616D262587D30079D273 /* UITabBarController+Hide.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD67616C262587D30079D273 /* UITabBarController+Hide.swift */; };
CD67617026259D220079D273 /* RadarMapLayersController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD67616F26259D220079D273 /* RadarMapLayersController.swift */; };
CD67617726259DD70079D273 /* MapLayersPresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD67617626259DD70079D273 /* MapLayersPresentationAnimator.swift */; };
CD67617C2625A60B0079D273 /* MapLayersDismissAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD67617B2625A60B0079D273 /* MapLayersDismissAnimator.swift */; };
CD6761802625B0F50079D273 /* RadarLayerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD67617F2625B0F50079D273 /* RadarLayerCell.swift */; };
CD6761842625B6A10079D273 /* RadarLayersCellFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6761832625B6A10079D273 /* RadarLayersCellFactory.swift */; };
CD6761882625C3360079D273 /* RadarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6761872625C3360079D273 /* RadarViewModel.swift */; };
CD6B3036257262C2004B34B3 /* UIColor+Highlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B3035257262C2004B34B3 /* UIColor+Highlight.swift */; };
CD6B303B2572680C004B34B3 /* SelfSizingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */; };
CD6B303E25726960004B34B3 /* ThemeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6B303D25726960004B34B3 /* ThemeProtocol.swift */; };
......@@ -261,6 +269,14 @@
CD593BDB2608CDF100C93428 /* Date+Now.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Now.swift"; sourceTree = "<group>"; };
CD647D0125ED07D60034578B /* TodayViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewModel.swift; sourceTree = "<group>"; };
CD647D0525ED08050034578B /* ViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelProtocol.swift; sourceTree = "<group>"; };
CD676169262575CD0079D273 /* MapLegendGradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLegendGradientView.swift; sourceTree = "<group>"; };
CD67616C262587D30079D273 /* UITabBarController+Hide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITabBarController+Hide.swift"; sourceTree = "<group>"; };
CD67616F26259D220079D273 /* RadarMapLayersController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarMapLayersController.swift; sourceTree = "<group>"; };
CD67617626259DD70079D273 /* MapLayersPresentationAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLayersPresentationAnimator.swift; sourceTree = "<group>"; };
CD67617B2625A60B0079D273 /* MapLayersDismissAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLayersDismissAnimator.swift; sourceTree = "<group>"; };
CD67617F2625B0F50079D273 /* RadarLayerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarLayerCell.swift; sourceTree = "<group>"; };
CD6761832625B6A10079D273 /* RadarLayersCellFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarLayersCellFactory.swift; sourceTree = "<group>"; };
CD6761872625C3360079D273 /* RadarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadarViewModel.swift; sourceTree = "<group>"; };
CD6B3035257262C2004B34B3 /* UIColor+Highlight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Highlight.swift"; sourceTree = "<group>"; };
CD6B303A2572680C004B34B3 /* SelfSizingButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfSizingButton.swift; sourceTree = "<group>"; };
CD6B303D25726960004B34B3 /* ThemeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeProtocol.swift; sourceTree = "<group>"; };
......@@ -501,6 +517,7 @@
CDC70832260FBFD3004A1974 /* UnitPressure+Atmosphere.swift */,
CDF4808E261727E00076E9F5 /* CLAuthorizationStatus+Localized.swift */,
CDF48091261729680076E9F5 /* UIApplication+Settings.swift */,
CD67616C262587D30079D273 /* UITabBarController+Hide.swift */,
);
path = Extensions;
sourceTree = "<group>";
......@@ -636,10 +653,29 @@
CD32CE07260C743B00235081 /* MenuViewModel.swift */,
CD37D3F5260DF5BA002669D6 /* SettingsViewModel.swift */,
CD866A6E260F67F200E96A5C /* SettingsDetailsViewModel.swift */,
CD6761872625C3360079D273 /* RadarViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
};
CD67617526259DBE0079D273 /* Animators */ = {
isa = PBXGroup;
children = (
CD67617626259DD70079D273 /* MapLayersPresentationAnimator.swift */,
CD67617B2625A60B0079D273 /* MapLayersDismissAnimator.swift */,
);
path = Animators;
sourceTree = "<group>";
};
CD67617E2625B0DE0079D273 /* Cells */ = {
isa = PBXGroup;
children = (
CD67617F2625B0F50079D273 /* RadarLayerCell.swift */,
CD6761832625B6A10079D273 /* RadarLayersCellFactory.swift */,
);
path = Cells;
sourceTree = "<group>";
};
CD6B3038257267E2004B34B3 /* View controllers */ = {
isa = PBXGroup;
children = (
......@@ -676,9 +712,12 @@
CD7BF15026203E2300A30DF5 /* Radar */ = {
isa = PBXGroup;
children = (
CD67617E2625B0DE0079D273 /* Cells */,
CD67617526259DBE0079D273 /* Animators */,
CDAD97B726207DFE007FCFB1 /* MapTimeControl */,
CDAD97AF26204285007FCFB1 /* Controls */,
CD7BF15426203E6900A30DF5 /* RadarViewController.swift */,
CD67616F26259D220079D273 /* RadarMapLayersController.swift */,
);
path = Radar;
sourceTree = "<group>";
......@@ -746,6 +785,7 @@
children = (
CDAD97B0262042B2007FCFB1 /* MapButton.swift */,
CD18728A2624763000AFEDAA /* MapLegendView.swift */,
CD676169262575CD0079D273 /* MapLegendGradientView.swift */,
);
path = Controls;
sourceTree = "<group>";
......@@ -1237,13 +1277,17 @@
87C1724925FF94F400DA3464 /* ConfigManager.swift in Sources */,
CE9D181925ECB9A70028D9D7 /* Logger.swift in Sources */,
CE8962AE26175DF500CA274A /* CoreLocation.swift in Sources */,
CD67616A262575CD0079D273 /* MapLegendGradientView.swift in Sources */,
CE578FD325F7E89400E8B85D /* DayTimeWeather.swift in Sources */,
CD593BCC2608A4F200C93428 /* ForecastDailyCell.swift in Sources */,
CEF959692600C30500975FAA /* Global.swift in Sources */,
CEAFF08925DFC6B200DF4EBF /* CurrentWeather.swift in Sources */,
CD866A72260F6A5300E96A5C /* SettingsDetailsCell.swift in Sources */,
CD6761802625B0F50079D273 /* RadarLayerCell.swift in Sources */,
CEC5270325E7BB4000DA58A5 /* WdtSurfaceObservation.swift in Sources */,
CE28474F26159857006C8DC5 /* HealthSource.swift in Sources */,
CD6761842625B6A10079D273 /* RadarLayersCellFactory.swift in Sources */,
CD67617C2625A60B0079D273 /* MapLayersDismissAnimator.swift in Sources */,
CEAFF08C25DFC6BD00DF4EBF /* DailyWeather.swift in Sources */,
CEDE4F0B25EFA3A7007457E9 /* UpdatableModelObject.swift in Sources */,
CE8962A626175DF500CA274A /* _CoreHealth.swift in Sources */,
......@@ -1262,6 +1306,7 @@
CDAD97B426207D14007FCFB1 /* MapTimeControlView.swift in Sources */,
CD32CE0E260C770E00235081 /* MenuHeaderView.swift in Sources */,
CD15DB3D25DA6C5100024727 /* ForecastTimePeriodControl.swift in Sources */,
CD67617726259DD70079D273 /* MapLayersPresentationAnimator.swift in Sources */,
CD1237F1255D83C500C98139 /* UIColor+Hex.swift in Sources */,
CD7BF1582620410800A30DF5 /* RadarCoordinator.swift in Sources */,
CDD0F1EE25725BCF00CF5017 /* ThemeManager.swift in Sources */,
......@@ -1327,6 +1372,7 @@
CE578FE725FB415F00E8B85D /* LocationsViewModel.swift in Sources */,
CD82300A25D6B2AF00A05501 /* AppTabBarController.swift in Sources */,
CE9F01C1261B3776009BA500 /* CoreDataUtils.swift in Sources */,
CD67616D262587D30079D273 /* UITabBarController+Hide.swift in Sources */,
CDC6126225E8DAB800188DA7 /* MoonPhaseCell.swift in Sources */,
CD37D3D6260C93B3002669D6 /* MenuCellFactory.swift in Sources */,
CD37D3FA260DF714002669D6 /* SettingsThemeCell.swift in Sources */,
......@@ -1336,6 +1382,7 @@
CD9B6B1125DBC723001D9B80 /* CubicCurveAlgorithm.swift in Sources */,
CEC5270025E7BACB00DA58A5 /* WdtLocation.swift in Sources */,
CE8962A726175DF500CA274A /* _CoreLocation.swift in Sources */,
CD67617026259D220079D273 /* RadarMapLayersController.swift in Sources */,
CD866A65260F642600E96A5C /* SettingsDetailsViewController.swift in Sources */,
CD647D0225ED07D60034578B /* TodayViewModel.swift in Sources */,
CD593BD32608BC3F00C93428 /* ForecastDayCell.swift in Sources */,
......@@ -1355,6 +1402,7 @@
CD86246125E662BC0097F3FB /* SunUvLineView.swift in Sources */,
CD32CE0B260C744A00235081 /* MenuCoordinator.swift in Sources */,
CD55E0BB2615EE2400CC4DC7 /* PollutantView.swift in Sources */,
CD6761882625C3360079D273 /* RadarViewModel.swift in Sources */,
CDF8F12A262089A200DB384A /* MapTimeView.swift in Sources */,
CEC526FA25E7959A00DA58A5 /* WeatherSource.swift in Sources */,
CDF4808F261727E00076E9F5 /* CLAuthorizationStatus+Localized.swift in Sources */,
......
......@@ -7,7 +7,7 @@
<key>1Weather.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>22</integer>
<integer>24</integer>
</dict>
<key>PG (Playground) 1.xcscheme</key>
<dict>
......
//
// UITabBarController+Hide.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
extension UITabBarController {
/**
Show or hide the tab bar.
- Parameter hidden: `true` if the bar should be hidden.
- Parameter animated: `true` if the action should be animated.
- Parameter transitionCoordinator: An optional `UIViewControllerTransitionCoordinator` to perform the animation
along side with. For example during a push on a `UINavigationController`.
*/
func setTabBar(hidden: Bool, animated: Bool = true, along transitionCoordinator: UIViewControllerTransitionCoordinator? = nil) {
guard isTabBarHidden != hidden else { return }
let offsetY = hidden ? tabBar.frame.height : -tabBar.frame.height
let endFrame = tabBar.frame.offsetBy(dx: 0, dy: offsetY)
let vc: UIViewController? = viewControllers?[selectedIndex]
var newInsets: UIEdgeInsets? = vc?.additionalSafeAreaInsets
let originalInsets = newInsets
newInsets?.bottom -= offsetY
/// Helper method for updating child view controller's safe area insets.
func set(childViewController cvc: UIViewController?, additionalSafeArea: UIEdgeInsets) {
cvc?.additionalSafeAreaInsets = additionalSafeArea
cvc?.view.setNeedsLayout()
}
// Update safe area insets for the current view controller before the animation takes place when hiding the bar.
if hidden, let insets = newInsets { set(childViewController: vc, additionalSafeArea: insets) }
guard animated else {
tabBar.frame = endFrame
return
}
// Perform animation with coordinato if one is given. Update safe area insets _after_ the animation is complete,
// if we're showing the tab bar.
weak var tabBarRef = self.tabBar
if let tc = transitionCoordinator {
tc.animateAlongsideTransition(in: self.view, animation: { _ in tabBarRef?.frame = endFrame }) { context in
if !hidden, let insets = context.isCancelled ? originalInsets : newInsets {
set(childViewController: vc, additionalSafeArea: insets)
}
}
} else {
UIView.animate(withDuration: 0.25, animations: { tabBarRef?.frame = endFrame }) { didFinish in
if !hidden, didFinish, let insets = newInsets {
set(childViewController: vc, additionalSafeArea: insets)
}
}
}
}
/// `true` if the tab bar is currently hidden.
var isTabBarHidden: Bool {
return !tabBar.frame.intersects(view.frame)
}
}
{
"images" : [
{
"filename" : "map_legend_close.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}
{
"images" : [
{
"filename" : "radar_layer_pin.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
......@@ -118,6 +118,10 @@
"location.status.whenInUser" = "when in use";
"location.status.unknown" = "unknown";
//Radar
"radar.layers.base" = "Base layer";
"radar.layers.severe" = "Severe weather layer";
//Menu
"menu.goPremium" = "Go premium";
"menu.premium.desc" = "Experience app without ads @ $8.99 a year";
......
//
// MapLayersDismissAnimator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
class MapLayersDismissAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromViewController = transitionContext.viewController(forKey: .from) else {
return
}
let container = transitionContext.containerView
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
fromViewController.view.frame.origin.x = container.bounds.width
} completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
//
// MapLayersPresentationAnimator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
class MapLayersPresentationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let toViewController = transitionContext.viewController(forKey: .to) else {
return
}
let container = transitionContext.containerView
toViewController.view.frame = .init(x: container.bounds.width,
y: 0,
width: 220,
height: container.frame.height)
container.addSubview(toViewController.view)
UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
toViewController.view.frame.origin.x = container.frame.width - 220
} completion: { finished in
transitionContext.completeTransition(finished)
}
}
}
//
// RadarLayerCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
class RadarLayerCell: UITableViewCell {
//Private
private let nameLabel = UILabel()
private let pinButton = UIButton()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
prepareCell()
preparePinButton()
prepareNameLabel()
updateUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func configure(text:String) {
nameLabel.text = text
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
updateUI()
}
private func updateUI() {
switch interfaceStyle {
case .light:
nameLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
case .dark:
nameLabel.textColor = ThemeManager.currentTheme.primaryTextColor
}
}
@objc private func handlePinButton() {
}
}
//MARK:- Prepare
private extension RadarLayerCell {
func prepareCell() {
selectionStyle = .none
contentView.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
}
func prepareNameLabel() {
nameLabel.lineBreakMode = .byTruncatingTail
nameLabel.font = AppFont.SFPro.regular(size: 14)
contentView.addSubview(nameLabel)
nameLabel.snp.makeConstraints { (make) in
make.left.equalToSuperview().inset(15)
make.centerY.equalToSuperview()
make.right.equalTo(pinButton.snp.left).inset(8).priority(999)
}
}
func preparePinButton() {
pinButton.setImage(UIImage(named: "radar_layer_pin"), for: .normal)
pinButton.tintColor = .white
pinButton.layer.cornerRadius = 9
pinButton.backgroundColor = .black
pinButton.addTarget(self, action: #selector(handlePinButton), for: .touchUpInside)
contentView.addSubview(pinButton)
pinButton.snp.makeConstraints { (make) in
make.width.height.equalTo(18)
make.centerY.equalToSuperview()
make.right.equalToSuperview().inset(22)
}
}
}
//
// RadarLayersCellFactory.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
private enum Section {
case base
case severe
}
private struct LayerSection {
let type:Section
let rows:[String]
}
class RadarLayersCellFactory: CellFactoryProtocol {
//Private
private let sections = [LayerSection(type: .base, rows: ["Temperature", "Precipitation", "Humidity", "Clouds", "Radar"]),
LayerSection(type: .severe, rows: ["None", "Fire", "Floods"])]
var numberOfSections: Int {
return sections.count
}
func numberOfRows(inSection section: Int) -> Int {
return sections[section].rows.count
}
func registerCells(on tableView: UITableView) {
registerCell(type: RadarLayerCell.self, tableView: tableView)
}
func cellFromTableView(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
let cell = dequeueReusableCell(type: RadarLayerCell.self, tableView: tableView, indexPath: indexPath)
cell.configure(text: sections[indexPath.section].rows[indexPath.row])
return cell
}
}
......@@ -40,19 +40,18 @@ class MapButton: UIControl {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
UIView.performWithoutAnimation {
self.alpha = 0.7
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
UIView.performWithoutAnimation {
self.alpha = 1
override var isHighlighted: Bool {
didSet {
if isHighlighted {
UIView.performWithoutAnimation {
self.alpha = 0.7
}
}
else {
UIView.performWithoutAnimation {
self.alpha = 1
}
}
}
}
......
//
// MapLegendGradientView.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
class MapLegendGradientView: UIView {
private let colors:[UIColor]
init(colors:[UIColor]) {
self.colors = colors
super.init(frame: .zero)
prepare()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override class var layerClass: AnyClass {
return CAGradientLayer.self
}
}
//MARK:- Prepare
private extension MapLegendGradientView {
func prepare() {
self.clipsToBounds = true
self.backgroundColor = .clear
guard let gradientLayer = self.layer as? CAGradientLayer else { return }
gradientLayer.colors = self.colors.map{$0.cgColor}
gradientLayer.startPoint = .init(x: 0, y: 0.5)
gradientLayer.endPoint = .init(x: 1, y: 0.5)
}
}
......@@ -12,15 +12,15 @@ class MapLegendView: UIView {
//Private
private let kOpenWidth:CGFloat = 180
private let kCloseWidth:CGFloat = 40
private let kPrecipitationColors = [UIColor(hex: 0x9c57fa).cgColor,
UIColor(hex: 0x5ef0e8).withAlphaComponent(0.8).cgColor,
UIColor(hex: 0x4ebaf6).cgColor]
private static let kPrecipitationColors = [UIColor(hex: 0x9c57fa),
UIColor(hex: 0x5ef0e8).withAlphaComponent(0.8),
UIColor(hex: 0x4ebaf6)]
private let button = UIButton()
private let viewGradient = CAGradientLayer()
private let buttonGradient = CAGradientLayer()
private let legendGradient = CAGradientLayer()
private let legendLabels = [UILabel]()
private var widthConstraint:Constraint?
private let legendGradient = MapLegendGradientView(colors: MapLegendView.kPrecipitationColors)
private let legendLabelsStackView = UIStackView()
private var legendLabels = [UILabel]()
private var isOpened = false
init() {
......@@ -29,6 +29,7 @@ class MapLegendView: UIView {
prepareView()
prepareViewGradient()
prepareButton()
prepareLegend()
updateUI()
}
......@@ -75,8 +76,12 @@ class MapLegendView: UIView {
}
self.setNeedsLayout()
self.button.setImage(isOpened ? UIImage(named: "map_legend_close") : nil, for: .normal)
UIView.animate(withDuration: 0.3) {
self.superview?.layoutIfNeeded()
self.legendGradient.alpha = self.isOpened ? 1 : 0
self.legendLabelsStackView.alpha = self.isOpened ? 1 : 0
self.layer.borderWidth = self.isOpened ? 0.5 : 0
}
}
}
......@@ -85,14 +90,14 @@ class MapLegendView: UIView {
private extension MapLegendView {
func prepareView() {
self.clipsToBounds = false
self.layer.borderColor = UIColor(hex: 0x353535).cgColor
layer.shadowColor = UIColor.black.withAlphaComponent(0.3).cgColor
layer.shadowOffset = .init(width: 0, height: 3)
layer.shadowOpacity = 1
layer.shadowRadius = 5
self.snp.makeConstraints { (make) in
self.widthConstraint = make.width.equalTo(40).priority(1000).constraint
make.height.equalTo(40).priority(1000)
make.width.height.equalTo(40).priority(1000)
}
}
......@@ -105,7 +110,7 @@ private extension MapLegendView {
}
func prepareButton() {
buttonGradient.colors = self.kPrecipitationColors
buttonGradient.colors = MapLegendView.kPrecipitationColors.map{$0.cgColor}
buttonGradient.startPoint = .init(x: 0, y: 0.5)
buttonGradient.endPoint = .init(x: 1, y: 0.5)
......@@ -120,4 +125,37 @@ private extension MapLegendView {
make.centerY.equalToSuperview()
}
}
func prepareLegend() {
legendGradient.alpha = 0
legendGradient.layer.cornerRadius = 2
addSubview(legendGradient)
legendGradient.snp.makeConstraints { (make) in
make.left.equalTo(button.snp.right).offset(6).priority(999)
make.top.equalToSuperview().inset(13)
make.height.equalTo(4)
make.right.equalToSuperview().inset(17)
}
//Labels
legendLabelsStackView.alpha = 0
legendLabelsStackView.axis = .horizontal
legendLabelsStackView.distribution = .equalCentering
addSubview(legendLabelsStackView)
legendLabelsStackView.snp.makeConstraints { (make) in
make.left.right.equalTo(legendGradient)
make.top.equalTo(legendGradient.snp.bottom).offset(6)
}
let values = ["1%", "25%", "50%", "100%"]
values.enumerated().forEach {
let label = UILabel()
label.font = AppFont.SFPro.regular(size: 10)
label.text = $1
self.legendLabels.append(label)
legendLabelsStackView.addArrangedSubview(label)
}
}
}
......@@ -58,7 +58,7 @@ private extension MapPinnedLayersView {
pinContainer.snp.makeConstraints { (make) in
make.left.equalToSuperview()
make.height.equalTo(40)
make.centerY.equalToSuperview()
make.top.equalToSuperview().inset(3)
make.width.equalTo(36)
}
......@@ -85,7 +85,7 @@ private extension MapPinnedLayersView {
scrollView.snp.makeConstraints { (make) in
make.left.equalTo(pinContainer.snp.right).offset(6)
make.right.equalToSuperview()
make.top.bottom.equalToSuperview().inset(8)
make.top.equalToSuperview().inset(8)
}
}
......
//
// RadarMapLayersController.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
class RadarMapLayersController: UIViewController {
//Private
private let cellFactory = RadarLayersCellFactory()
private let tableView = UITableView(frame: .zero, style: .grouped)
init() {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
prepareTableView()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tableView.layer.shadowPath = CGPath(rect: self.view.bounds, transform: nil)
}
@objc private func handleCloseButton() {
self.dismiss(animated: true)
}
}
//MARK:- Prepare
private extension RadarMapLayersController {
func prepareController() {
}
func prepareTableView() {
cellFactory.registerCells(on: tableView)
tableView.clipsToBounds = false
tableView.layer.shadowColor = UIColor.black.withAlphaComponent(0.12).cgColor
tableView.layer.shadowRadius = 8
tableView.layer.shadowOffset = .init(width: 0, height: 3)
tableView.layer.shadowOpacity = 1
tableView.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
tableView.tableHeaderView = UIView(frame: .init(origin: .zero, size: CGSize(width: 0, height: 0.01)))
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = 46
tableView.tableFooterView = UIView()
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
}
//MARK:- UITableView Data Source
extension RadarMapLayersController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return cellFactory.numberOfSections
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellFactory.numberOfRows(inSection: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return cellFactory.cellFromTableView(tableView: tableView, indexPath: indexPath)
}
}
//MARK:- UITableView Delegate
extension RadarMapLayersController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return .leastNormalMagnitude
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return nil
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let container = UIView()
container.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
switch section {
case 0:
let closeButton = UIButton()
closeButton.setTitle("general.close".localized().capitalized, for: .normal)
closeButton.setTitleColor(ThemeManager.currentTheme.graphTintColor, for: .normal)
closeButton.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside)
closeButton.titleLabel?.font = AppFont.SFPro.regular(size: 14)
container.addSubview(closeButton)
closeButton.snp.makeConstraints { (make) in
make.height.equalTo(24)
make.right.equalToSuperview().inset(20)
make.top.equalToSuperview().inset(18)
}
let label = UILabel()
label.textColor = view.interfaceStyle == .light ? ThemeManager.currentTheme.secondaryTextColor :
ThemeManager.currentTheme.primaryTextColor
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.font = AppFont.SFPro.bold(size: 18)
label.text = "radar.layers.base".localized()
container.addSubview(label)
label.snp.makeConstraints { (make) in
make.left.equalToSuperview().inset(18)
make.top.bottom.equalToSuperview().inset(18)
make.right.equalTo(closeButton.snp.left).offset(8).priority(999)
}
case 1:
let label = UILabel()
label.textColor = view.interfaceStyle == .light ? ThemeManager.currentTheme.secondaryTextColor :
ThemeManager.currentTheme.primaryTextColor
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.font = AppFont.SFPro.bold(size: 18)
label.text = "radar.layers.severe".localized()
container.addSubview(label)
label.snp.makeConstraints { (make) in
make.left.right.equalToSuperview().inset(18)
make.top.bottom.equalToSuperview().inset(18)
}
default:
return nil
}
return container
}
}
//MARK:- Transitioning Delegate
extension RadarMapLayersController: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MapLayersPresentationAnimator()
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MapLayersDismissAnimator()
}
}
......@@ -10,10 +10,13 @@ import MapKit
class RadarViewController: UIViewController {
//Private
private let kPinnedLayersHeight:CGFloat = 43
private let radarViewModel = RadarViewModel()
private let coordinator:RadarCoordinator
private let cityButton = NavigationCityButton()
private var localizationObserver:Any?
private let mapView = MKMapView()
private var isFullScreen = false
//Buttons
private let fullScreenButton = MapButton(image: UIImage(named: "map_fullscreen"))
......@@ -23,7 +26,6 @@ class RadarViewController: UIViewController {
private let mapTimeControlView = MapTimeControlView()
private let pinnedLayersView = MapPinnedLayersView()
private let locationButton = UIButton()
init(coordinator:RadarCoordinator) {
self.coordinator = coordinator
......@@ -42,40 +44,73 @@ class RadarViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
radarViewModel.delegate = self
extendedLayoutIncludesOpaqueBars = true
edgesForExtendedLayout = [.bottom]
prepareNavigationBar()
prepareViewController()
// prepareMapView()
prepareMapView()
prepareMapPinnedLayers()
prepareLocationButton()
prepareMapButtons()
prepareMapTimeControl()
updateUI()
centerMap()
cityButton.configure(with: radarViewModel.location)
}
//Private
private func updateUI() {
view.backgroundColor = .red//ThemeManager.currentTheme.baseBackgroundColor
view.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
locationButton.backgroundColor = ThemeManager.currentTheme.mapControlsColor
}
@objc private func handleCityButton() {
private func centerMap() {
guard let coordinates = radarViewModel.location?.coordinates else {
return
}
let region = MKCoordinateRegion(center: coordinates, latitudinalMeters: 4000, longitudinalMeters: 4000)
mapView.setRegion(region, animated: true)
}
@objc private func handleNotificationButton() {
@objc private func handleCityButton() {
}
@objc private func handleFullScreenButton() {
@objc private func handleNotificationButton() {
}
@objc private func handlePrecipitationButton() {
@objc private func handleFullScreenButton() {
if isFullScreen {
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.tabBarController?.setTabBar(hidden: false, animated: true)
self.pinnedLayersView.snp.updateConstraints { (update) in
let tabBarHeight = self.tabBarController?.tabBar.frame.height ?? 0
update.height.equalTo(kPinnedLayersHeight + tabBarHeight)
}
isFullScreen = false
}
else {
self.navigationController?.setNavigationBarHidden(true, animated: true)
self.tabBarController?.setTabBar(hidden: true, animated: true)
self.pinnedLayersView.snp.updateConstraints { (update) in
update.height.equalTo(kPinnedLayersHeight + view.safeAreaInsets.bottom)
}
isFullScreen = true
}
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.25) {
self.view.layoutIfNeeded()
}
}
@objc private func handleLayersButton() {
let layersViewController = RadarMapLayersController()
self.present(layersViewController, animated: true)
}
@objc private func handleRadarButton() {
......@@ -128,7 +163,8 @@ private extension RadarViewController {
pinnedLayersView.snp.makeConstraints { (make) in
make.left.right.bottom.equalToSuperview()
// make.height.equalTo(43)
let tabBarHeight = self.tabBarController?.tabBar.frame.height ?? 0
make.height.equalTo(kPinnedLayersHeight + tabBarHeight)
}
}
......@@ -138,7 +174,7 @@ private extension RadarViewController {
view.addSubview(fullScreenButton)
fullScreenButton.snp.makeConstraints { (make) in
make.width.height.equalTo(40)
make.top.equalToSuperview().inset(16)
make.top.equalTo(view.safeAreaLayoutGuide.snp.top).inset(16)
make.right.equalToSuperview().inset(8)
}
......@@ -191,3 +227,11 @@ private extension RadarViewController {
}
}
}
//MARK:- ViewModel Delegate
extension RadarViewController: ViewModelDelegate {
func viewModelDidChange<P>(model: P) where P : ViewModelProtocol {
self.centerMap()
cityButton.configure(with: radarViewModel.location)
}
}
//
// RadarViewModel.swift
// 1Weather
//
// Created by Dmitry Stepanets on 13.04.2021.
//
import UIKit
class RadarViewModel: ViewModelProtocol {
//Public
public weak var delegate:ViewModelDelegate?
//Private
private let locationManager = LocationManager.shared
var location:Location? {
return locationManager.selectedLocation
}
init() {
locationManager.add(delegate: self)
}
}
//MARK:- LocationManager Delegate
extension RadarViewModel: LocationManagerDelegate {
func locationManager(_ locationManager: LocationManager, changedSelectedLocation newLocation: Location?) {
DispatchQueue.main.async {
self.delegate?.viewModelDidChange(model: self)
}
}
func locationManager(_ locationManager: LocationManager, updatedLocationsList newList: [Location]) {
// do nothing
}
}
......@@ -10,6 +10,8 @@ import UIKit
class TodayViewModel: ViewModelProtocol {
//Public
public weak var delegate:ViewModelDelegate?
//Private
private let locationManager = LocationManager.shared
private(set) var location:Location?
......
......@@ -21,14 +21,14 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
<key>Cirque.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>2</integer>
<integer>3</integer>
</dict>
<key>Cirque.xcscheme_^#shared#^_</key>
<dict>
......@@ -40,7 +40,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
<integer>5</integer>
</dict>
<key>Firebase.xcscheme_^#shared#^_</key>
<dict>
......@@ -52,7 +52,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>4</integer>
<integer>6</integer>
</dict>
<key>FirebaseABTesting.xcscheme_^#shared#^_</key>
<dict>
......@@ -64,7 +64,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>5</integer>
<integer>7</integer>
</dict>
<key>FirebaseAnalytics.xcscheme_^#shared#^_</key>
<dict>
......@@ -76,7 +76,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>6</integer>
<integer>8</integer>
</dict>
<key>FirebaseCore.xcscheme_^#shared#^_</key>
<dict>
......@@ -88,7 +88,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>7</integer>
<integer>9</integer>
</dict>
<key>FirebaseCoreDiagnostics.xcscheme_^#shared#^_</key>
<dict>
......@@ -100,7 +100,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>8</integer>
<integer>10</integer>
</dict>
<key>FirebaseCrashlytics.xcscheme_^#shared#^_</key>
<dict>
......@@ -112,7 +112,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>9</integer>
<integer>11</integer>
</dict>
<key>FirebaseInstallations.xcscheme_^#shared#^_</key>
<dict>
......@@ -124,7 +124,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>10</integer>
<integer>12</integer>
</dict>
<key>FirebaseRemoteConfig.xcscheme_^#shared#^_</key>
<dict>
......@@ -136,7 +136,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>11</integer>
<integer>13</integer>
</dict>
<key>Flurry-iOS-SDK.xcscheme_^#shared#^_</key>
<dict>
......@@ -148,7 +148,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>12</integer>
<integer>14</integer>
</dict>
<key>GoogleAppMeasurement.xcscheme_^#shared#^_</key>
<dict>
......@@ -160,7 +160,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>13</integer>
<integer>15</integer>
</dict>
<key>GoogleDataTransport.xcscheme_^#shared#^_</key>
<dict>
......@@ -172,7 +172,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>14</integer>
<integer>16</integer>
</dict>
<key>GoogleUtilities.xcscheme_^#shared#^_</key>
<dict>
......@@ -184,7 +184,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>15</integer>
<integer>17</integer>
</dict>
<key>Localize-Swift.xcscheme_^#shared#^_</key>
<dict>
......@@ -196,7 +196,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>16</integer>
<integer>18</integer>
</dict>
<key>Logging.xcscheme_^#shared#^_</key>
<dict>
......@@ -208,7 +208,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>18</integer>
<integer>20</integer>
</dict>
<key>MORichNotification.xcscheme_^#shared#^_</key>
<dict>
......@@ -220,7 +220,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>17</integer>
<integer>19</integer>
</dict>
<key>MoEngage-iOS-SDK.xcscheme_^#shared#^_</key>
<dict>
......@@ -232,14 +232,14 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>1</integer>
<integer>2</integer>
</dict>
<key>PromisesObjC.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>21</integer>
<integer>22</integer>
</dict>
<key>PromisesObjC.xcscheme_^#shared#^_</key>
<dict>
......@@ -251,7 +251,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>2</integer>
<integer>4</integer>
</dict>
<key>XMLCoder.xcscheme</key>
<dict>
......@@ -270,7 +270,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>19</integer>
<integer>21</integer>
</dict>
<key>nanopb.xcscheme_^#shared#^_</key>
<dict>
......
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