[ios] add TrackRecording widget to the top-right
Signed-off-by: Kiryl Kaveryn <kirylkaveryn@gmail.com>
This commit is contained in:
parent
4a33a609d8
commit
b03108318c
14 changed files with 241 additions and 5 deletions
|
@ -5,6 +5,7 @@
|
|||
|
||||
@class MapViewController;
|
||||
@class BottomTabBarViewController;
|
||||
@class TrackRecordingViewController;
|
||||
@protocol MWMFeatureHolder;
|
||||
|
||||
@interface MWMMapViewControlsManager : NSObject
|
||||
|
@ -18,7 +19,8 @@
|
|||
@property(nonatomic) MWMBottomMenuState menuState;
|
||||
@property(nonatomic) MWMBottomMenuState menuRestoreState;
|
||||
@property(nonatomic) BOOL isDirectionViewHidden;
|
||||
@property(nonatomic) BottomTabBarViewController *tabBarController;
|
||||
@property(nonatomic) BottomTabBarViewController * tabBarController;
|
||||
@property(nonatomic) TrackRecordingViewController * trackRecordingButton;
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("init is not available")));
|
||||
- (instancetype)initWithParentController:(MapViewController *)controller;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#import "MWMSearchManager.h"
|
||||
#import "MWMSideButtons.h"
|
||||
#import "MWMTrafficButtonViewController.h"
|
||||
#import "MWMMapWidgetsHelper.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "SwiftBridge.h"
|
||||
|
@ -63,9 +64,16 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
self.menuState = MWMBottomMenuStateInactive;
|
||||
self.menuRestoreState = MWMBottomMenuStateInactive;
|
||||
self.isAddingPlace = NO;
|
||||
[TrackRecordingManager.shared addObserver:self recordingIsActiveDidChangeHandler:^(BOOL isActive) {
|
||||
[self setTrackRecordingButtonHidden:!isActive];
|
||||
}];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[TrackRecordingManager.shared removeObserver:self];
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
BOOL const isSearchUnderStatusBar = (self.searchManager.state != MWMSearchManagerStateHidden);
|
||||
BOOL const isNavigationUnderStatusBar = self.navigationManager.state != MWMNavigationDashboardStateHidden &&
|
||||
|
@ -91,6 +99,7 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
[self.trafficButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.trackRecordingButton viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.tabBarController viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
[self.searchManager viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
}
|
||||
|
@ -311,6 +320,19 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
|
|||
self.trafficButton.hidden = self.hidden || _trafficButtonHidden;
|
||||
}
|
||||
|
||||
- (void)setTrackRecordingButtonHidden:(BOOL)trackRecordingButtonHidden {
|
||||
if (trackRecordingButtonHidden && _trackRecordingButton) {
|
||||
[self.trackRecordingButton closeWithCompletion:^{
|
||||
[MWMMapWidgetsHelper updateLayoutForAvailableArea];
|
||||
}];
|
||||
_trackRecordingButton = nil;
|
||||
}
|
||||
else if (!trackRecordingButtonHidden && !_trackRecordingButton) {
|
||||
_trackRecordingButton = [[TrackRecordingViewController alloc] init];
|
||||
[MWMMapWidgetsHelper updateLayoutForAvailableArea];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMenuState:(MWMBottomMenuState)menuState {
|
||||
_menuState = menuState;
|
||||
MapViewController * ownerController = _ownerController;
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
final class TrackRecordingViewController: MWMViewController {
|
||||
|
||||
private enum Constants {
|
||||
static let buttonDiameter = CGFloat(48)
|
||||
static let topOffset = CGFloat(6)
|
||||
static let trailingOffset = CGFloat(10)
|
||||
static let blinkingDuration = 1.0
|
||||
static let color: (lighter: UIColor, darker: UIColor) = (.red, .red.darker(percent: 0.3))
|
||||
}
|
||||
|
||||
private let trackRecordingManager: TrackRecordingManager = .shared
|
||||
private let button = BottomTabBarButton()
|
||||
private var blinkingTimer: Timer?
|
||||
private var topConstraint = NSLayoutConstraint()
|
||||
private var trailingConstraint = NSLayoutConstraint()
|
||||
|
||||
private static var availableArea: CGRect = .zero
|
||||
private static var topConstraintValue: CGFloat {
|
||||
availableArea.origin.y + Constants.topOffset
|
||||
}
|
||||
private static var trailingConstraintValue: CGFloat {
|
||||
-(UIScreen.main.bounds.maxX - availableArea.maxX + Constants.trailingOffset)
|
||||
}
|
||||
|
||||
@objc
|
||||
init() {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
let ownerViewController = MapViewController.shared()
|
||||
ownerViewController?.addChild(self)
|
||||
ownerViewController?.controlsView.addSubview(view)
|
||||
self.setupView()
|
||||
self.layout()
|
||||
self.startTimer()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
UIView.transition(with: self.view,
|
||||
duration: kDefaultAnimationDuration,
|
||||
options: .transitionCrossDissolve,
|
||||
animations: {
|
||||
self.button.isHidden = false
|
||||
})
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
@objc
|
||||
func close(completion: @escaping (() -> Void)) {
|
||||
stopTimer()
|
||||
UIView.transition(with: self.view,
|
||||
duration: kDefaultAnimationDuration,
|
||||
options: .transitionCrossDissolve,
|
||||
animations: {
|
||||
self.button.isHidden = true
|
||||
}, completion: { _ in
|
||||
self.removeFromParent()
|
||||
self.view.removeFromSuperview()
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func setupView() {
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(button)
|
||||
|
||||
button.setStyleAndApply("TrackRecordingWidgetButton")
|
||||
button.tintColor = Constants.color.darker
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.setImage(UIImage(resource: .icMenuBookmarkTrackRecording), for: .normal)
|
||||
button.addTarget(self, action: #selector(onTrackRecordingButtonPressed), for: .touchUpInside)
|
||||
button.isHidden = true
|
||||
}
|
||||
|
||||
private func layout() {
|
||||
guard let superview = view.superview else { return }
|
||||
topConstraint = view.topAnchor.constraint(equalTo: superview.topAnchor, constant: Self.topConstraintValue)
|
||||
trailingConstraint = view.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: Self.trailingConstraintValue)
|
||||
NSLayoutConstraint.activate([
|
||||
topConstraint,
|
||||
trailingConstraint,
|
||||
view.widthAnchor.constraint(equalToConstant: Constants.buttonDiameter),
|
||||
view.heightAnchor.constraint(equalToConstant: Constants.buttonDiameter),
|
||||
|
||||
button.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
button.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
button.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
button.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
guard let superview = self.view.superview else { return }
|
||||
superview.animateConstraints {
|
||||
self.topConstraint.constant = Self.topConstraintValue
|
||||
self.trailingConstraint.constant = Self.trailingConstraintValue
|
||||
}
|
||||
}
|
||||
|
||||
private func startTimer() {
|
||||
guard blinkingTimer == nil else { return }
|
||||
var lighter = false
|
||||
let timer = Timer.scheduledTimer(withTimeInterval: Constants.blinkingDuration, repeats: true) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
UIView.animate(withDuration: Constants.blinkingDuration, animations: {
|
||||
self.button.tintColor = lighter ? Constants.color.lighter : Constants.color.darker
|
||||
lighter.toggle()
|
||||
})
|
||||
}
|
||||
blinkingTimer = timer
|
||||
RunLoop.current.add(timer, forMode: .common)
|
||||
}
|
||||
|
||||
private func stopTimer() {
|
||||
blinkingTimer?.invalidate()
|
||||
blinkingTimer = nil
|
||||
}
|
||||
|
||||
static func updateAvailableArea(_ frame: CGRect) {
|
||||
availableArea = frame
|
||||
guard let controller = MapViewController.shared()?.controlsManager.trackRecordingButton else { return }
|
||||
DispatchQueue.main.async {
|
||||
controller.updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc
|
||||
private func onTrackRecordingButtonPressed(_ sender: Any) {
|
||||
switch trackRecordingManager.recordingState {
|
||||
case .inactive, .error:
|
||||
trackRecordingManager.processAction(.start)
|
||||
case .active:
|
||||
trackRecordingManager.processAction(.stop)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -268,4 +268,8 @@ final class NavigationControlView: SolidTouchView, MWMTextToSpeechObserver, MapO
|
|||
override var widgetsAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return alternative(iPhone: .bottom, iPad: [])
|
||||
}
|
||||
|
||||
override var trackRecordingButtonAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return .bottom
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,8 @@ final class NavigationStreetNameView: SolidTouchView {
|
|||
override var sideButtonsAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return .top
|
||||
}
|
||||
|
||||
override var trackRecordingButtonAreaAffectDirections: MWMAvailableAreaAffectDirections {
|
||||
return .top
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,4 +87,11 @@
|
|||
return MWMAvailableAreaAffectDirectionsLeft;
|
||||
}
|
||||
|
||||
#pragma mark - AvailableArea / TrackRecordingButtonArea
|
||||
|
||||
- (MWMAvailableAreaAffectDirections)trackRecordingButtonAreaAffectDirections
|
||||
{
|
||||
return MWMAvailableAreaAffectDirectionsRight;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -68,4 +68,11 @@
|
|||
return MWMAvailableAreaAffectDirectionsTop;
|
||||
}
|
||||
|
||||
#pragma mark - AvailableArea / TrackRecordingButtonArea
|
||||
|
||||
- (MWMAvailableAreaAffectDirections)trackRecordingButtonAreaAffectDirections
|
||||
{
|
||||
return MWMAvailableAreaAffectDirectionsTop;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -70,8 +70,9 @@
|
|||
auto const viewWidth = [MapViewController sharedController].mapView.width;
|
||||
auto const rulerOffset =
|
||||
m2::PointF(frame.origin.x * vs, (frame.origin.y + frame.size.height - viewHeight) * vs);
|
||||
auto const kCompassAdditionalYOffset = [TrackRecordingManager.shared isActive] ? 50 : 0;
|
||||
auto const compassOffset =
|
||||
m2::PointF((frame.origin.x + frame.size.width - viewWidth) * vs, frame.origin.y * vs);
|
||||
m2::PointF((frame.origin.x + frame.size.width - viewWidth) * vs, (frame.origin.y + kCompassAdditionalYOffset) * vs);
|
||||
m_skin->ForEach([&](gui::EWidget w, gui::Position const & pos) {
|
||||
m2::PointF pivot = pos.m_pixelPivot;
|
||||
switch (w)
|
||||
|
|
|
@ -119,6 +119,10 @@ class GlobalStyleSheet: IStyleSheet {
|
|||
s.onTintColor = .red
|
||||
}
|
||||
|
||||
theme.add(styleName: "TrackRecordingWidgetButton", from: "BottomTabBarButton") { (s) -> (Void) in
|
||||
s.cornerRadius = 23
|
||||
}
|
||||
|
||||
theme.add(styleName: "BlackOpaqueBackground") { (s) -> (Void) in
|
||||
s.backgroundColor = colors.blackOpaque
|
||||
}
|
||||
|
|
|
@ -475,6 +475,8 @@
|
|||
ED1080A72B791CFE0023F27E /* SocialMediaCollectionViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1080A62B791CFE0023F27E /* SocialMediaCollectionViewHeader.swift */; };
|
||||
ED1263AB2B6F99F900AD99F3 /* UIView+AddSeparator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1263AA2B6F99F900AD99F3 /* UIView+AddSeparator.swift */; };
|
||||
ED1ADA332BC6B1B40029209F /* CarPlayServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1ADA322BC6B1B40029209F /* CarPlayServiceTests.swift */; };
|
||||
ED2E328E2D10500900807A08 /* TrackRecordingButtonArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED46DD922D06F804007CACD6 /* TrackRecordingButtonArea.swift */; };
|
||||
ED2E32912D10501700807A08 /* TrackRecordingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED49D76F2CF0E3A8004AF27E /* TrackRecordingViewController.swift */; };
|
||||
ED3EAC202B03C88100220A4A /* BottomTabBarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED3EAC1F2B03C88100220A4A /* BottomTabBarButton.swift */; };
|
||||
ED43B8BD2C12063500D07BAA /* DocumentPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED43B8BC2C12063500D07BAA /* DocumentPicker.swift */; };
|
||||
ED4DC7772CAEDECC0029B338 /* ProductsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4DC7752CAEDECC0029B338 /* ProductsViewModel.swift */; };
|
||||
|
@ -1406,8 +1408,10 @@
|
|||
ED1ADA322BC6B1B40029209F /* CarPlayServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlayServiceTests.swift; sourceTree = "<group>"; };
|
||||
ED3EAC1F2B03C88100220A4A /* BottomTabBarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomTabBarButton.swift; sourceTree = "<group>"; };
|
||||
ED43B8BC2C12063500D07BAA /* DocumentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPicker.swift; sourceTree = "<group>"; };
|
||||
ED46DD922D06F804007CACD6 /* TrackRecordingButtonArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackRecordingButtonArea.swift; sourceTree = "<group>"; };
|
||||
ED48BBB817C2B1E2003E7E92 /* CircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleView.h; sourceTree = "<group>"; };
|
||||
ED48BBB917C2B1E2003E7E92 /* CircleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleView.m; sourceTree = "<group>"; };
|
||||
ED49D76F2CF0E3A8004AF27E /* TrackRecordingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackRecordingViewController.swift; sourceTree = "<group>"; };
|
||||
ED4DC7732CAEDECC0029B338 /* ProductButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductButton.swift; sourceTree = "<group>"; };
|
||||
ED4DC7742CAEDECC0029B338 /* ProductsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsViewController.swift; sourceTree = "<group>"; };
|
||||
ED4DC7752CAEDECC0029B338 /* ProductsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsViewModel.swift; sourceTree = "<group>"; };
|
||||
|
@ -2508,6 +2512,7 @@
|
|||
34BC72091B0DECAE0012A34B /* MapViewControls */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED49D76F2CF0E3A8004AF27E /* TrackRecordingViewController.swift */,
|
||||
340537621BBED98600D452C6 /* MWMMapViewControlsCommon.h */,
|
||||
34BC72101B0DECAE0012A34B /* MWMMapViewControlsManager.h */,
|
||||
34BC72111B0DECAE0012A34B /* MWMMapViewControlsManager.mm */,
|
||||
|
@ -2566,6 +2571,7 @@
|
|||
34FE5A6D1F18F30F00BCA729 /* TrafficButtonArea.swift */,
|
||||
340708631F2905A500029ECC /* NavigationInfoArea.swift */,
|
||||
9989272F2449DE1500260CE2 /* TabBarArea.swift */,
|
||||
ED46DD922D06F804007CACD6 /* TrackRecordingButtonArea.swift */,
|
||||
);
|
||||
path = AvailableArea;
|
||||
sourceTree = "<group>";
|
||||
|
@ -4361,6 +4367,7 @@
|
|||
340708651F2905A500029ECC /* NavigationInfoArea.swift in Sources */,
|
||||
993DF0CC23F6BD0600AC231A /* ElevationDetailsPresenter.swift in Sources */,
|
||||
34AB666B1FC5AA330078E451 /* TransportTransitCell.swift in Sources */,
|
||||
ED2E32912D10501700807A08 /* TrackRecordingViewController.swift in Sources */,
|
||||
47E8163323B17734008FD836 /* MWMStorage+UI.m in Sources */,
|
||||
993DF11123F6BDB100AC231A /* UILabelRenderer.swift in Sources */,
|
||||
34AB66471FC5AA330078E451 /* RouteManagerTableView.swift in Sources */,
|
||||
|
@ -4565,6 +4572,7 @@
|
|||
995739062355CAC40019AEE7 /* ImageViewCrossDisolve.swift in Sources */,
|
||||
47B9065221C7FA400079C85E /* MWMWebImage.m in Sources */,
|
||||
47A13CAD24BE9AA500027D4F /* DatePickerViewRenderer.swift in Sources */,
|
||||
ED2E328E2D10500900807A08 /* TrackRecordingButtonArea.swift in Sources */,
|
||||
F6E2FE7C1E097BA00083EBEC /* MWMPlacePageOpeningHoursCell.mm in Sources */,
|
||||
340E1EFB1E2F614400CE49BF /* Storyboard.swift in Sources */,
|
||||
34E776331F15FAC2003040B3 /* MWMPlacePageManagerHelper.mm in Sources */,
|
||||
|
|
21
iphone/Maps/UI/AvailableArea/TrackRecordingButtonArea.swift
Normal file
21
iphone/Maps/UI/AvailableArea/TrackRecordingButtonArea.swift
Normal file
|
@ -0,0 +1,21 @@
|
|||
final class TrackRecordingButtonArea: AvailableArea {
|
||||
override func isAreaAffectingView(_ other: UIView) -> Bool {
|
||||
return !other.trackRecordingButtonAreaAffectDirections.isEmpty
|
||||
}
|
||||
|
||||
override func addAffectingView(_ other: UIView) {
|
||||
let ov = other.trackRecordingButtonAreaAffectView
|
||||
let directions = ov.trackRecordingButtonAreaAffectDirections
|
||||
addConstraints(otherView: ov, directions: directions)
|
||||
}
|
||||
|
||||
override func notifyObserver() {
|
||||
TrackRecordingViewController.updateAvailableArea(areaFrame)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
@objc var trackRecordingButtonAreaAffectDirections: MWMAvailableAreaAffectDirections { return [] }
|
||||
|
||||
var trackRecordingButtonAreaAffectView: UIView { return self }
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import UIKit
|
||||
|
||||
final class BottomTabBarButton: MWMButton {
|
||||
class BottomTabBarButton: MWMButton {
|
||||
@objc override func applyTheme() {
|
||||
styleName = "BottomTabBarButton"
|
||||
|
||||
if styleName.isEmpty {
|
||||
styleName = "BottomTabBarButton"
|
||||
}
|
||||
|
||||
for style in StyleManager.shared.getStyle(styleName) where !style.isEmpty && !style.hasExclusion(view: self) {
|
||||
BottomTabBarButtonRenderer.render(self, style: style)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ final class SearchBar: SolidTouchView {
|
|||
|
||||
override var tabBarAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: [], iPad: .left) }
|
||||
|
||||
override var trackRecordingButtonAreaAffectDirections: MWMAvailableAreaAffectDirections { return alternative(iPhone: .top, iPad: .left) }
|
||||
|
||||
@objc var state: SearchBarState = .ready {
|
||||
didSet {
|
||||
if state != oldValue {
|
||||
|
|
|
@ -84,6 +84,9 @@
|
|||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QKu-4A-UgP" customClass="TrafficButtonArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="59" y="0.0" width="814" height="409"/>
|
||||
</view>
|
||||
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yto-Gu-Ugz" userLabel="Track Recording Button Area" customClass="TrackRecordingButtonArea" customModule="Organic_Maps" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="59" width="430" height="839"/>
|
||||
<color key="backgroundColor" red="0.0" green="1" blue="0.0" alpha="0.20000000000000001" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
</subviews>
|
||||
|
@ -179,6 +182,7 @@
|
|||
<constraint firstItem="utd-Jy-pE5" firstAttribute="top" secondItem="xJx-UU-IdV" secondAttribute="top" priority="100" id="BMq-jc-qfO"/>
|
||||
<constraint firstItem="ixC-IZ-Pvs" firstAttribute="top" secondItem="USG-6L-Uhw" secondAttribute="top" id="DSJ-0D-hwO"/>
|
||||
<constraint firstItem="rL1-9E-4b7" firstAttribute="top" secondItem="USG-6L-Uhw" secondAttribute="top" id="E89-WV-ZTh"/>
|
||||
<constraint firstItem="yto-Gu-Ugz" firstAttribute="top" secondItem="utd-Jy-pE5" secondAttribute="top" priority="100" id="FGp-pl-Mgy"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="QKu-4A-UgP" secondAttribute="trailing" id="Fjy-Cy-dHS"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="at1-V1-pzl" secondAttribute="trailing" id="GKG-4Y-2Pq"/>
|
||||
<constraint firstAttribute="trailing" secondItem="aPn-pa-nCx" secondAttribute="trailing" id="GKJ-zm-8xb"/>
|
||||
|
@ -188,12 +192,15 @@
|
|||
<constraint firstAttribute="trailing" secondItem="ixC-IZ-Pvs" secondAttribute="trailing" id="O7f-qU-UN2"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="at1-V1-pzl" secondAttribute="bottom" priority="750" constant="48" id="O8L-nd-nOa"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="FFY-Dy-Wou" secondAttribute="bottom" priority="100" id="OE7-Qb-J0v"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="yto-Gu-Ugz" secondAttribute="bottom" priority="100" id="PBh-hG-PzA"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="awj-9E-eBS" secondAttribute="bottom" id="PFs-sL-oVA"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rL1-9E-4b7" secondAttribute="trailing" id="QdS-Yx-ADV"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="TdT-ia-GP9" secondAttribute="trailing" id="Rsb-fB-8bn"/>
|
||||
<constraint firstItem="jio-3T-E6G" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" constant="-320" id="SAj-bF-qrr"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="xJx-UU-IdV" secondAttribute="bottom" id="SDX-4J-Jz5"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="FFY-Dy-Wou" secondAttribute="bottom" id="TZk-MH-pMV"/>
|
||||
<constraint firstItem="yto-Gu-Ugz" firstAttribute="leading" secondItem="utd-Jy-pE5" secondAttribute="leading" id="TgS-dg-g9B"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="trailing" secondItem="yto-Gu-Ugz" secondAttribute="trailing" id="URB-3l-JiC"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="bottom" secondItem="xJx-UU-IdV" secondAttribute="bottom" priority="100" id="VfU-Zk-8IU"/>
|
||||
<constraint firstItem="rbx-Oj-jeo" firstAttribute="leading" secondItem="jio-3T-E6G" secondAttribute="trailing" constant="20" id="W0l-NG-7lt"/>
|
||||
<constraint firstItem="utd-Jy-pE5" firstAttribute="top" secondItem="QKu-4A-UgP" secondAttribute="top" priority="100" id="X96-y7-5oI"/>
|
||||
|
|
Reference in a new issue