// Copyright 2020-present the Material Components for iOS authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import UIKit import MaterialComponents.MaterialCollections import MaterialComponents.MaterialDialogs import MaterialComponents.MaterialDialogs_Theming import MaterialComponents.MaterialTextControls_FilledTextFields import MaterialComponents.MaterialTextControls_FilledTextFieldsTheming import MaterialComponents.MaterialContainerScheme import MaterialComponents.MaterialTypographyScheme class DialogsAlignmentExampleViewController: MDCCollectionViewController { @objc lazy var containerScheme: MDCContainerScheming = { let scheme = MDCContainerScheme() scheme.colorScheme = MDCSemanticColorScheme(defaults: .material201907) scheme.typographyScheme = MDCTypographyScheme(defaults: .material201902) return scheme }() let kReusableIdentifierItem = "customCell" var menu: [String] = [] var handler: MDCActionHandler = { action in print(action.title ?? "Some Action") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = containerScheme.colorScheme.backgroundColor loadCollectionView(menu: [ "Centered", "Justified Action", "Justified Actions", "Vertical Justified Actions", "Vertical Actions In Reversed Order", "Custom Insets", ]) } func loadCollectionView(menu: [String]) { self.collectionView?.register( MDCCollectionViewTextCell.self, forCellWithReuseIdentifier: kReusableIdentifierItem) self.menu = menu } override func collectionView( _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath ) { guard let alert = alertController(for: indexPath.row) else { return } self.present(alert, animated: true, completion: nil) } private func alertController(for row: Int) -> MDCAlertController? { switch row { case 0: return alertWithCenteredContent() case 1: return alertWithJustifiedAction() case 2: return alertWithJustifiedActions() case 3: return alertWithVerticallyJustifiedActions() case 4: return alertWithVerticalActionsInReverseOrder() case 5: return alertWithCustomInsets() default: print("No row is selected") return nil } } func alertWithCenteredContent() -> MDCAlertController { let alert = createMDCAlertController(title: "Centered Title") let bundle = Bundle(for: DialogsAlignmentExampleViewController.self) alert.titleIcon = UIImage(named: "outline_lock_black_24pt", in: bundle, compatibleWith: nil) alert.titleAlignment = .center alert.titleIconAlignment = .center alert.messageAlignment = .center alert.actionsHorizontalAlignment = .center alert.applyTheme(withScheme: containerScheme) return alert } func alertWithJustifiedAction() -> MDCAlertController { let alert = MDCAlertController( title: "Justified Action", message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ) alert.addAction(MDCAlertAction(title: "Got It", emphasis: .high, handler: handler)) alert.actionsHorizontalAlignment = .justified alert.applyTheme(withScheme: containerScheme) return alert } func alertWithJustifiedActions() -> MDCAlertController { let alert = createMDCAlertController(title: "Justified Actions") alert.actionsHorizontalAlignment = .justified alert.applyTheme(withScheme: containerScheme) return alert } func alertWithVerticallyJustifiedActions() -> MDCAlertController { let alert = MDCAlertController( title: "Vertical Actions", message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ) alert.addAction(MDCAlertAction(title: "Sed do eiusmod", emphasis: .high, handler: handler)) alert.addAction(MDCAlertAction(title: "Tempor incididunt", emphasis: .medium, handler: handler)) alert.actionsHorizontalAlignmentInVerticalLayout = .justified alert.applyTheme(withScheme: containerScheme) return alert } func alertWithVerticalActionsInReverseOrder() -> MDCAlertController { let alert = MDCAlertController( title: "Reversed Vertical Order", message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.") alert.addAction(MDCAlertAction(title: "Sed do eiusmod", handler: handler)) alert.addAction(MDCAlertAction(title: "Tempor incididunt", handler: handler)) alert.actionsHorizontalAlignmentInVerticalLayout = .trailing alert.orderVerticalActionsByEmphasis = true alert.applyTheme(withScheme: containerScheme) return alert } func alertWithCustomInsets() -> MDCAlertController { let alert = MDCAlertController( title: "Custom Insets", message: """ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. """) alert.addAction(MDCAlertAction(title: "Accept", emphasis: .medium, handler: handler)) alert.addAction(MDCAlertAction(title: "Cancel", emphasis: .medium, handler: handler)) alert.actionsHorizontalAlignment = .justified if let alertView = alert.view as? MDCAlertControllerView { alertView.titleInsets = UIEdgeInsets(top: 30, left: 30, bottom: 20, right: 30) alertView.contentInsets = UIEdgeInsets(top: 0, left: 30, bottom: 20, right: 30) alertView.actionsInsets = UIEdgeInsets(top: 8, left: 30, bottom: 30, right: 30) alertView.actionsHorizontalMargin = 16 } alert.applyTheme(withScheme: containerScheme) return alert } private func createMDCAlertController(title: String?) -> MDCAlertController { let alertController = MDCAlertController( title: title, message: """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. """) alertController.addAction(MDCAlertAction(title: "OK", emphasis: .high, handler: handler)) alertController.addAction(MDCAlertAction(title: "Cancel", emphasis: .medium, handler: handler)) return alertController } } // MDCCollectionViewController Data Source extension DialogsAlignmentExampleViewController { override func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } override func collectionView( _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int { return menu.count } override func collectionView( _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath ) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell( withReuseIdentifier: kReusableIdentifierItem, for: indexPath) guard let customCell = cell as? MDCCollectionViewTextCell else { return cell } customCell.isAccessibilityElement = true customCell.accessibilityTraits = .button let cellTitle = menu[indexPath.row] customCell.accessibilityLabel = cellTitle customCell.textLabel?.text = cellTitle return customCell } } // MARK: Catalog by convention extension DialogsAlignmentExampleViewController { @objc class func catalogMetadata() -> [String: Any] { return [ "breadcrumbs": ["Dialogs", "Alignment and Insets"], "primaryDemo": false, "presentable": true, ] } } // MARK: Snapshot Testing by Convention extension DialogsAlignmentExampleViewController { func resetTests() { if presentedViewController != nil { dismiss(animated: false) } } @objc func testCentered() { resetTests() self.present(alertWithCenteredContent(), animated: false, completion: nil) } @objc func testJustifiedAction() { resetTests() self.present(alertWithJustifiedAction(), animated: false, completion: nil) } @objc func testJustifiedActions() { resetTests() self.present(alertWithJustifiedActions(), animated: false, completion: nil) } @objc func testVerticalJustified() { resetTests() self.present(alertWithVerticallyJustifiedActions(), animated: false, completion: nil) } @objc func testReverseVerticalOrder() { resetTests() self.present(alertWithVerticalActionsInReverseOrder(), animated: false, completion: nil) } @objc func testCustomInsets() { resetTests() self.present(alertWithCustomInsets(), animated: false, completion: nil) } }