Skip to content

Commit

Permalink
feat(copy): Allow copying link and selection of a message
Browse files Browse the repository at this point in the history
Signed-off-by: Marcel Müller <marcel-mueller@gmx.de>
  • Loading branch information
SystemKeeper committed Jan 27, 2025
1 parent 76ed892 commit 202a727
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 27 deletions.
8 changes: 8 additions & 0 deletions NextcloudTalk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@
1F5499202D35B07700E9AA9E /* ButtonContainerSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F54991F2D35B07700E9AA9E /* ButtonContainerSwiftUI.swift */; };
1F549B662D3995C600E9AA9E /* UserSelectionSwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F549B652D3995C600E9AA9E /* UserSelectionSwiftUIView.swift */; };
1F549B692D3A9AA500E9AA9E /* DebouncedOnChange in Frameworks */ = {isa = PBXBuildFile; productRef = 1F549B682D3A9AA500E9AA9E /* DebouncedOnChange */; };
1F549E2B2D45695C00E9AA9E /* MessageTextViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1F549E2A2D45695C00E9AA9E /* MessageTextViewController.xib */; };
1F549E2D2D45695D00E9AA9E /* MessageTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F549E2C2D45695D00E9AA9E /* MessageTextViewController.swift */; };
1F5683CF2BA7980C0023E151 /* FilePreviewImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5683CE2BA7980C0023E151 /* FilePreviewImageView.swift */; };
1F5813F828EB23EF00318FC3 /* NCSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5813F628EB23EF00318FC3 /* NCSplitViewController.swift */; };
1F5813F928EB23EF00318FC3 /* NCSplitViewPlaceholderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5813F728EB23EF00318FC3 /* NCSplitViewPlaceholderViewController.swift */; };
Expand Down Expand Up @@ -743,6 +745,8 @@
1F54991D2D346F9700E9AA9E /* UserStatusAbsenceSwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserStatusAbsenceSwiftUIView.swift; sourceTree = "<group>"; };
1F54991F2D35B07700E9AA9E /* ButtonContainerSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonContainerSwiftUI.swift; sourceTree = "<group>"; };
1F549B652D3995C600E9AA9E /* UserSelectionSwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSelectionSwiftUIView.swift; sourceTree = "<group>"; };
1F549E2A2D45695C00E9AA9E /* MessageTextViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MessageTextViewController.xib; sourceTree = "<group>"; };
1F549E2C2D45695D00E9AA9E /* MessageTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageTextViewController.swift; sourceTree = "<group>"; };
1F5683CE2BA7980C0023E151 /* FilePreviewImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewImageView.swift; sourceTree = "<group>"; };
1F5813F628EB23EF00318FC3 /* NCSplitViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSplitViewController.swift; sourceTree = "<group>"; };
1F5813F728EB23EF00318FC3 /* NCSplitViewPlaceholderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSplitViewPlaceholderViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1985,6 +1989,8 @@
C65D252C2C7581A200157A89 /* ExpandedVoiceMessageRecordingView.swift */,
1F205C562CEFA01900AAA673 /* OutOfOfficeView.swift */,
1F205C542CEFA01200AAA673 /* OutOfOfficeView.xib */,
1F549E2C2D45695D00E9AA9E /* MessageTextViewController.swift */,
1F549E2A2D45695C00E9AA9E /* MessageTextViewController.xib */,
);
name = "Chat views";
sourceTree = "<group>";
Expand Down Expand Up @@ -2566,6 +2572,7 @@
2C440D1220EA4A770005F9BB /* RoomInfoTableViewController.xib in Resources */,
2C1D13A3253760EE00EC0533 /* LaunchScreen.xib in Resources */,
1FB7B99C2BF0DF360093CE98 /* BannedActorCell.xib in Resources */,
1F549E2B2D45695C00E9AA9E /* MessageTextViewController.xib in Resources */,
2C4747E22CB58FD2002828F2 /* PollMessageView.xib in Resources */,
2CA1CCAC1F067F35002FE6A2 /* Images.xcassets in Resources */,
2CA1CCD71F1E664C002FE6A2 /* ContactsTableViewCell.xib in Resources */,
Expand Down Expand Up @@ -2921,6 +2928,7 @@
2C5BFBEF288A947900E75118 /* PollVotingView.swift in Sources */,
1FAB2EF02AD1EAA3001214EB /* RLMSupport.swift in Sources */,
1F1B50342B8E069800B0F2F4 /* BaseChatTableViewCell.swift in Sources */,
1F549E2D2D45695D00E9AA9E /* MessageTextViewController.swift in Sources */,
2C1EF36B25505DCE007C9768 /* NCNavigationController.m in Sources */,
1FA38C9029A4B3C6008871B8 /* NCNotificationAction.swift in Sources */,
2C44B4D127FF05A000AD1C86 /* ReactionsSummaryView.swift in Sources */,
Expand Down
12 changes: 11 additions & 1 deletion NextcloudTalk/BaseChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,11 @@ import SwiftUI
NotificationPresenter.shared().present(text: NSLocalizedString("Message link copied", comment: ""), dismissAfterDelay: 5.0, includedStyle: .dark)
}

func didPressCopySelection(for message: NCChatMessage) {
let vc = MessageTextViewController(messageText: message.parsedMessage().string)
self.presentWithNavigation(vc, animated: true)
}

func didPressTranslate(for message: NCChatMessage) {
let translateMessageVC = MessageTranslationViewController(message: message.parsedMessage().string, availableTranslations: NCDatabaseManager.sharedInstance().availableTranslations(forAccountId: self.room.accountId))
self.presentWithNavigation(translateMessageVC, animated: true)
Expand Down Expand Up @@ -3070,10 +3075,15 @@ import SwiftUI
var actions: [UIMenuElement] = []

// Copy option
actions.append(UIAction(title: NSLocalizedString("Copy", comment: ""), image: .init(systemName: "square.on.square")) { _ in
actions.append(UIAction(title: NSLocalizedString("Copy", comment: ""), image: .init(systemName: "doc.on.doc")) { _ in
self.didPressCopy(for: message)
})

// Copy Selection
actions.append(UIAction(title: NSLocalizedString("Copy message selection", comment: ""), image: .init(systemName: "text.viewfinder")) { _ in
self.didPressCopySelection(for: message)
})

// Copy Link
actions.append(UIAction(title: NSLocalizedString("Copy message link", comment: ""), image: .init(systemName: "link")) { _ in
self.didPressCopyLink(for: message)
Expand Down
75 changes: 49 additions & 26 deletions NextcloudTalk/ChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1779,27 +1779,31 @@ import SwiftyAttributes
})
}

// Reply-privately option (only to other users and not in one-to-one)
if self.isMessageReplyable(message: message), self.room.type != .oneToOne, message.actorType == "users", message.actorId != self.account.userId {
actions.append(UIAction(title: NSLocalizedString("Reply privately", comment: ""), image: .init(systemName: "person")) { _ in
self.didPressReplyPrivately(for: message)
})
}

// Forward option (only normal messages for now)
if message.file() == nil, message.poll == nil, !message.isDeletedMessage {
actions.append(UIAction(title: NSLocalizedString("Forward", comment: ""), image: .init(systemName: "arrowshape.turn.up.right")) { _ in
self.didPressForward(for: message)
})
}

// Note to self
if message.file() == nil, message.poll == nil, !message.isDeletedMessage, room.type != .noteToSelf,
NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityNoteToSelf, for: room) {
actions.append(UIAction(title: NSLocalizedString("Note to self", comment: ""), image: .init(systemName: "square.and.pencil")) { _ in
self.didPressNoteToSelf(for: message)
})
}
var copyMenuActions: [UIMenuElement] = []

// Copy option
copyMenuActions.append(UIAction(title: NSLocalizedString("Message", comment: "Copy 'message'"), image: .init(systemName: "doc.text")) { _ in
self.didPressCopy(for: message)
})

// Copy part option
copyMenuActions.append(UIAction(title: NSLocalizedString("Selection", comment: "Copy a 'selection' of a message"), image: .init(systemName: "text.viewfinder")) { _ in
self.didPressCopySelection(for: message)
})

// Copy link option
copyMenuActions.append(UIAction(title: NSLocalizedString("Message link", comment: "Copy 'link' to a message"), image: .init(systemName: "link")) { _ in
self.didPressCopyLink(for: message)
})

actions.append(UIMenu(title: NSLocalizedString("Copy", comment: ""), image: .init(systemName: "doc.on.doc"), children: copyMenuActions))

// Remind me later
if !message.sendingFailed, !message.isOfflineMessage, NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityRemindMeLater, for: room) {
Expand Down Expand Up @@ -1849,18 +1853,6 @@ import SwiftyAttributes
})
}

// Copy option
actions.append(UIAction(title: NSLocalizedString("Copy", comment: ""), image: .init(systemName: "square.on.square")) { _ in
self.didPressCopy(for: message)
})

// Translate
if !self.offlineMode, NCDatabaseManager.sharedInstance().hasAvailableTranslations(forAccountId: self.account.accountId) {
actions.append(UIAction(title: NSLocalizedString("Translate", comment: ""), image: .init(systemName: "character.book.closed")) { _ in
self.didPressTranslate(for: message)
})
}

// Open in nextcloud option
if !self.offlineMode, message.file() != nil {
let openInNextcloudTitle = String(format: NSLocalizedString("Open in %@", comment: ""), filesAppName)
Expand All @@ -1877,6 +1869,37 @@ import SwiftyAttributes
})
}

var moreMenuActions: [UIMenuElement] = []

// Reply-privately option (only to other users and not in one-to-one)
if self.isMessageReplyable(message: message), self.room.type != .oneToOne, message.actorType == "users", message.actorId != self.account.userId {
moreMenuActions.append(UIAction(title: NSLocalizedString("Reply privately", comment: ""), image: .init(systemName: "person")) { _ in
self.didPressReplyPrivately(for: message)
})
}

// Translate
if !self.offlineMode, NCDatabaseManager.sharedInstance().hasAvailableTranslations(forAccountId: self.account.accountId) {
moreMenuActions.append(UIAction(title: NSLocalizedString("Translate", comment: ""), image: .init(systemName: "character.book.closed")) { _ in
self.didPressTranslate(for: message)
})
}

// Note to self
if message.file() == nil, message.poll == nil, !message.isDeletedMessage, room.type != .noteToSelf,
NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityNoteToSelf, for: room) {
moreMenuActions.append(UIAction(title: NSLocalizedString("Note to self", comment: ""), image: .init(systemName: "square.and.pencil")) { _ in
self.didPressNoteToSelf(for: message)
})
}

if moreMenuActions.count == 1, let firstElement = moreMenuActions.first {
// When there's only one element, no need to create a "More" menu
actions.append(firstElement)
} else if !moreMenuActions.isEmpty {
actions.append(UIMenu(title: NSLocalizedString("More", comment: "More menu elements"), children: moreMenuActions))
}

var destructiveMenuActions: [UIMenuElement] = []

// Edit option
Expand Down
41 changes: 41 additions & 0 deletions NextcloudTalk/MessageTextViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
// SPDX-License-Identifier: GPL-3.0-or-later
//

import UIKit
import Foundation
import SwiftyAttributes

@objcMembers class MessageTextViewController: UIViewController {

@IBOutlet public weak var messageTextView: UITextView!

private var messageText = ""

init(messageText: String) {
super.init(nibName: "MessageTextViewController", bundle: nil)

self.messageText = messageText
}

required init?(coder: NSCoder) {
super.init(coder: coder)
}

override func viewDidLoad() {
super.viewDidLoad()

NCAppBranding.styleViewController(self)

self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Close", comment: ""), primaryAction: UIAction { [unowned self] _ in
self.dismiss(animated: true)
})

self.messageTextView.layer.cornerRadius = 8
self.messageTextView.layer.masksToBounds = true
self.messageTextView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
self.messageTextView.text = messageText
}

}
55 changes: 55 additions & 0 deletions NextcloudTalk/MessageTextViewController.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="GithubPermalinkViewController" customModule="NextcloudTalk" customModuleProvider="target">
<connections>
<outlet property="messageTextView" destination="cBP-KD-G41" id="i1n-9c-Aw9"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" layoutManager="textKit1" translatesAutoresizingMaskIntoConstraints="NO" id="cBP-KD-G41" userLabel="MessageTextView">
<rect key="frame" x="10" y="102" width="394" height="750"/>
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="cBP-KD-G41" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="10" id="1kw-8j-kX2"/>
<constraint firstAttribute="trailing" secondItem="cBP-KD-G41" secondAttribute="trailing" constant="10" id="WFu-fW-DVD"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="cBP-KD-G41" secondAttribute="bottom" constant="10" id="aq2-kt-9iz"/>
<constraint firstItem="cBP-KD-G41" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="10" id="jFw-Kg-42l"/>
</constraints>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<point key="canvasLocation" x="82.608695652173921" y="91.741071428571431"/>
</view>
</objects>
<resources>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="secondarySystemBackgroundColor">
<color red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
15 changes: 15 additions & 0 deletions NextcloudTalk/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,9 @@
/* No comment provided by engineer. */
"Copy message link" = "Copy message link";

/* No comment provided by engineer. */
"Copy message selection" = "Copy message selection";

/* No comment provided by engineer. */
"Could not access camera" = "Could not access camera";

Expand Down Expand Up @@ -1174,6 +1177,9 @@
/* 'Mentioned' meaning 'Mentioned conversations' */
"Mentioned" = "Mentioned";

/* Copy 'message' */
"Message" = "Message";

/* No comment provided by engineer. */
"Message copied" = "Message copied";

Expand All @@ -1192,6 +1198,9 @@
/* No comment provided by engineer. */
"Message expiration time" = "Message expiration time";

/* Copy 'link' to a message */
"Message link" = "Message link";

/* No comment provided by engineer. */
"Message link copied" = "Message link copied";

Expand Down Expand Up @@ -1231,6 +1240,9 @@
/* No comment provided by engineer. */
"Modification date" = "Modification date";

/* More menu elements */
"More" = "More";

/* No comment provided by engineer. */
"More actions" = "More actions";

Expand Down Expand Up @@ -1621,6 +1633,9 @@
/* No comment provided by engineer. */
"Select language" = "Select language";

/* Copy a 'selection' of a message */
"Selection" = "Selection";

/* No comment provided by engineer. */
"Send" = "Send";

Expand Down

0 comments on commit 202a727

Please sign in to comment.