diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 9bf6c177a..64537ca0b 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -449,6 +449,7 @@ 4C20B2B920CA10DE001BAC90 /* ConversationSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */; }; 4C23A5F2215C4ADE00534937 /* SheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C23A5F1215C4ADE00534937 /* SheetViewController.swift */; }; 4C2F454F214C00E1004871FF /* AvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */; }; + 4C3E245C21F29FCE000AE092 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5F792211E1F06008C2708 /* Toast.swift */; }; 4C3EF7FD2107DDEE0007EBF7 /* ParamParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */; }; 4C3EF802210918740007EBF7 /* SSKProtoEnvelopeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EF801210918740007EBF7 /* SSKProtoEnvelopeTest.swift */; }; 4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */; }; @@ -465,7 +466,6 @@ 4C9CA25D217E676900607C63 /* ZXingObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C9CA25C217E676900607C63 /* ZXingObjC.framework */; }; 4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA46F4B219CCC630038ABDE /* CaptionView.swift */; }; 4CA46F4D219CFDAA0038ABDE /* GalleryRailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA46F49219C78050038ABDE /* GalleryRailView.swift */; }; - 4CA5F793211E1F06008C2708 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5F792211E1F06008C2708 /* Toast.swift */; }; 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; }; 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; }; 4CB93DC22180FF07004B9764 /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB93DC12180FF07004B9764 /* ProximityMonitoringManager.swift */; }; @@ -1745,6 +1745,7 @@ 34AC09FD211B39E700997B47 /* TappableView.swift */, 34AC0A0D211B39EA00997B47 /* ThreadViewHelper.h */, 34AC0A0B211B39EA00997B47 /* ThreadViewHelper.m */, + 4CA5F792211E1F06008C2708 /* Toast.swift */, 34AC0A04211B39E800997B47 /* VideoPlayerView.swift */, ); path = Views; @@ -2348,7 +2349,6 @@ 45A6DAD51EBBF85500893231 /* ReminderView.swift */, 450D19111F85236600970622 /* RemoteVideoView.h */, 450D19121F85236600970622 /* RemoteVideoView.m */, - 4CA5F792211E1F06008C2708 /* Toast.swift */, 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */, 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */, 4CA46F4B219CCC630038ABDE /* CaptionView.swift */, @@ -3388,6 +3388,7 @@ 4C618199219DF03A009BD6B5 /* OWSButton.swift in Sources */, 4598198F204E2F28009414F2 /* OWS108CallLoggingPreference.m in Sources */, 34AC09F3211B39B100997B47 /* NewNonContactConversationViewController.m in Sources */, + 4C3E245C21F29FCE000AE092 /* Toast.swift in Sources */, 34AC09FA211B39B100997B47 /* SharingThreadPickerViewController.m in Sources */, 45F59A082028E4FB00E8D2B0 /* OWSAudioSession.swift in Sources */, 34612A071FD7238600532771 /* OWSSyncManager.m in Sources */, @@ -3565,7 +3566,6 @@ 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */, 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */, 45DDA6242090CEB500DE97F8 /* ConversationHeaderView.swift in Sources */, - 4CA5F793211E1F06008C2708 /* Toast.swift in Sources */, 3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */, 45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */, 3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */, diff --git a/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift b/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift index 32b414fd6..b2371bbe6 100644 --- a/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift +++ b/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift @@ -389,6 +389,27 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat } } + func showTooManySelectedToast() { + Logger.info("") + + guard let collectionView = collectionView else { + owsFailDebug("collectionView was unexpectedly nil") + return + } + + let toastFormat = NSLocalizedString("IMAGE_PICKER_CAN_SELECT_NO_MORE_TOAST_FORMAT", + comment: "Momentarily shown to the user when attempting to select more images than is allowed. Embeds {{max number of items}} that can be shared.") + + let toastText = String(format: toastFormat, NSNumber(value: SignalAttachment.maxAttachmentsAllowed)) + + let toastController = ToastController(text: toastText) + + let kToastInset: CGFloat = 10 + let bottomInset = kToastInset + collectionView.contentInset.bottom + view.layoutMargins.bottom + + toastController.presentToastView(fromBottomOfView: view, inset: bottomInset) + } + // MARK: - PhotoLibraryDelegate func photoLibraryDidChange(_ photoLibrary: PhotoLibrary) { @@ -504,7 +525,12 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat return true } - return indexPathsForSelectedItems.count < SignalAttachment.maxAttachmentsAllowed + if (indexPathsForSelectedItems.count < SignalAttachment.maxAttachmentsAllowed) { + return true + } else { + showTooManySelectedToast() + return false + } } override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index fc1c1050b..fd8dc77bf 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1086,6 +1086,9 @@ /* Label for crop button in image editor. */ "IMAGE_EDITOR_CROP_BUTTON" = "Crop"; +/* Momentarily shown to the user when attempting to select more images than is allowed. */ +"IMAGE_PICKER_CAN_SELECT_NO_MORE_TOAST_FORMAT" = "You can't share more than %@ items."; + /* alert title */ "IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS" = "Failed to select attachment."; diff --git a/Signal/src/views/Toast.swift b/SignalMessaging/Views/Toast.swift similarity index 92% rename from Signal/src/views/Toast.swift rename to SignalMessaging/Views/Toast.swift index 8444d3f82..3500aaf12 100644 --- a/Signal/src/views/Toast.swift +++ b/SignalMessaging/Views/Toast.swift @@ -1,71 +1,11 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // import Foundation -protocol ToastViewDelegate: class { - func didTapToastView(_ toastView: ToastView) - func didSwipeToastView(_ toastView: ToastView) -} - -class ToastView: UIView { - - var text: String? { - get { - return label.text - } - set { - label.text = newValue - } - } - weak var delegate: ToastViewDelegate? - - private let label: UILabel - - // MARK: Initializers - - override init(frame: CGRect) { - label = UILabel() - super.init(frame: frame) - - self.layer.cornerRadius = 4 - self.backgroundColor = Theme.toastBackgroundColor - self.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) - - label.textAlignment = .center - label.textColor = Theme.toastForegroundColor - label.font = UIFont.ows_dynamicTypeBody - label.numberOfLines = 0 - self.addSubview(label) - label.autoPinEdgesToSuperviewMargins() - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(gesture:))) - self.addGestureRecognizer(tapGesture) - - let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(didSwipe(gesture:))) - self.addGestureRecognizer(swipeGesture) - } - - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - // MARK: Gestures - - @objc - func didTap(gesture: UITapGestureRecognizer) { - self.delegate?.didTapToastView(self) - } - - @objc - func didSwipe(gesture: UISwipeGestureRecognizer) { - self.delegate?.didSwipeToastView(self) - } -} - @objc -class ToastController: NSObject, ToastViewDelegate { +public class ToastController: NSObject, ToastViewDelegate { static var currentToastController: ToastController? @@ -75,7 +15,7 @@ class ToastController: NSObject, ToastViewDelegate { // MARK: Initializers @objc - required init(text: String) { + required public init(text: String) { toastView = ToastView() toastView.text = text isDismissing = false @@ -85,14 +25,10 @@ class ToastController: NSObject, ToastViewDelegate { toastView.delegate = self } - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - // MARK: Public @objc - func presentToastView(fromBottomOfView view: UIView, inset: CGFloat) { + public func presentToastView(fromBottomOfView view: UIView, inset: CGFloat) { Logger.debug("") toastView.alpha = 0 view.addSubview(toastView) @@ -153,3 +89,63 @@ class ToastController: NSObject, ToastViewDelegate { }) } } + +protocol ToastViewDelegate: class { + func didTapToastView(_ toastView: ToastView) + func didSwipeToastView(_ toastView: ToastView) +} + +class ToastView: UIView { + + var text: String? { + get { + return label.text + } + set { + label.text = newValue + } + } + weak var delegate: ToastViewDelegate? + + private let label: UILabel + + // MARK: Initializers + + override init(frame: CGRect) { + label = UILabel() + super.init(frame: frame) + + self.layer.cornerRadius = 4 + self.backgroundColor = Theme.toastBackgroundColor + self.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) + + label.textAlignment = .center + label.textColor = Theme.toastForegroundColor + label.font = UIFont.ows_dynamicTypeBody + label.numberOfLines = 0 + self.addSubview(label) + label.autoPinEdgesToSuperviewMargins() + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(gesture:))) + self.addGestureRecognizer(tapGesture) + + let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(didSwipe(gesture:))) + self.addGestureRecognizer(swipeGesture) + } + + required init?(coder aDecoder: NSCoder) { + notImplemented() + } + + // MARK: Gestures + + @objc + func didTap(gesture: UITapGestureRecognizer) { + self.delegate?.didTapToastView(self) + } + + @objc + func didSwipe(gesture: UISwipeGestureRecognizer) { + self.delegate?.didSwipeToastView(self) + } +}