diff --git a/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/Contents.json b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/Contents.json new file mode 100644 index 0000000000..b33f9cb47f --- /dev/null +++ b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "img_welcome.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "img_welcome@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "img_welcome@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome.png b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome.png new file mode 100644 index 0000000000..59a5536ae5 Binary files /dev/null and b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome.png differ diff --git a/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome@2x.png b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome@2x.png new file mode 100644 index 0000000000..4b158b463c Binary files /dev/null and b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome@2x.png differ diff --git a/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome@3x.png b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome@3x.png new file mode 100644 index 0000000000..33050bc6a7 Binary files /dev/null and b/iphone/Maps/Images.xcassets/Welcome/img_welcome.imageset/img_welcome@3x.png differ diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index cf6790bd43..bc5318d3d5 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -348,6 +348,7 @@ 4767CDA620AB1F6200BD8166 /* LeftAlignedIconButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4767CDA520AB1F6200BD8166 /* LeftAlignedIconButton.swift */; }; 4767CDA820AB401000BD8166 /* LinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4767CDA720AB401000BD8166 /* LinkTextView.swift */; }; 4767CDC120B477BA00BD8166 /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4767CDC020B477BA00BD8166 /* WelcomeViewController.swift */; }; + 47800D1D20BEEE2E00072F42 /* TermsOfUseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47800D1C20BEEE2E00072F42 /* TermsOfUseController.swift */; }; 4A300ED51C6DCFD400140018 /* countries-strings in Resources */ = {isa = PBXBuildFile; fileRef = 4A300ED31C6DCFD400140018 /* countries-strings */; }; 56C74C391C74A3BC00B71B9F /* MWMInputEmailValidator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA62F1C2D58F300FE1BEC /* MWMInputEmailValidator.mm */; }; 56EE14D11FE804550036F20C /* libtransit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56EE14D21FE804550036F20C /* libtransit.a */; }; @@ -1278,6 +1279,7 @@ 4767CDA520AB1F6200BD8166 /* LeftAlignedIconButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftAlignedIconButton.swift; sourceTree = ""; }; 4767CDA720AB401000BD8166 /* LinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = ""; }; 4767CDC020B477BA00BD8166 /* WelcomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewController.swift; sourceTree = ""; }; + 47800D1C20BEEE2E00072F42 /* TermsOfUseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfUseController.swift; sourceTree = ""; }; 4A00DBDE1AB704C400113624 /* drules_proto_dark.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = drules_proto_dark.bin; path = ../../data/drules_proto_dark.bin; sourceTree = ""; }; 4A23D1561B8B4DD700D4EB6F /* drules_proto_clear.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = drules_proto_clear.bin; path = ../../data/drules_proto_clear.bin; sourceTree = ""; }; 4A23D1571B8B4DD700D4EB6F /* resources-6plus_clear */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-6plus_clear"; path = "../../data/resources-6plus_clear"; sourceTree = ""; }; @@ -2665,6 +2667,7 @@ 34D4FA611E26572D003F53EF /* FirstLaunchController.swift */, 34D4FA651E265749003F53EF /* WhatsNewController.swift */, 4767CDC020B477BA00BD8166 /* WelcomeViewController.swift */, + 47800D1C20BEEE2E00072F42 /* TermsOfUseController.swift */, ); path = Welcome; sourceTree = ""; @@ -4714,6 +4717,7 @@ F6E2FF031E097BA00083EBEC /* MWMSearchHistoryClearCell.mm in Sources */, 340475091E08199E00C92850 /* MWMMyTarget.mm in Sources */, 340416501E7C086000E2B6D6 /* PhotoViewController.swift in Sources */, + 47800D1D20BEEE2E00072F42 /* TermsOfUseController.swift in Sources */, 674A7E301C0DB10B003D48E1 /* MWMMapWidgets.mm in Sources */, 34AB66291FC5AA330078E451 /* RouteManagerViewController.swift in Sources */, 3404754D1E081A4600C92850 /* MWMKeyboard.mm in Sources */, diff --git a/iphone/Maps/UI/Storyboard/Welcome.storyboard b/iphone/Maps/UI/Storyboard/Welcome.storyboard index b66c768858..d1051ef787 100644 --- a/iphone/Maps/UI/Storyboard/Welcome.storyboard +++ b/iphone/Maps/UI/Storyboard/Welcome.storyboard @@ -293,7 +293,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iphone/Maps/UI/Welcome/TermsOfUseController.swift b/iphone/Maps/UI/Welcome/TermsOfUseController.swift new file mode 100644 index 0000000000..1c3aa62bc4 --- /dev/null +++ b/iphone/Maps/UI/Welcome/TermsOfUseController.swift @@ -0,0 +1,100 @@ +import SafariServices + +class TermsOfUseController: WelcomeViewController { + + private enum UserDefaultsKeys { + static let needTermsKey = "TermsOfUseController_needTerms" + static let ppLinkKey = "TermsOfUseController_ppLink" + static let tosLinkKey = "TermsOfUseController_tosLink" + static let acceptTimeKey = "TermsOfUseController_acceptTime" + } + + static var needTerms: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.needTermsKey) + } + set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.needTermsKey) + } + } + + static func controller() -> TermsOfUseController { + let sb = UIStoryboard.instance(.welcome) + let vc = sb.instantiateViewController(withIdentifier: toString(self)) as! TermsOfUseController + return vc + } + + let privacyPolicyLink = MWMAuthorizationViewModel.privacyPolicyLink() + let termsOfUseLink = MWMAuthorizationViewModel.termsOfUseLink() + + @IBOutlet weak var alertAdditionalText: UILabel! + + @IBOutlet private weak var privacyPolicyTextView: UITextView! { + didSet { + let htmlString = String(coreFormat: L("sign_agree_pp_gdpr"), arguments: [privacyPolicyLink]) + let attributes: [NSAttributedStringKey : Any] = [NSAttributedStringKey.font: UIFont.regular16(), + NSAttributedStringKey.foregroundColor: UIColor.blackPrimaryText()] + privacyPolicyTextView.attributedText = NSAttributedString.string(withHtml: htmlString, + defaultAttributes: attributes) + privacyPolicyTextView.delegate = self + } + } + + @IBOutlet private weak var termsOfUseTextView: UITextView! { + didSet { + let htmlString = String(coreFormat: L("sign_agree_tof_gdpr"), arguments: [termsOfUseLink]) + let attributes: [NSAttributedStringKey : Any] = [NSAttributedStringKey.font: UIFont.regular16(), + NSAttributedStringKey.foregroundColor: UIColor.blackPrimaryText()] + termsOfUseTextView.attributedText = NSAttributedString.string(withHtml: htmlString, + defaultAttributes: attributes) + termsOfUseTextView.delegate = self + } + } + + @IBOutlet private weak var privacyPolicyCheck: Checkmark! { + didSet { + privacyPolicyCheck.offTintColor = .blackHintText() + privacyPolicyCheck.onTintColor = .linkBlue() + } + } + + @IBOutlet private weak var termsOfUseCheck: Checkmark! { + didSet { + termsOfUseCheck.offTintColor = .blackHintText() + termsOfUseCheck.onTintColor = .linkBlue() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + image.image = #imageLiteral(resourceName: "img_welcome") + alertTitle.text = L("onboarding_welcome_title") + alertText.text = L("onboarding_welcome_first_subtitle") + alertAdditionalText.text = L("sign_message_gdpr") + nextPageButton.setTitle(L("whats_new_next_button"), for: .normal) + + Statistics.logEvent("OnStart_MapsMeConsent_shown") + } + + @IBAction func onCheck(_ sender: Checkmark) { + nextPageButton.isEnabled = privacyPolicyCheck.isChecked && termsOfUseCheck.isChecked; + } + + override func nextPage() { + TermsOfUseController.needTerms = false + Statistics.logEvent("OnStart_MapsMeConsent_accepted") + UserDefaults.standard.set(privacyPolicyLink, forKey: UserDefaultsKeys.ppLinkKey) + UserDefaults.standard.set(termsOfUseLink, forKey: UserDefaultsKeys.tosLinkKey) + UserDefaults.standard.set(Date(), forKey: UserDefaultsKeys.acceptTimeKey) + super.nextPage() + } +} + +extension TermsOfUseController: UITextViewDelegate { + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { + let safari = SFSafariViewController(url: URL) + present(safari, animated: true, completion: nil) + return false; + } +} diff --git a/iphone/Maps/UI/Welcome/WelcomePageController.swift b/iphone/Maps/UI/Welcome/WelcomePageController.swift index 88f79363e0..8a328dd43c 100644 --- a/iphone/Maps/UI/Welcome/WelcomePageController.swift +++ b/iphone/Maps/UI/Welcome/WelcomePageController.swift @@ -34,19 +34,33 @@ final class WelcomePageController: UIPageViewController { } @objc static func controller(parent: WelcomePageControllerProtocol) -> WelcomePageController? { - if (!WelcomeViewController.shouldShowWelcome) { return nil } - guard let welcomeControllers = WelcomeViewController.controllers(firstSession: Alohalytics.isFirstSession()) - else { return nil } - - let vc = WelcomePageController(transitionStyle: welcomeControllers.count > 1 ? .scroll : .pageCurl, + var controllersToShow: [WelcomeViewController] = [] + + if TermsOfUseController.needTerms { + controllersToShow.append(TermsOfUseController.controller()) + controllersToShow.append(contentsOf: FirstLaunchController.controllers()) + } else { + if Alohalytics.isFirstSession() { + TermsOfUseController.needTerms = true + controllersToShow.append(TermsOfUseController.controller()) + controllersToShow.append(contentsOf: FirstLaunchController.controllers()) + } else { + if (WhatsNewController.shouldShowWhatsNew) { + controllersToShow.append(contentsOf: WhatsNewController.controllers()) + } + } + } + + if controllersToShow.count == 0 { return nil } + + let vc = WelcomePageController(transitionStyle: controllersToShow.count > 1 ? .scroll : .pageCurl, navigationOrientation: .horizontal, options: [:]) vc.parentController = parent - vc.dataSource = vc - welcomeControllers.forEach { (controller) in + controllersToShow.forEach { (controller) in controller.delegate = vc } - vc.controllers = welcomeControllers + vc.controllers = controllersToShow vc.show() return vc } @@ -64,6 +78,7 @@ final class WelcomePageController: UIPageViewController { view.clipsToBounds = true } currentController = controllers.first + WhatsNewController.shouldShowWhatsNew = false } func nextPage() { @@ -75,7 +90,6 @@ final class WelcomePageController: UIPageViewController { } func close() { - WelcomeViewController.shouldShowWelcome = false if let controller = currentController as? WelcomeViewController { Statistics.logEvent(kStatEventName(kStatWhatsNew, type(of: controller).key), withParameters: [kStatAction: kStatClose]) diff --git a/iphone/Maps/UI/Welcome/WelcomeViewController.swift b/iphone/Maps/UI/Welcome/WelcomeViewController.swift index 1d75762407..28f0077697 100644 --- a/iphone/Maps/UI/Welcome/WelcomeViewController.swift +++ b/iphone/Maps/UI/Welcome/WelcomeViewController.swift @@ -23,15 +23,6 @@ class WelcomeViewController: MWMViewController { class var key: String { return "" } - static var shouldShowWelcome: Bool { - get { - return !UserDefaults.standard.bool(forKey: WhatsNewController.key) - } - set { - UserDefaults.standard.set(!newValue, forKey: WhatsNewController.key) - } - } - static func controllers(firstSession: Bool) -> [WelcomeViewController]? { return firstSession ? FirstLaunchController.controllers() : WhatsNewController.controllers() } diff --git a/iphone/Maps/UI/Welcome/WhatsNewController.swift b/iphone/Maps/UI/Welcome/WhatsNewController.swift index db7a8a9683..7d32d6256c 100644 --- a/iphone/Maps/UI/Welcome/WhatsNewController.swift +++ b/iphone/Maps/UI/Welcome/WhatsNewController.swift @@ -23,6 +23,15 @@ final class WhatsNewController: WelcomeViewController { override class var key: String { return welcomeConfigs.reduce("\(self)", { return "\($0)_\($1.title)" }) } + static var shouldShowWhatsNew: Bool { + get { + return !UserDefaults.standard.bool(forKey: key) + } + set { + UserDefaults.standard.set(!newValue, forKey: key) + } + } + static func controllers() -> [WelcomeViewController] { var result = [WelcomeViewController]() let sb = UIStoryboard.instance(.welcome)