[ios] Create bookmark category alert.

This commit is contained in:
VladiMihaylenko 2018-03-22 15:09:43 +03:00 committed by Roman Kuznetsov
parent e852f87297
commit cc34cceaae
15 changed files with 488 additions and 18 deletions

View file

@ -42,27 +42,23 @@ final class BMCViewController: MWMViewController {
private func updateCategoryName(category: BMCCategory?) {
let isNewCategory = (category == nil)
let alert = UIAlertController(title: L(isNewCategory ? "bookmarks_create_new_group" : "rename"), message: nil, preferredStyle: .alert)
alertController.presentCreateBookmarkCategoryAlert(withMaxCharacterNum: viewModel.maxCategoryNameLength,
minCharacterNum: viewModel.minCategoryNameLength,
isNewCategory: isNewCategory)
{ [weak viewModel] (name: String!) -> Bool in
guard let model = viewModel else { return false }
if model.checkCategory(name: name) {
if isNewCategory {
model.addCategory(name: name)
} else {
model.renameCategory(category: category!, name: name)
}
alert.addTextField { textField in
textField.placeholder = L("bookmark_set_name")
if let category = category {
textField.text = category.title
return true
}
return false
}
alert.addAction(UIAlertAction(title: L("cancel").capitalized, style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: L(isNewCategory ? "create" : "ok").capitalized, style: .default) { [weak alert, viewModel] _ in
guard let categoryName = alert?.textFields?.first?.text, !categoryName.isEmpty,
let viewModel = viewModel else { return }
if let category = category {
viewModel.renameCategory(category: category, name: categoryName)
} else {
viewModel.addCategory(name: categoryName)
}
})
present(alert, animated: true, completion: nil)
}
private func shareCategory(category: BMCCategory, anchor: UIView) {

View file

@ -1,5 +1,10 @@
final class BMCDefaultViewModel: NSObject {
var view: BMCView!
private enum Const
{
static let minCategoryNameLength: UInt = 0
static let maxCategoryNameLength: UInt = 60
}
private var sections: [BMCSection] = []
private var permissions: [BMCPermission] = []
@ -10,6 +15,9 @@ final class BMCDefaultViewModel: NSObject {
private(set) var isPendingPermission = false
private var isAuthenticated = false
var minCategoryNameLength: UInt = Const.minCategoryNameLength
var maxCategoryNameLength: UInt = Const.maxCategoryNameLength
typealias BM = MWMBookmarksManager
override init() {
@ -147,6 +155,10 @@ extension BMCDefaultViewModel: BMCViewModel {
view.delete(at: IndexPath(row: row, section: section))
}
func checkCategory(name: String) -> Bool {
return BM.checkCategoryName(name)
}
func beginShareCategory(category: BMCCategory) -> BMCShareCategoryStatus {
switch BM.beginShareCategory(category.identifier) {
case .success:

View file

@ -12,6 +12,8 @@ enum BMCShareCategoryStatus {
protocol BMCViewModel: AnyObject {
var view: BMCView! { get set }
var isPendingPermission: Bool { get }
var minCategoryNameLength: UInt { get }
var maxCategoryNameLength: UInt { get }
func numberOfSections() -> Int
func sectionType(section: Int) -> BMCSection
@ -28,6 +30,7 @@ protocol BMCViewModel: AnyObject {
func addCategory(name: String)
func renameCategory(category: BMCCategory, name: String)
func deleteCategory(category: BMCCategory)
func checkCategory(name: String) -> Bool
func beginShareCategory(category: BMCCategory) -> BMCShareCategoryStatus
func endShareCategory(category: BMCCategory)

View file

@ -1,6 +1,7 @@
@interface UIFont (MapsMeFonts)
+ (UIFont *)regular10;
+ (UIFont *)regular11;
+ (UIFont *)regular12;
+ (UIFont *)regular13;
+ (UIFont *)regular14;

View file

@ -6,6 +6,7 @@ NSString * const kLightFontName = @"HelveticaNeue-Light";
@implementation UIFont (MapsMeFonts)
+ (UIFont *)regular10 { return [UIFont systemFontOfSize:10]; }
+ (UIFont *)regular11 { return [UIFont systemFontOfSize:11]; }
+ (UIFont *)regular12 { return [UIFont systemFontOfSize:12]; }
+ (UIFont *)regular13 { return [UIFont systemFontOfSize:13]; }
+ (UIFont *)regular14 { return [UIFont systemFontOfSize:14]; }

View file

@ -44,6 +44,11 @@
- (void)presentSearchNoResultsAlert;
- (void)presentMobileInternetAlertWithBlock:(nonnull MWMVoidBlock)block;
- (void)presentInfoAlert:(nonnull NSString *)title text:(nonnull NSString *)text;
- (void)presentCreateBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max
minCharacterNum:(NSUInteger)min
isNewCategory:(BOOL)isNewCategory
callback:(nonnull MWMCheckStringBlock)callback;
- (void)closeAlert:(nullable MWMVoidBlock)completion;
- (nonnull instancetype)init __attribute__((unavailable("call -initWithViewController: instead!")));

View file

@ -215,6 +215,23 @@ static NSString * const kAlertControllerNibIdentifier = @"MWMAlertViewController
- (void)presentEditorViralAlert { [self displayAlert:[MWMAlert editorViralAlert]]; }
- (void)presentOsmAuthAlert { [self displayAlert:[MWMAlert osmAuthAlert]]; }
- (void)presentCreateBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max
minCharacterNum:(NSUInteger)min
isNewCategory:(BOOL)isNewCategory
callback:(nonnull MWMCheckStringBlock)callback
{
auto alert = static_cast<MWMBCCreateCategoryAlert *>([MWMAlert
createBookmarkCategoryAlertWithMaxCharacterNum:max
minCharacterNum:min
isNewCategory:isNewCategory
callback:callback]);
[self displayAlert:alert];
dispatch_async(dispatch_get_main_queue(), ^{
[alert.textField becomeFirstResponder];
});
}
- (void)displayAlert:(MWMAlert *)alert
{
// TODO(igrechuhin): Remove this check on location manager refactoring.

View file

@ -35,6 +35,10 @@
+ (MWMAlert *)personalInfoWarningAlertWithBlock:(MWMVoidBlock)block;
+ (MWMAlert *)trackWarningAlertWithCancelBlock:(MWMVoidBlock)block;
+ (MWMAlert *)infoAlert:(NSString *)title text:(NSString *)text;
+ (MWMAlert *)createBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max
minCharacterNum:(NSUInteger)min
isNewCategory:(BOOL)isNewCategory
callback:(MWMCheckStringBlock)callback;
- (void)close:(MWMVoidBlock)completion;
- (void)setNeedsCloseAlertAfterEnterBackground;

View file

@ -11,6 +11,8 @@
#import "MWMRateAlert.h"
#import "MWMRoutingDisclaimerAlert.h"
#import "SwiftBridge.h"
@implementation MWMAlert
+ (MWMAlert *)rateAlert { return [MWMRateAlert alert]; }
@ -157,6 +159,17 @@
return [MWMDefaultAlert infoAlert:title text:text];
}
+ (MWMAlert *)createBookmarkCategoryAlertWithMaxCharacterNum:(NSUInteger)max
minCharacterNum:(NSUInteger)min
isNewCategory:(BOOL)isNewCategory
callback:(MWMCheckStringBlock)callback
{
return [MWMBCCreateCategoryAlert alertWithMaxCharachersNum:max
minCharactersNum:min
isNewCategory:isNewCategory
callback:callback];
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
// Should override this method if you want custom relayout after rotation.

View file

@ -0,0 +1,156 @@
@objc(MWMBCCreateCategoryAlert)
final class BCCreateCategoryAlert: MWMAlert {
private enum State {
case valid
case tooFewSymbols
case tooManySymbols
case nameAlreadyExists
}
@IBOutlet private(set) weak var textField: UITextField!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var textFieldContainer: UIView!
@IBOutlet private weak var centerHorizontaly: NSLayoutConstraint!
@IBOutlet private weak var errorLabel: UILabel!
@IBOutlet private weak var charactersCountLabel: UILabel!
@IBOutlet private weak var rightButton: UIButton! {
didSet {
rightButton.setTitleColor(UIColor.blackHintText(), for: .disabled)
}
}
private var maxCharactersNum: UInt?
private var minCharactersNum: UInt?
private var callback: MWMCheckStringBlock?
@objc static func alert(maxCharachersNum: UInt,
minCharactersNum: UInt,
isNewCategory: Bool,
callback: @escaping MWMCheckStringBlock) -> BCCreateCategoryAlert? {
guard let alert = Bundle.main.loadNibNamed(className(), owner: nil, options: nil)?.first
as? BCCreateCategoryAlert else {
assertionFailure()
return nil
}
alert.titleLabel.text = L(isNewCategory ? "bookmarks_create_new_group" : "rename")
let text = L(isNewCategory ? "create" : "ok").capitalized
for s in [.normal, .highlighted, .disabled] as [UIControlState] {
alert.rightButton.setTitle(text, for: s)
}
alert.maxCharactersNum = maxCharachersNum
alert.minCharactersNum = minCharactersNum
alert.callback = callback
alert.process(state: .tooFewSymbols)
alert.formatCharactersCountText()
MWMKeyboard.add(alert)
return alert
}
@IBAction private func leftButtonTap() {
MWMKeyboard.remove(self)
close(nil)
}
@IBAction private func rightButtonTap() {
guard let callback = callback, let text = textField.text else {
assertionFailure()
return
}
if callback(text) {
MWMKeyboard.remove(self)
close(nil)
} else {
process(state: .nameAlreadyExists)
}
}
@IBAction private func editingChanged(sender: UITextField) {
formatCharactersCountText()
process(state: checkState())
}
private func checkState() -> State {
let count = textField.text!.count
if count <= minCharactersNum! {
return .tooFewSymbols
}
if count > maxCharactersNum! {
return .tooManySymbols
}
return .valid
}
private func process(state: State) {
let color: UIColor
switch state {
case .valid:
color = UIColor.blackHintText()
rightButton.isEnabled = true
errorLabel.isHidden = true
case .tooFewSymbols:
color = UIColor.blackHintText()
errorLabel.isHidden = true
rightButton.isEnabled = false
case .tooManySymbols:
color = UIColor.buttonRed()
errorLabel.isHidden = false
errorLabel.text = L("bookmarks_error_title_list_name_too_long")
rightButton.isEnabled = false
case .nameAlreadyExists:
color = UIColor.buttonRed()
errorLabel.isHidden = false
errorLabel.text = L("bookmarks_error_title_list_name_already_taken")
rightButton.isEnabled = false
}
charactersCountLabel.textColor = color
textFieldContainer.layer.borderColor = color.cgColor
}
private func formatCharactersCountText() {
let count = textField.text!.count
charactersCountLabel.text = String(count) + " / " + String(maxCharactersNum!)
}
}
extension BCCreateCategoryAlert: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if checkState() == .valid {
rightButtonTap()
}
return true
}
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let str = textField.text as NSString?
let newStr = str?.replacingCharacters(in: range, with: string)
guard let count = newStr?.count else {
return true
}
if count > maxCharactersNum! + 1 {
return false
}
return true
}
}
extension BCCreateCategoryAlert: MWMKeyboardObserver {
func onKeyboardAnimation() {
centerHorizontaly.constant -= MWMKeyboard.keyboardHeight() / 2
layoutIfNeeded()
}
func onKeyboardWillAnimate() {
setNeedsLayout()
}
}

View file

@ -0,0 +1,239 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<customFonts key="customFonts">
<array key="HelveticaNeue.ttc">
<string>HelveticaNeue</string>
<string>HelveticaNeue-Medium</string>
</array>
</customFonts>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="QQB-Ml-wwB" customClass="MWMBCCreateCategoryAlert" propertyAccessControl="none">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QG2-Qb-EKf" userLabel="ContainerView">
<rect key="frame" x="47.5" y="248" width="280" height="171.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4T3-au-6h5" userLabel="Title">
<rect key="frame" x="20" y="20" width="240" height="21.5"/>
<constraints>
<constraint firstAttribute="width" constant="240" id="4gN-jJ-fkn"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="20" id="dpW-YS-s4x"/>
</constraints>
<fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackPrimaryText"/>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium18"/>
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="bookmarks_create_new_group"/>
</userDefinedRuntimeAttributes>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="otE-Ct-TPM">
<rect key="frame" x="16" y="61.5" width="248" height="28"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="xlp-ke-FxI">
<rect key="frame" x="4" y="0.0" width="240" height="28"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="240" id="T3H-0E-q2e"/>
</constraints>
<edgeInsets key="layoutMargins" top="4" left="4" bottom="4" right="4"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences" autocorrectionType="no" returnKeyType="done" textContentType="name"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular14"/>
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="blackPrimaryText"/>
<userDefinedRuntimeAttribute type="string" keyPath="localizedPlaceholder" value="bookmark_set_name"/>
<userDefinedRuntimeAttribute type="string" keyPath="_placeholderLabel.colorName" value="blackHintText"/>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="editingChangedWithSender:" destination="QQB-Ml-wwB" eventType="editingChanged" id="Rab-rj-UaD"/>
<outlet property="delegate" destination="QQB-Ml-wwB" id="7Hk-7k-Biw"/>
</connections>
</textField>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="28" id="497-yd-ibe"/>
<constraint firstItem="xlp-ke-FxI" firstAttribute="centerY" secondItem="otE-Ct-TPM" secondAttribute="centerY" id="LK1-93-zgY"/>
<constraint firstAttribute="width" constant="248" id="hLe-SE-FJ2"/>
<constraint firstItem="xlp-ke-FxI" firstAttribute="centerX" secondItem="otE-Ct-TPM" secondAttribute="centerX" id="sOC-II-DCo"/>
<constraint firstItem="xlp-ke-FxI" firstAttribute="height" secondItem="otE-Ct-TPM" secondAttribute="height" id="tj3-TS-dmp"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="layer.borderUIColor">
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.12" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
<real key="value" value="0.5"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="white"/>
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uxx-Di-f1Q" userLabel="hDivider">
<rect key="frame" x="0.0" y="127.5" width="280" height="1"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.12" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="9Ur-cw-cWk"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="blackDividers"/>
</userDefinedRuntimeAttributes>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Wxi-5V-caq" userLabel="left">
<rect key="frame" x="0.0" y="127.5" width="140" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="140" id="PcO-3k-jAQ"/>
<constraint firstAttribute="height" constant="44" id="sIn-W3-LqB"/>
</constraints>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="17"/>
<state key="normal" title="left">
<color key="titleColor" red="0.090196078430000007" green="0.61960784310000006" blue="0.30196078430000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<state key="highlighted" backgroundImage="dialog_btn_press"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="cancel"/>
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="linkBlue"/>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium17"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="leftButtonTap" destination="QQB-Ml-wwB" eventType="touchUpInside" id="q1X-dI-dSs"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eg6-8K-8yh" userLabel="right">
<rect key="frame" x="140" y="127.5" width="140" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="Pk8-S5-m8D"/>
<constraint firstAttribute="width" constant="140" id="m9E-k8-sQh"/>
</constraints>
<fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="17"/>
<state key="normal" title="right">
<color key="titleColor" red="0.090196078430000007" green="0.61960784310000006" blue="0.30196078430000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<state key="highlighted" backgroundImage="dialog_btn_press"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="localizedText" value="create"/>
<userDefinedRuntimeAttribute type="string" keyPath="textColorName" value="linkBlue"/>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="medium17"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="rightButtonTap" destination="QQB-Ml-wwB" eventType="touchUpInside" id="HT2-dB-W2f"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QQD-2O-DHw" userLabel="vDivider">
<rect key="frame" x="139" y="127.5" width="1" height="44"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.12" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="1" id="Lhw-ff-5Vq"/>
<constraint firstAttribute="height" constant="44" id="eaZ-L1-nnD"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="blackDividers"/>
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This name is too long" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dX9-2y-ZEd" userLabel="Error label">
<rect key="frame" x="16" y="95.5" width="112" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="W4K-74-Pug"/>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="198" id="uYL-oU-tYf"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular11"/>
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="buttonRed"/>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="251" text="69 / 60" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WKj-KX-xnU" userLabel="Count label">
<rect key="frame" x="225.5" y="95.5" width="38.5" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="aJd-wn-gwl"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="fontName" value="regular11"/>
<userDefinedRuntimeAttribute type="string" keyPath="colorName" value="buttonRed"/>
</userDefinedRuntimeAttributes>
</label>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="4T3-au-6h5" firstAttribute="top" secondItem="QG2-Qb-EKf" secondAttribute="top" constant="20" id="2l5-Sp-9hA"/>
<constraint firstItem="dX9-2y-ZEd" firstAttribute="top" secondItem="otE-Ct-TPM" secondAttribute="bottom" constant="6" id="3N9-5v-z4Y"/>
<constraint firstAttribute="bottom" secondItem="Wxi-5V-caq" secondAttribute="bottom" id="3Ze-v3-100"/>
<constraint firstAttribute="trailing" secondItem="eg6-8K-8yh" secondAttribute="trailing" id="6oa-ch-DMu"/>
<constraint firstItem="Wxi-5V-caq" firstAttribute="leading" secondItem="QG2-Qb-EKf" secondAttribute="leading" id="6v3-kv-oqt"/>
<constraint firstItem="uxx-Di-f1Q" firstAttribute="top" secondItem="dX9-2y-ZEd" secondAttribute="bottom" constant="12" id="7Bf-UJ-7mU"/>
<constraint firstItem="uxx-Di-f1Q" firstAttribute="centerX" secondItem="QG2-Qb-EKf" secondAttribute="centerX" id="CSk-xb-Fd3"/>
<constraint firstAttribute="width" constant="280" id="CwP-uI-Ukp"/>
<constraint firstItem="uxx-Di-f1Q" firstAttribute="width" secondItem="QG2-Qb-EKf" secondAttribute="width" id="Fcb-Hq-n6a"/>
<constraint firstItem="otE-Ct-TPM" firstAttribute="top" secondItem="4T3-au-6h5" secondAttribute="bottom" constant="20" id="NAI-NR-TFE"/>
<constraint firstItem="otE-Ct-TPM" firstAttribute="centerX" secondItem="QG2-Qb-EKf" secondAttribute="centerX" id="Y2k-u1-PgF"/>
<constraint firstItem="Wxi-5V-caq" firstAttribute="top" secondItem="uxx-Di-f1Q" secondAttribute="bottom" constant="-1" id="Yo8-tt-8Q6"/>
<constraint firstAttribute="trailing" secondItem="WKj-KX-xnU" secondAttribute="trailing" constant="16" id="aRt-r1-EwI"/>
<constraint firstItem="4T3-au-6h5" firstAttribute="centerX" secondItem="QG2-Qb-EKf" secondAttribute="centerX" id="cTf-xg-SpW"/>
<constraint firstItem="dX9-2y-ZEd" firstAttribute="leading" secondItem="QG2-Qb-EKf" secondAttribute="leading" constant="16" id="gyf-Hq-FLl"/>
<constraint firstItem="QQD-2O-DHw" firstAttribute="centerX" secondItem="QG2-Qb-EKf" secondAttribute="centerX" id="sUU-uz-fhn"/>
<constraint firstAttribute="bottom" secondItem="QQD-2O-DHw" secondAttribute="bottom" id="vgE-JK-Ong"/>
<constraint firstAttribute="bottom" secondItem="eg6-8K-8yh" secondAttribute="bottom" id="vzg-UL-heQ"/>
<constraint firstItem="WKj-KX-xnU" firstAttribute="top" secondItem="otE-Ct-TPM" secondAttribute="bottom" constant="6" id="zK8-7y-xuI"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="size" keyPath="layer.shadowOffset">
<size key="value" width="0.0" height="3"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="layer.shadowUIColor">
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.22" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.shadowRadius">
<integer key="value" value="6"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="12"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.shadowOpacity">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="string" keyPath="backgroundColorName" value="alertBackground"/>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="QG2-Qb-EKf" firstAttribute="centerY" secondItem="QQB-Ml-wwB" secondAttribute="centerY" id="od7-2i-rqy"/>
<constraint firstItem="QG2-Qb-EKf" firstAttribute="centerX" secondItem="QQB-Ml-wwB" secondAttribute="centerX" id="zjO-HS-7Up"/>
</constraints>
<viewLayoutGuide key="safeArea" id="oQA-N9-AkF"/>
<connections>
<outlet property="centerHorizontaly" destination="od7-2i-rqy" id="lVF-DA-PUg"/>
<outlet property="charactersCountLabel" destination="WKj-KX-xnU" id="X0L-zL-ZcF"/>
<outlet property="errorLabel" destination="dX9-2y-ZEd" id="XLx-WJ-h4h"/>
<outlet property="rightButton" destination="eg6-8K-8yh" id="YGF-Zh-u1y"/>
<outlet property="textField" destination="xlp-ke-FxI" id="pBV-Ne-ekt"/>
<outlet property="textFieldContainer" destination="otE-Ct-TPM" id="Nf8-ly-qdn"/>
<outlet property="titleLabel" destination="4T3-au-6h5" id="ye3-HE-xqN"/>
</connections>
<point key="canvasLocation" x="304.5" y="171.5"/>
</view>
</objects>
<resources>
<image name="dialog_btn_press" width="280" height="44"/>
</resources>
</document>

View file

@ -1,6 +1,7 @@
typedef void (^MWMVoidBlock)(void);
typedef void (^MWMStringBlock)(NSString *);
typedef void (^MWMURLBlock)(NSURL *);
typedef BOOL (^MWMCheckStringBlock)(NSString *);
typedef NS_ENUM(NSUInteger, MWMDayTime) { MWMDayTimeDay, MWMDayTimeNight };

View file

@ -22,6 +22,7 @@
+ (void)deleteCategory:(MWMMarkGroupID)groupId;
+ (void)deleteBookmark:(MWMMarkID)bookmarkId;
+ (BOOL)checkCategoryName:(NSString *)name;
+ (MWMBookmarksShareStatus)beginShareCategory:(MWMMarkGroupID)groupId;
+ (NSURL *)shareCategoryURL;

View file

@ -183,6 +183,11 @@ using TLoopBlock = void (^)(Observer observer);
}];
}
+ (BOOL)checkCategoryName:(NSString *)name
{
return !GetFramework().GetBookmarkManager().IsUsedCategoryName(name.UTF8String);
}
+ (MWMBookmarksShareStatus)beginShareCategory:(MWMMarkGroupID)groupId
{
auto const sharingResult = GetFramework().GetBookmarkManager().BeginSharing(groupId);

View file

@ -512,6 +512,8 @@
F6BD1D211CA412920047B8E8 /* MWMOsmAuthAlert.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6BD1D1F1CA412920047B8E8 /* MWMOsmAuthAlert.mm */; };
F6BD1D241CA412E40047B8E8 /* MWMOsmAuthAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6BD1D221CA412E30047B8E8 /* MWMOsmAuthAlert.xib */; };
F6C16A671F9626B2000FE296 /* ReviewsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3430291B1F87BC3000D0A07C /* ReviewsViewController.xib */; };
F6D67CDC2062B9C00032FD38 /* BCCreateCategoryAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D67CDB2062B9C00032FD38 /* BCCreateCategoryAlert.swift */; };
F6D67CDE2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6D67CDD2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib */; };
F6E2FD501E097BA00083EBEC /* MWMMapDownloaderAdsTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FBFF1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.mm */; };
F6E2FD531E097BA00083EBEC /* MWMMapDownloaderAdsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F6E2FC001E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.xib */; };
F6E2FD561E097BA00083EBEC /* MWMMapDownloaderButtonTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6E2FC021E097B9F0083EBEC /* MWMMapDownloaderButtonTableViewCell.mm */; };
@ -1433,6 +1435,8 @@
F6BD1D1E1CA412920047B8E8 /* MWMOsmAuthAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMOsmAuthAlert.h; sourceTree = "<group>"; };
F6BD1D1F1CA412920047B8E8 /* MWMOsmAuthAlert.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MWMOsmAuthAlert.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
F6BD1D221CA412E30047B8E8 /* MWMOsmAuthAlert.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMOsmAuthAlert.xib; sourceTree = "<group>"; };
F6D67CDB2062B9C00032FD38 /* BCCreateCategoryAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BCCreateCategoryAlert.swift; sourceTree = "<group>"; };
F6D67CDD2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MWMBCCreateCategoryAlert.xib; sourceTree = "<group>"; };
F6DF5F321CD1136800A87154 /* LocaleTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocaleTranslator.h; sourceTree = "<group>"; };
F6E2FBFE1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapDownloaderAdsTableViewCell.h; sourceTree = "<group>"; };
F6E2FBFF1E097B9F0083EBEC /* MWMMapDownloaderAdsTableViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapDownloaderAdsTableViewCell.mm; sourceTree = "<group>"; };
@ -3054,6 +3058,7 @@
F64F195F1AB8125C006EAF7E /* CustomAlert */ = {
isa = PBXGroup;
children = (
F6D67CDA2062B9810032FD38 /* CreateBookmarkCategory */,
349B92691DF0516C007779DD /* Toast */,
349A137E1DEC138C00C7DB60 /* MobileInternetAlert */,
3462258B1DDC5D76001E8752 /* SearchAlert */,
@ -3241,6 +3246,15 @@
name = AuthAlert;
sourceTree = "<group>";
};
F6D67CDA2062B9810032FD38 /* CreateBookmarkCategory */ = {
isa = PBXGroup;
children = (
F6D67CDB2062B9C00032FD38 /* BCCreateCategoryAlert.swift */,
F6D67CDD2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib */,
);
path = CreateBookmarkCategory;
sourceTree = "<group>";
};
F6E2FBFB1E097B9F0083EBEC /* UI */ = {
isa = PBXGroup;
children = (
@ -4190,6 +4204,7 @@
F6E2FF421E097BA00083EBEC /* MWMSearchTableViewController.xib in Resources */,
34AB66681FC5AA330078E451 /* TransportTransitPedestrian.xib in Resources */,
F6E2FEEE1E097BA00083EBEC /* MWMSearchView.xib in Resources */,
F6D67CDE2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib in Resources */,
344532511F714FD70059FBCC /* UGCAddReviewController.xib in Resources */,
3490D2E31CE9DD2500D0B838 /* MWMSideButtonsView.xib in Resources */,
346DB82B1E5C4F6700E3123E /* GalleryCell.xib in Resources */,
@ -4634,6 +4649,7 @@
3430291D1F87BF4400D0A07C /* ReviewsViewController.swift in Sources */,
F6E2FE731E097BA00083EBEC /* MWMOpeningHours.mm in Sources */,
3404F4842028908C0090E401 /* AddSetTableViewCell.mm in Sources */,
F6D67CDC2062B9C00032FD38 /* BCCreateCategoryAlert.swift in Sources */,
F6E2FF601E097BA00083EBEC /* MWMSettingsViewController.mm in Sources */,
F6E2FE2B1E097BA00083EBEC /* MWMStreetEditorEditTableViewCell.mm in Sources */,
34AB66891FC5AA330078E451 /* NavigationControlView.swift in Sources */,