Split out generic action sheet components
Keep the message specific components separte, so we could re-use the MenuActionsViewController.
This commit is contained in:
parent
093a5eaa68
commit
82fdd5b883
|
@ -419,7 +419,8 @@
|
||||||
4C20B2B720CA0034001BAC90 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; };
|
4C20B2B720CA0034001BAC90 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; };
|
||||||
4C20B2B920CA10DE001BAC90 /* ConversationSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */; };
|
4C20B2B920CA10DE001BAC90 /* ConversationSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */; };
|
||||||
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */; };
|
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */; };
|
||||||
4CB5F26720F6E1E2004D1B42 /* MessageActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MessageActionsViewController.swift */; };
|
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; };
|
||||||
|
4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; };
|
||||||
4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */; };
|
4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */; };
|
||||||
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
|
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
|
||||||
768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; };
|
768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; };
|
||||||
|
@ -1083,8 +1084,9 @@
|
||||||
4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; };
|
4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; };
|
||||||
4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearchViewController.swift; sourceTree = "<group>"; };
|
4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearchViewController.swift; sourceTree = "<group>"; };
|
||||||
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableTextField.swift; sourceTree = "<group>"; };
|
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableTextField.swift; sourceTree = "<group>"; };
|
||||||
|
4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = "<group>"; };
|
||||||
4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationConfigurationSyncOperation.swift; sourceTree = "<group>"; };
|
4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationConfigurationSyncOperation.swift; sourceTree = "<group>"; };
|
||||||
4CFF4C0920F55BBA005DA313 /* MessageActionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActionsViewController.swift; sourceTree = "<group>"; };
|
4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuActionsViewController.swift; sourceTree = "<group>"; };
|
||||||
69349DE607F5BA6036C9AC60 /* Pods-SignalShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
69349DE607F5BA6036C9AC60 /* Pods-SignalShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
70377AAA1918450100CAF501 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
70377AAA1918450100CAF501 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||||
748A5CAEDD7C919FC64C6807 /* Pods_SignalTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
748A5CAEDD7C919FC64C6807 /* Pods_SignalTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -1691,7 +1693,7 @@
|
||||||
452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */,
|
452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */,
|
||||||
45F32C1D205718B000A300D5 /* MediaPageViewController.swift */,
|
45F32C1D205718B000A300D5 /* MediaPageViewController.swift */,
|
||||||
454A84032059C787008B8C75 /* MediaTileViewController.swift */,
|
454A84032059C787008B8C75 /* MediaTileViewController.swift */,
|
||||||
4CFF4C0920F55BBA005DA313 /* MessageActionsViewController.swift */,
|
4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */,
|
||||||
34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */,
|
34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */,
|
||||||
34B3F84F1E8DF1700035BE1A /* NewContactThreadViewController.h */,
|
34B3F84F1E8DF1700035BE1A /* NewContactThreadViewController.h */,
|
||||||
34B3F8501E8DF1700035BE1A /* NewContactThreadViewController.m */,
|
34B3F8501E8DF1700035BE1A /* NewContactThreadViewController.m */,
|
||||||
|
@ -1989,6 +1991,7 @@
|
||||||
45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */,
|
45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */,
|
||||||
458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */,
|
458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */,
|
||||||
458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */,
|
458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */,
|
||||||
|
4CB5F26820F7D060004D1B42 /* MessageActions.swift */,
|
||||||
);
|
);
|
||||||
path = Models;
|
path = Models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -3264,7 +3267,7 @@
|
||||||
340FC8CD20518C77007AEB0F /* OWSBackupJob.m in Sources */,
|
340FC8CD20518C77007AEB0F /* OWSBackupJob.m in Sources */,
|
||||||
34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */,
|
34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */,
|
||||||
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
|
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
|
||||||
4CB5F26720F6E1E2004D1B42 /* MessageActionsViewController.swift in Sources */,
|
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */,
|
||||||
451686AB1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */,
|
451686AB1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */,
|
||||||
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,
|
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,
|
||||||
340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */,
|
340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */,
|
||||||
|
@ -3350,6 +3353,7 @@
|
||||||
76EB054018170B33006006FC /* AppDelegate.m in Sources */,
|
76EB054018170B33006006FC /* AppDelegate.m in Sources */,
|
||||||
34D1F0831F8678AA0066283D /* ConversationInputTextView.m in Sources */,
|
34D1F0831F8678AA0066283D /* ConversationInputTextView.m in Sources */,
|
||||||
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */,
|
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */,
|
||||||
|
4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */,
|
||||||
340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */,
|
340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */,
|
||||||
34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */,
|
34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */,
|
||||||
340FC8B9204DAC8D007AEB0F /* UpdateGroupViewController.m in Sources */,
|
340FC8B9204DAC8D007AEB0F /* UpdateGroupViewController.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc
|
||||||
|
protocol MessageActionsDelegate: class {
|
||||||
|
func messageActionsShowDetailsForItem(_ conversationViewItem: ConversationViewItem)
|
||||||
|
func messageActionsReplyToItem(_ conversationViewItem: ConversationViewItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MessageActionBuilder {
|
||||||
|
static func reply(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
|
||||||
|
return MenuAction(image: #imageLiteral(resourceName: "ic_reply"),
|
||||||
|
title: NSLocalizedString("MESSAGE_ACTION_REPLY", comment: "Action sheet button title"),
|
||||||
|
subtitle: nil,
|
||||||
|
block: { [weak delegate] (_) in
|
||||||
|
delegate?.messageActionsReplyToItem(conversationViewItem)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static func copyText(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
|
||||||
|
return MenuAction(image: #imageLiteral(resourceName: "ic_copy"),
|
||||||
|
title: NSLocalizedString("MESSAGE_ACTION_COPY_TEXT", comment: "Action sheet button title"),
|
||||||
|
subtitle: nil,
|
||||||
|
block: { (_) in
|
||||||
|
conversationViewItem.copyTextAction()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static func showDetails(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
|
||||||
|
return MenuAction(image: #imageLiteral(resourceName: "ic_info"),
|
||||||
|
title: NSLocalizedString("MESSAGE_ACTION_DETAILS", comment: "Action sheet button title"),
|
||||||
|
subtitle: nil,
|
||||||
|
block: { [weak delegate] (_) in
|
||||||
|
delegate?.messageActionsShowDetailsForItem(conversationViewItem)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static func deleteMessage(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
|
||||||
|
return MenuAction(image: #imageLiteral(resourceName: "ic_trash"),
|
||||||
|
title: NSLocalizedString("MESSAGE_ACTION_DELETE_MESSAGE", comment: "Action sheet button title"),
|
||||||
|
subtitle: NSLocalizedString("MESSAGE_ACTION_DELETE_MESSAGE_SUBTITLE", comment: "Action sheet button subtitle"),
|
||||||
|
block: { (_) in
|
||||||
|
conversationViewItem.deleteAction()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static func copyMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
|
||||||
|
return MenuAction(image: #imageLiteral(resourceName: "ic_copy"),
|
||||||
|
title: NSLocalizedString("MESSAGE_ACTION_COPY_MEDIA", comment: "Action sheet button title"),
|
||||||
|
subtitle: nil,
|
||||||
|
block: { (_) in
|
||||||
|
conversationViewItem.copyMediaAction()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static func saveMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MenuAction {
|
||||||
|
return MenuAction(image: #imageLiteral(resourceName: "ic_download"),
|
||||||
|
title: NSLocalizedString("MESSAGE_ACTION_SAVE_MEDIA", comment: "Action sheet button title"),
|
||||||
|
subtitle: nil,
|
||||||
|
block: { (_) in
|
||||||
|
conversationViewItem.saveMediaAction()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ConversationViewItem {
|
||||||
|
|
||||||
|
@objc
|
||||||
|
func textActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||||
|
var actions: [MenuAction] = []
|
||||||
|
|
||||||
|
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(replyAction)
|
||||||
|
|
||||||
|
if self.hasBodyTextActionContent {
|
||||||
|
let copyTextAction = MessageActionBuilder.copyText(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(copyTextAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(deleteAction)
|
||||||
|
|
||||||
|
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(showDetailsAction)
|
||||||
|
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
func mediaActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||||
|
var actions: [MenuAction] = []
|
||||||
|
|
||||||
|
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(replyAction)
|
||||||
|
|
||||||
|
if self.hasMediaActionContent {
|
||||||
|
let copyMediaAction = MessageActionBuilder.copyMedia(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(copyMediaAction)
|
||||||
|
let saveMediaAction = MessageActionBuilder.saveMedia(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(saveMediaAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(deleteAction)
|
||||||
|
|
||||||
|
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||||
|
actions.append(showDetailsAction)
|
||||||
|
|
||||||
|
return actions
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
func quotedMessageActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||||
|
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||||
|
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||||
|
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||||
|
|
||||||
|
return [replyAction, deleteAction, showDetailsAction]
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
func infoMessageActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||||
|
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||||
|
|
||||||
|
return [deleteAction]
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,7 @@ typedef enum : NSUInteger {
|
||||||
ConversationViewCellDelegate,
|
ConversationViewCellDelegate,
|
||||||
ConversationInputTextViewDelegate,
|
ConversationInputTextViewDelegate,
|
||||||
MessageActionsDelegate,
|
MessageActionsDelegate,
|
||||||
|
MenuActionsViewControllerDelegate,
|
||||||
OWSMessageBubbleViewDelegate,
|
OWSMessageBubbleViewDelegate,
|
||||||
UICollectionViewDelegate,
|
UICollectionViewDelegate,
|
||||||
UICollectionViewDataSource,
|
UICollectionViewDataSource,
|
||||||
|
@ -1981,13 +1982,6 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
#pragma mark - MessageActionsDelegate
|
#pragma mark - MessageActionsDelegate
|
||||||
|
|
||||||
- (void)messageActionsDidHide:(MessageActionsViewController *)messageActionsViewController
|
|
||||||
{
|
|
||||||
[[OWSWindowManager sharedManager] hideMessageActionsWindow:messageActionsViewController];
|
|
||||||
|
|
||||||
[self updateShouldObserveDBModifications];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)messageActionsShowDetailsForItem:(ConversationViewItem *)conversationViewItem
|
- (void)messageActionsShowDetailsForItem:(ConversationViewItem *)conversationViewItem
|
||||||
{
|
{
|
||||||
[self showDetailViewForViewItem:conversationViewItem];
|
[self showDetailViewForViewItem:conversationViewItem];
|
||||||
|
@ -1998,7 +1992,16 @@ typedef enum : NSUInteger {
|
||||||
[self populateReplyForViewItem:conversationViewItem];
|
[self populateReplyForViewItem:conversationViewItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)messageActions:(MessageActionsViewController *)messageActionsViewController
|
#pragma mark - MenuActionsViewControllerDelegate
|
||||||
|
|
||||||
|
- (void)menuActionsDidHide:(MenuActionsViewController *)menuActionsViewController
|
||||||
|
{
|
||||||
|
[[OWSWindowManager sharedManager] hideMenuActionsWindow];
|
||||||
|
|
||||||
|
[self updateShouldObserveDBModifications];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)menuActions:(MenuActionsViewController *)menuActionsViewController
|
||||||
isPresentingWithVerticalFocusChange:(CGFloat)verticalChange
|
isPresentingWithVerticalFocusChange:(CGFloat)verticalChange
|
||||||
{
|
{
|
||||||
UIEdgeInsets oldInset = self.collectionView.contentInset;
|
UIEdgeInsets oldInset = self.collectionView.contentInset;
|
||||||
|
@ -2026,7 +2029,7 @@ typedef enum : NSUInteger {
|
||||||
self.collectionView.contentInset = newInset;
|
self.collectionView.contentInset = newInset;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)messageActions:(MessageActionsViewController *)messageActionsViewController
|
- (void)menuActions:(MenuActionsViewController *)menuActionsViewController
|
||||||
isDismissingWithVerticalFocusChange:(CGFloat)verticalChange
|
isDismissingWithVerticalFocusChange:(CGFloat)verticalChange
|
||||||
{
|
{
|
||||||
UIEdgeInsets oldInset = self.collectionView.contentInset;
|
UIEdgeInsets oldInset = self.collectionView.contentInset;
|
||||||
|
@ -2058,36 +2061,36 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(ConversationViewItem *)viewItem
|
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(ConversationViewItem *)viewItem
|
||||||
{
|
{
|
||||||
NSArray<MessageAction *> *messageActions = [viewItem mediaActionsWithDelegate:self];
|
NSArray<MenuAction *> *messageActions = [viewItem mediaActionsWithDelegate:self];
|
||||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(ConversationViewItem *)viewItem
|
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(ConversationViewItem *)viewItem
|
||||||
{
|
{
|
||||||
NSArray<MessageAction *> *messageActions = [viewItem textActionsWithDelegate:self];
|
NSArray<MenuAction *> *messageActions = [viewItem textActionsWithDelegate:self];
|
||||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(ConversationViewItem *)viewItem
|
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(ConversationViewItem *)viewItem
|
||||||
{
|
{
|
||||||
NSArray<MessageAction *> *messageActions = [viewItem quotedMessageActionsWithDelegate:self];
|
NSArray<MenuAction *> *messageActions = [viewItem quotedMessageActionsWithDelegate:self];
|
||||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressSystemMessageViewItem:(ConversationViewItem *)viewItem
|
- (void)conversationCell:(ConversationViewCell *)cell didLongpressSystemMessageViewItem:(ConversationViewItem *)viewItem
|
||||||
{
|
{
|
||||||
NSArray<MessageAction *> *messageActions = [viewItem infoMessageActionsWithDelegate:self];
|
NSArray<MenuAction *> *messageActions = [viewItem infoMessageActionsWithDelegate:self];
|
||||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)presentMessageActions:(NSArray<MessageAction *> *)messageActions withFocusedCell:(ConversationViewCell *)cell
|
- (void)presentMessageActions:(NSArray<MenuAction *> *)messageActions withFocusedCell:(ConversationViewCell *)cell
|
||||||
{
|
{
|
||||||
MessageActionsViewController *messageActionsViewController =
|
MenuActionsViewController *menuActionsViewController =
|
||||||
[[MessageActionsViewController alloc] initWithFocusedView:cell actions:messageActions];
|
[[MenuActionsViewController alloc] initWithFocusedView:cell actions:messageActions];
|
||||||
|
|
||||||
messageActionsViewController.delegate = self;
|
menuActionsViewController.delegate = self;
|
||||||
|
|
||||||
[[OWSWindowManager sharedManager] showMessageActionsWindow:messageActionsViewController];
|
[[OWSWindowManager sharedManager] showMenuActionsWindow:menuActionsViewController];
|
||||||
|
|
||||||
[self updateShouldObserveDBModifications];
|
[self updateShouldObserveDBModifications];
|
||||||
}
|
}
|
||||||
|
@ -4550,7 +4553,7 @@ typedef enum : NSUInteger {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OWSWindowManager.sharedManager.isPresentingMessageActions) {
|
if (OWSWindowManager.sharedManager.isPresentingMenuActions) {
|
||||||
self.shouldObserveDBModifications = NO;
|
self.shouldObserveDBModifications = NO;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,148 +5,41 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
protocol MessageActionsDelegate: class {
|
public class MenuAction: NSObject {
|
||||||
func messageActionsDidHide(_ messageActionsViewController: MessageActionsViewController)
|
let block: (MenuAction) -> Void
|
||||||
func messageActionsShowDetailsForItem(_ conversationViewItem: ConversationViewItem)
|
let image: UIImage
|
||||||
func messageActionsReplyToItem(_ conversationViewItem: ConversationViewItem)
|
let title: String
|
||||||
func messageActions(_ messageActionsViewController: MessageActionsViewController, isPresentingWithVerticalFocusChange: CGFloat)
|
let subtitle: String?
|
||||||
func messageActions(_ messageActionsViewController: MessageActionsViewController, isDismissingWithVerticalFocusChange: CGFloat)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MessageActionBuilder {
|
public init(image: UIImage, title: String, subtitle: String?, block: @escaping (MenuAction) -> Void) {
|
||||||
static func reply(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MessageAction {
|
self.image = image
|
||||||
return MessageAction(image: #imageLiteral(resourceName: "ic_reply"),
|
self.title = title
|
||||||
title: NSLocalizedString("MESSAGE_ACTION_REPLY", comment: "Action sheet button title"),
|
self.subtitle = subtitle
|
||||||
subtitle: nil,
|
self.block = block
|
||||||
block: { [weak delegate] (_) in
|
|
||||||
delegate?.messageActionsReplyToItem(conversationViewItem)
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static func copyText(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MessageAction {
|
|
||||||
return MessageAction(image: #imageLiteral(resourceName: "ic_copy"),
|
|
||||||
title: NSLocalizedString("MESSAGE_ACTION_COPY_TEXT", comment: "Action sheet button title"),
|
|
||||||
subtitle: nil,
|
|
||||||
block: { (_) in
|
|
||||||
conversationViewItem.copyTextAction()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static func showDetails(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MessageAction {
|
|
||||||
return MessageAction(image: #imageLiteral(resourceName: "ic_info"),
|
|
||||||
title: NSLocalizedString("MESSAGE_ACTION_DETAILS", comment: "Action sheet button title"),
|
|
||||||
subtitle: nil,
|
|
||||||
block: { [weak delegate] (_) in
|
|
||||||
delegate?.messageActionsShowDetailsForItem(conversationViewItem)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static func deleteMessage(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MessageAction {
|
|
||||||
return MessageAction(image: #imageLiteral(resourceName: "ic_trash"),
|
|
||||||
title: NSLocalizedString("MESSAGE_ACTION_DELETE_MESSAGE", comment: "Action sheet button title"),
|
|
||||||
subtitle: NSLocalizedString("MESSAGE_ACTION_DELETE_MESSAGE_SUBTITLE", comment: "Action sheet button subtitle"),
|
|
||||||
block: { (_) in
|
|
||||||
conversationViewItem.deleteAction()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static func copyMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MessageAction {
|
|
||||||
return MessageAction(image: #imageLiteral(resourceName: "ic_copy"),
|
|
||||||
title: NSLocalizedString("MESSAGE_ACTION_COPY_MEDIA", comment: "Action sheet button title"),
|
|
||||||
subtitle: nil,
|
|
||||||
block: { (_) in
|
|
||||||
conversationViewItem.copyMediaAction()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static func saveMedia(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> MessageAction {
|
|
||||||
return MessageAction(image: #imageLiteral(resourceName: "ic_download"),
|
|
||||||
title: NSLocalizedString("MESSAGE_ACTION_SAVE_MEDIA", comment: "Action sheet button title"),
|
|
||||||
subtitle: nil,
|
|
||||||
block: { (_) in
|
|
||||||
conversationViewItem.saveMediaAction()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ConversationViewItem {
|
|
||||||
|
|
||||||
@objc
|
|
||||||
func textActions(delegate: MessageActionsDelegate) -> [MessageAction] {
|
|
||||||
var actions: [MessageAction] = []
|
|
||||||
|
|
||||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(replyAction)
|
|
||||||
|
|
||||||
if self.hasBodyTextActionContent {
|
|
||||||
let copyTextAction = MessageActionBuilder.copyText(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(copyTextAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(deleteAction)
|
|
||||||
|
|
||||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(showDetailsAction)
|
|
||||||
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
func mediaActions(delegate: MessageActionsDelegate) -> [MessageAction] {
|
|
||||||
var actions: [MessageAction] = []
|
|
||||||
|
|
||||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(replyAction)
|
|
||||||
|
|
||||||
if self.hasMediaActionContent {
|
|
||||||
let copyMediaAction = MessageActionBuilder.copyMedia(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(copyMediaAction)
|
|
||||||
let saveMediaAction = MessageActionBuilder.saveMedia(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(saveMediaAction)
|
|
||||||
}
|
|
||||||
|
|
||||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(deleteAction)
|
|
||||||
|
|
||||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
|
||||||
actions.append(showDetailsAction)
|
|
||||||
|
|
||||||
return actions
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
func quotedMessageActions(delegate: MessageActionsDelegate) -> [MessageAction] {
|
|
||||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
|
||||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
|
||||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
|
||||||
|
|
||||||
return [replyAction, deleteAction, showDetailsAction]
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
func infoMessageActions(delegate: MessageActionsDelegate) -> [MessageAction] {
|
|
||||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
|
||||||
|
|
||||||
return [deleteAction]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
class MessageActionsViewController: UIViewController, MessageActionSheetDelegate {
|
protocol MenuActionsViewControllerDelegate: class {
|
||||||
|
func menuActionsDidHide(_ menuActionsViewController: MenuActionsViewController)
|
||||||
|
func menuActions(_ menuActionsViewController: MenuActionsViewController, isPresentingWithVerticalFocusChange: CGFloat)
|
||||||
|
func menuActions(_ menuActionsViewController: MenuActionsViewController, isDismissingWithVerticalFocusChange: CGFloat)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
class MenuActionsViewController: UIViewController, MenuActionSheetDelegate {
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
weak var delegate: MessageActionsDelegate?
|
weak var delegate: MenuActionsViewControllerDelegate?
|
||||||
|
|
||||||
private let focusedView: UIView
|
private let focusedView: UIView
|
||||||
private let actionSheetView: MessageActionSheetView
|
private let actionSheetView: MenuActionSheetView
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
required init(focusedView: UIView, actions: [MessageAction]) {
|
required init(focusedView: UIView, actions: [MenuAction]) {
|
||||||
self.focusedView = focusedView
|
self.focusedView = focusedView
|
||||||
|
|
||||||
self.actionSheetView = MessageActionSheetView(actions: actions)
|
self.actionSheetView = MenuActionSheetView(actions: actions)
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
actionSheetView.delegate = self
|
actionSheetView.delegate = self
|
||||||
|
@ -206,8 +99,6 @@ class MessageActionsViewController: UIViewController, MessageActionSheetDelegate
|
||||||
}
|
}
|
||||||
|
|
||||||
private func animatePresentation() {
|
private func animatePresentation() {
|
||||||
// TODO first time only?
|
|
||||||
|
|
||||||
guard let actionSheetViewVerticalConstraint = self.actionSheetViewVerticalConstraint else {
|
guard let actionSheetViewVerticalConstraint = self.actionSheetViewVerticalConstraint else {
|
||||||
owsFail("\(self.logTag) in \(#function) actionSheetViewVerticalConstraint was unexpectedly nil")
|
owsFail("\(self.logTag) in \(#function) actionSheetViewVerticalConstraint was unexpectedly nil")
|
||||||
return
|
return
|
||||||
|
@ -255,27 +146,27 @@ class MessageActionsViewController: UIViewController, MessageActionSheetDelegate
|
||||||
|
|
||||||
let offset = -overlap
|
let offset = -overlap
|
||||||
self.presentationFocusOffset = offset
|
self.presentationFocusOffset = offset
|
||||||
self.delegate?.messageActions(self, isPresentingWithVerticalFocusChange: offset)
|
self.delegate?.menuActions(self, isPresentingWithVerticalFocusChange: offset)
|
||||||
},
|
},
|
||||||
completion: nil)
|
completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func animateDismiss(action: MessageAction?) {
|
private func animateDismiss(action: MenuAction?) {
|
||||||
guard let actionSheetViewVerticalConstraint = self.actionSheetViewVerticalConstraint else {
|
guard let actionSheetViewVerticalConstraint = self.actionSheetViewVerticalConstraint else {
|
||||||
owsFail("\(self.logTag) in \(#function) actionSheetVerticalConstraint was unexpectedly nil")
|
owsFail("\(self.logTag) in \(#function) actionSheetVerticalConstraint was unexpectedly nil")
|
||||||
self.delegate?.messageActionsDidHide(self)
|
self.delegate?.menuActionsDidHide(self)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let snapshotView = self.snapshotView else {
|
guard let snapshotView = self.snapshotView else {
|
||||||
owsFail("\(self.logTag) in \(#function) snapshotView was unexpectedly nil")
|
owsFail("\(self.logTag) in \(#function) snapshotView was unexpectedly nil")
|
||||||
self.delegate?.messageActionsDidHide(self)
|
self.delegate?.menuActionsDidHide(self)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let presentationFocusOffset = self.presentationFocusOffset else {
|
guard let presentationFocusOffset = self.presentationFocusOffset else {
|
||||||
owsFail("\(self.logTag) in \(#function) presentationFocusOffset was unexpectedly nil")
|
owsFail("\(self.logTag) in \(#function) presentationFocusOffset was unexpectedly nil")
|
||||||
self.delegate?.messageActionsDidHide(self)
|
self.delegate?.menuActionsDidHide(self)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,11 +184,11 @@ class MessageActionsViewController: UIViewController, MessageActionSheetDelegate
|
||||||
snapshotView.frame.origin.y -= presentationFocusOffset
|
snapshotView.frame.origin.y -= presentationFocusOffset
|
||||||
// this helps when focused view is above navbars, etc.
|
// this helps when focused view is above navbars, etc.
|
||||||
snapshotView.alpha = 0
|
snapshotView.alpha = 0
|
||||||
self.delegate?.messageActions(self, isDismissingWithVerticalFocusChange: presentationFocusOffset)
|
self.delegate?.menuActions(self, isDismissingWithVerticalFocusChange: presentationFocusOffset)
|
||||||
},
|
},
|
||||||
completion: { _ in
|
completion: { _ in
|
||||||
self.view.isHidden = true
|
self.view.isHidden = true
|
||||||
self.delegate?.messageActionsDidHide(self)
|
self.delegate?.menuActionsDidHide(self)
|
||||||
if let action = action {
|
if let action = action {
|
||||||
action.block(action)
|
action.block(action)
|
||||||
}
|
}
|
||||||
|
@ -316,43 +207,92 @@ class MessageActionsViewController: UIViewController, MessageActionSheetDelegate
|
||||||
animateDismiss(action: nil)
|
animateDismiss(action: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: MessageActionSheetDelegate
|
// MARK: MenuActionSheetDelegate
|
||||||
|
|
||||||
func actionSheet(_ actionSheet: MessageActionSheetView, didSelectAction action: MessageAction) {
|
func actionSheet(_ actionSheet: MenuActionSheetView, didSelectAction action: MenuAction) {
|
||||||
animateDismiss(action: action)
|
animateDismiss(action: action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: ActionView
|
protocol MenuActionSheetDelegate: class {
|
||||||
|
func actionSheet(_ actionSheet: MenuActionSheetView, didSelectAction action: MenuAction)
|
||||||
|
}
|
||||||
|
|
||||||
@objc
|
class MenuActionSheetView: UIView, MenuActionViewDelegate {
|
||||||
public class MessageAction: NSObject {
|
|
||||||
let block: (MessageAction) -> Void
|
|
||||||
let image: UIImage
|
|
||||||
let title: String
|
|
||||||
let subtitle: String?
|
|
||||||
|
|
||||||
public init(image: UIImage, title: String, subtitle: String?, block: @escaping (MessageAction) -> Void) {
|
private let actionStackView: UIStackView
|
||||||
self.image = image
|
private var actions: [MenuAction]
|
||||||
self.title = title
|
weak var delegate: MenuActionSheetDelegate?
|
||||||
self.subtitle = subtitle
|
|
||||||
self.block = block
|
override var bounds: CGRect {
|
||||||
|
didSet {
|
||||||
|
updateMask()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(actions: [MenuAction]) {
|
||||||
|
self.init(frame: CGRect.zero)
|
||||||
|
actions.forEach { self.addAction($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
actionStackView = UIStackView()
|
||||||
|
actionStackView.axis = .vertical
|
||||||
|
actionStackView.spacing = CGHairlineWidth()
|
||||||
|
|
||||||
|
actions = []
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
backgroundColor = UIColor.ows_light10
|
||||||
|
addSubview(actionStackView)
|
||||||
|
actionStackView.autoPinToSuperviewEdges()
|
||||||
|
|
||||||
|
self.clipsToBounds = true
|
||||||
|
|
||||||
|
// Prevent panning from percolating to the superview, which would
|
||||||
|
// cause us to dismiss
|
||||||
|
let panGestureSink = UIPanGestureRecognizer(target: nil, action: nil)
|
||||||
|
self.addGestureRecognizer(panGestureSink)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
public func addAction(_ action: MenuAction) {
|
||||||
|
let actionView = MenuActionView(action: action)
|
||||||
|
actionView.delegate = self
|
||||||
|
actions.append(action)
|
||||||
|
self.actionStackView.addArrangedSubview(actionView)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: MenuActionViewDelegate
|
||||||
|
|
||||||
|
func actionView(_ actionView: MenuActionView, didSelectAction action: MenuAction) {
|
||||||
|
self.delegate?.actionSheet(self, didSelectAction: action)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK:
|
||||||
|
|
||||||
|
private func updateMask() {
|
||||||
|
let cornerRadius: CGFloat = 16
|
||||||
|
let path: UIBezierPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
|
||||||
|
let mask = CAShapeLayer()
|
||||||
|
mask.path = path.cgPath
|
||||||
|
self.layer.mask = mask
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol MessageActionSheetDelegate: class {
|
protocol MenuActionViewDelegate: class {
|
||||||
func actionSheet(_ actionSheet: MessageActionSheetView, didSelectAction action: MessageAction)
|
func actionView(_ actionView: MenuActionView, didSelectAction action: MenuAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol MessageActionViewDelegate: class {
|
class MenuActionView: UIButton {
|
||||||
func actionView(_ actionView: MessageActionView, didSelectAction action: MessageAction)
|
public weak var delegate: MenuActionViewDelegate?
|
||||||
}
|
private let action: MenuAction
|
||||||
|
|
||||||
class MessageActionView: UIButton {
|
required init(action: MenuAction) {
|
||||||
public weak var delegate: MessageActionViewDelegate?
|
|
||||||
private let action: MessageAction
|
|
||||||
|
|
||||||
required init(action: MessageAction) {
|
|
||||||
self.action = action
|
self.action = action
|
||||||
|
|
||||||
super.init(frame: CGRect.zero)
|
super.init(frame: CGRect.zero)
|
||||||
|
@ -413,69 +353,3 @@ class MessageActionView: UIButton {
|
||||||
fatalError("not implemented")
|
fatalError("not implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageActionSheetView: UIView, MessageActionViewDelegate {
|
|
||||||
|
|
||||||
private let actionStackView: UIStackView
|
|
||||||
private var actions: [MessageAction]
|
|
||||||
weak var delegate: MessageActionSheetDelegate?
|
|
||||||
|
|
||||||
override var bounds: CGRect {
|
|
||||||
didSet {
|
|
||||||
updateMask()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
convenience init(actions: [MessageAction]) {
|
|
||||||
self.init(frame: CGRect.zero)
|
|
||||||
actions.forEach { self.addAction($0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
actionStackView = UIStackView()
|
|
||||||
actionStackView.axis = .vertical
|
|
||||||
actionStackView.spacing = CGHairlineWidth()
|
|
||||||
|
|
||||||
actions = []
|
|
||||||
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
backgroundColor = UIColor.ows_light10
|
|
||||||
addSubview(actionStackView)
|
|
||||||
actionStackView.autoPinToSuperviewEdges()
|
|
||||||
|
|
||||||
self.clipsToBounds = true
|
|
||||||
|
|
||||||
// Prevent panning from percolating to the superview, which would
|
|
||||||
// cause us to dismiss
|
|
||||||
let panGestureSink = UIPanGestureRecognizer(target: nil, action: nil)
|
|
||||||
self.addGestureRecognizer(panGestureSink)
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
|
||||||
fatalError("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
public func addAction(_ action: MessageAction) {
|
|
||||||
let actionView = MessageActionView(action: action)
|
|
||||||
actionView.delegate = self
|
|
||||||
actions.append(action)
|
|
||||||
self.actionStackView.addArrangedSubview(actionView)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: MessageActionViewDelegate
|
|
||||||
|
|
||||||
func actionView(_ actionView: MessageActionView, didSelectAction action: MessageAction) {
|
|
||||||
self.delegate?.actionSheet(self, didSelectAction: action)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK:
|
|
||||||
|
|
||||||
private func updateMask() {
|
|
||||||
let cornerRadius: CGFloat = 16
|
|
||||||
let path: UIBezierPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
|
|
||||||
let mask = CAShapeLayer()
|
|
||||||
mask.path = path.cgPath
|
|
||||||
self.layer.mask = mask
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,10 +29,10 @@ extern const UIWindowLevel UIWindowLevel_Background;
|
||||||
|
|
||||||
#pragma mark - Message Actions
|
#pragma mark - Message Actions
|
||||||
|
|
||||||
@property (nonatomic, readonly) BOOL isPresentingMessageActions;
|
@property (nonatomic, readonly) BOOL isPresentingMenuActions;
|
||||||
|
|
||||||
- (void)showMessageActionsWindow:(UIViewController *)messageActionsViewController;
|
- (void)showMenuActionsWindow:(UIViewController *)menuActionsViewController;
|
||||||
- (void)hideMessageActionsWindow:(UIViewController *)messageActionsViewController;
|
- (void)hideMenuActionsWindow;
|
||||||
|
|
||||||
#pragma mark - Calls
|
#pragma mark - Calls
|
||||||
|
|
||||||
|
|
|
@ -101,8 +101,8 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
|
||||||
@property (nonatomic) UINavigationController *callNavigationController;
|
@property (nonatomic) UINavigationController *callNavigationController;
|
||||||
|
|
||||||
// UIWindowLevel_MessageActions
|
// UIWindowLevel_MessageActions
|
||||||
@property (nonatomic) UIWindow *messageActionsWindow;
|
@property (nonatomic) UIWindow *menuActionsWindow;
|
||||||
@property (nonatomic, nullable) UIViewController *messageActionsViewController;
|
@property (nonatomic, nullable) UIViewController *menuActionsViewController;
|
||||||
|
|
||||||
// UIWindowLevel_Background if inactive,
|
// UIWindowLevel_Background if inactive,
|
||||||
// UIWindowLevel_ScreenBlocking() if active.
|
// UIWindowLevel_ScreenBlocking() if active.
|
||||||
|
@ -157,7 +157,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
|
||||||
|
|
||||||
self.returnToCallWindow = [self createReturnToCallWindow:rootWindow];
|
self.returnToCallWindow = [self createReturnToCallWindow:rootWindow];
|
||||||
self.callViewWindow = [self createCallViewWindow:rootWindow];
|
self.callViewWindow = [self createCallViewWindow:rootWindow];
|
||||||
self.messageActionsWindow = [self createMessageActionsWindowWithRoowWindow:rootWindow];
|
self.menuActionsWindow = [self createMenuActionsWindowWithRoowWindow:rootWindow];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(didChangeStatusBarFrame:)
|
selector:@selector(didChangeStatusBarFrame:)
|
||||||
|
@ -200,7 +200,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIWindow *)createMessageActionsWindowWithRoowWindow:(UIWindow *)rootWindow
|
- (UIWindow *)createMenuActionsWindowWithRoowWindow:(UIWindow *)rootWindow
|
||||||
{
|
{
|
||||||
UIWindow *window;
|
UIWindow *window;
|
||||||
if (@available(iOS 11, *)) {
|
if (@available(iOS 11, *)) {
|
||||||
|
@ -262,25 +262,23 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
|
||||||
|
|
||||||
#pragma mark - Message Actions
|
#pragma mark - Message Actions
|
||||||
|
|
||||||
- (BOOL)isPresentingMessageActions
|
- (BOOL)isPresentingMenuActions
|
||||||
{
|
{
|
||||||
return self.messageActionsViewController != nil;
|
return self.menuActionsViewController != nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showMessageActionsWindow:(UIViewController *)messageActionsViewController
|
- (void)showMenuActionsWindow:(UIViewController *)menuActionsViewController
|
||||||
{
|
{
|
||||||
self.messageActionsViewController = messageActionsViewController;
|
self.menuActionsViewController = menuActionsViewController;
|
||||||
self.messageActionsWindow.rootViewController = messageActionsViewController;
|
self.menuActionsWindow.rootViewController = menuActionsViewController;
|
||||||
|
|
||||||
[self ensureWindowState];
|
[self ensureWindowState];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)hideMessageActionsWindow:(UIViewController *)messageActionsViewController
|
- (void)hideMenuActionsWindow
|
||||||
{
|
{
|
||||||
OWSAssert(self.messageActionsViewController == messageActionsViewController);
|
self.menuActionsWindow.rootViewController = nil;
|
||||||
|
self.menuActionsViewController = nil;
|
||||||
self.messageActionsWindow.rootViewController = nil;
|
|
||||||
self.messageActionsViewController = nil;
|
|
||||||
|
|
||||||
[self ensureWindowState];
|
[self ensureWindowState];
|
||||||
}
|
}
|
||||||
|
@ -404,7 +402,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
|
||||||
[self ensureCallViewWindowHidden];
|
[self ensureCallViewWindowHidden];
|
||||||
[self ensureMessageActionsWindowHidden];
|
[self ensureMessageActionsWindowHidden];
|
||||||
[self ensureScreenBlockWindowHidden];
|
[self ensureScreenBlockWindowHidden];
|
||||||
} else if (self.messageActionsViewController) {
|
} else if (self.menuActionsViewController) {
|
||||||
// Show Message Actions
|
// Show Message Actions
|
||||||
|
|
||||||
[self ensureRootWindowShown];
|
[self ensureRootWindowShown];
|
||||||
|
@ -503,23 +501,23 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
|
||||||
{
|
{
|
||||||
OWSAssertIsOnMainThread();
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
if (self.messageActionsWindow.hidden) {
|
if (self.menuActionsWindow.hidden) {
|
||||||
DDLogInfo(@"%@ showing message actions window.", self.logTag);
|
DDLogInfo(@"%@ showing message actions window.", self.logTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not make key, we want the keyboard to stay popped.
|
// Do not make key, we want the keyboard to stay popped.
|
||||||
self.messageActionsWindow.hidden = NO;
|
self.menuActionsWindow.hidden = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)ensureMessageActionsWindowHidden
|
- (void)ensureMessageActionsWindowHidden
|
||||||
{
|
{
|
||||||
OWSAssertIsOnMainThread();
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
if (!self.messageActionsWindow.hidden) {
|
if (!self.menuActionsWindow.hidden) {
|
||||||
DDLogInfo(@"%@ hiding message actions window.", self.logTag);
|
DDLogInfo(@"%@ hiding message actions window.", self.logTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.messageActionsWindow.hidden = YES;
|
self.menuActionsWindow.hidden = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)ensureScreenBlockWindowShown
|
- (void)ensureScreenBlockWindowShown
|
||||||
|
|
Loading…
Reference in New Issue