mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge branch 'dev' of https://github.com/oxen-io/session-ios into preformance-improvement
This commit is contained in:
commit
7e92391740
13 changed files with 129 additions and 81 deletions
|
@ -10,6 +10,16 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
|||
ConversationTitleViewDelegate {
|
||||
|
||||
func handleTitleViewTapped() {
|
||||
// Don't take the user to settings for message requests
|
||||
guard
|
||||
let contactThread: TSContactThread = thread as? TSContactThread,
|
||||
let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()),
|
||||
contact.isApproved,
|
||||
contact.didApproveMe
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
openSettings()
|
||||
}
|
||||
|
||||
|
@ -292,32 +302,56 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
|||
|
||||
func sendAttachments(_ attachments: [SignalAttachment], with text: String, onComplete: (() -> ())? = nil) {
|
||||
guard !showBlockedModalIfNeeded() else { return }
|
||||
|
||||
for attachment in attachments {
|
||||
if attachment.hasError {
|
||||
return showErrorAlert(for: attachment, onDismiss: onComplete)
|
||||
}
|
||||
}
|
||||
|
||||
let thread = self.thread
|
||||
let sentTimestamp: UInt64 = NSDate.millisecondTimestamp()
|
||||
let message = VisibleMessage()
|
||||
message.sentTimestamp = NSDate.millisecondTimestamp()
|
||||
message.sentTimestamp = sentTimestamp
|
||||
message.text = replaceMentions(in: text)
|
||||
|
||||
// Note: 'shouldBeVisible' is set to true the first time a thread is saved so we can
|
||||
// use it to determine if the user is creating a new thread and update the 'isApproved'
|
||||
// flags appropriately
|
||||
let oldThreadShouldBeVisible: Bool = thread.shouldBeVisible
|
||||
let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread)
|
||||
Storage.write(with: { transaction in
|
||||
tsMessage.save(with: transaction)
|
||||
// The new message cell is inserted at this point, but the TSOutgoingMessage doesn't have its attachment yet
|
||||
}, completion: { [weak self] in
|
||||
Storage.write(with: { transaction in
|
||||
MessageSender.send(message, with: attachments, in: thread, using: transaction)
|
||||
}, completion: { [weak self] in
|
||||
// At this point the TSOutgoingMessage should have its attachments set, so we can scroll to the bottom knowing
|
||||
// the height of the new message cell
|
||||
self?.scrollToBottom(isAnimated: false)
|
||||
})
|
||||
self?.handleMessageSent()
|
||||
|
||||
// Attachment successfully sent - dismiss the screen
|
||||
onComplete?()
|
||||
})
|
||||
|
||||
Storage.write(
|
||||
with: { transaction in
|
||||
tsMessage.save(with: transaction)
|
||||
// The new message cell is inserted at this point, but the TSOutgoingMessage doesn't have its attachment yet
|
||||
},
|
||||
completion: { [weak self] in
|
||||
Storage.shared.write(
|
||||
with: { transaction in
|
||||
self?.approveMessageRequestIfNeeded(
|
||||
for: self?.thread,
|
||||
with: (transaction as! YapDatabaseReadWriteTransaction),
|
||||
isNewThread: !oldThreadShouldBeVisible,
|
||||
timestamp: (sentTimestamp - 1) // Set 1ms earlier as this is used for sorting
|
||||
)
|
||||
},
|
||||
completion: { [weak self] in
|
||||
Storage.write(with: { transaction in
|
||||
MessageSender.send(message, with: attachments, in: thread, using: transaction)
|
||||
}, completion: { [weak self] in
|
||||
// At this point the TSOutgoingMessage should have its attachments set, so we can scroll to the bottom knowing
|
||||
// the height of the new message cell
|
||||
self?.scrollToBottom(isAnimated: false)
|
||||
})
|
||||
self?.handleMessageSent()
|
||||
|
||||
// Attachment successfully sent - dismiss the screen
|
||||
onComplete?()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
func handleMessageSent() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import SessionUIKit
|
||||
import SessionMessagingKit
|
||||
import UIKit
|
||||
|
||||
// TODO:
|
||||
// • Slight paging glitch when scrolling up and loading more content
|
||||
|
@ -461,30 +462,47 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
// MARK: Updating
|
||||
|
||||
func updateNavBarButtons() {
|
||||
navigationItem.hidesBackButton = isShowingSearchUI
|
||||
|
||||
if isShowingSearchUI {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
navigationItem.rightBarButtonItems = []
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
navigationItem.leftBarButtonItem = UIViewController.createOWSBackButton(withTarget: self, selector: #selector(handleBackPressed))
|
||||
|
||||
let rightBarButtonItem: UIBarButtonItem
|
||||
if thread is TSContactThread {
|
||||
let size = Values.verySmallProfilePictureSize
|
||||
let profilePictureView = ProfilePictureView()
|
||||
profilePictureView.accessibilityLabel = "Settings button"
|
||||
profilePictureView.size = size
|
||||
profilePictureView.update(for: thread)
|
||||
profilePictureView.set(.width, to: size)
|
||||
profilePictureView.set(.height, to: size)
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
|
||||
profilePictureView.addGestureRecognizer(tapGestureRecognizer)
|
||||
rightBarButtonItem = UIBarButtonItem(customView: profilePictureView)
|
||||
} else {
|
||||
rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings))
|
||||
if let contactThread: TSContactThread = thread as? TSContactThread {
|
||||
// Don't show the settings button for message requests
|
||||
if let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()), contact.isApproved, contact.didApproveMe {
|
||||
let size = Values.verySmallProfilePictureSize
|
||||
let profilePictureView = ProfilePictureView()
|
||||
profilePictureView.size = size
|
||||
profilePictureView.update(for: thread)
|
||||
profilePictureView.set(.width, to: size)
|
||||
profilePictureView.set(.height, to: size)
|
||||
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
|
||||
profilePictureView.addGestureRecognizer(tapGestureRecognizer)
|
||||
|
||||
let rightBarButtonItem: UIBarButtonItem = UIBarButtonItem(customView: profilePictureView)
|
||||
rightBarButtonItem.accessibilityLabel = "Settings button"
|
||||
rightBarButtonItem.isAccessibilityElement = true
|
||||
|
||||
navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||
}
|
||||
else {
|
||||
// Note: Adding an empty button because without it the title alignment is busted (Note: The size was
|
||||
// taken from the layout inspector for the back button in Xcode
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: UIView(frame: CGRect(x: 0, y: 0, width: 37, height: 44)))
|
||||
}
|
||||
}
|
||||
else {
|
||||
let rightBarButtonItem: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings))
|
||||
rightBarButtonItem.accessibilityLabel = "Settings button"
|
||||
rightBarButtonItem.isAccessibilityElement = true
|
||||
|
||||
navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||
}
|
||||
rightBarButtonItem.accessibilityLabel = "Settings button"
|
||||
rightBarButtonItem.isAccessibilityElement = true
|
||||
navigationItem.rightBarButtonItem = rightBarButtonItem
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -806,7 +824,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
let searchBar = searchController.uiSearchController.searchBar
|
||||
searchBar.searchBarStyle = .minimal
|
||||
searchBar.barStyle = .black
|
||||
searchBar.tintColor = Colors.accent
|
||||
searchBar.tintColor = Colors.text
|
||||
let searchIcon = UIImage(named: "searchbar_search")!.asTintedImage(color: Colors.searchBarPlaceholder)
|
||||
searchBar.setImage(searchIcon, for: .search, state: UIControl.State.normal)
|
||||
let clearIcon = UIImage(named: "searchbar_clear")!.asTintedImage(color: Colors.searchBarPlaceholder)
|
||||
|
|
|
@ -277,7 +277,7 @@ CGFloat kIconViewLength = 24;
|
|||
contents.title = NSLocalizedString(@"CONVERSATION_SETTINGS", @"title for conversation settings screen");
|
||||
|
||||
BOOL isNoteToSelf = self.thread.isNoteToSelf;
|
||||
|
||||
|
||||
__weak OWSConversationSettingsViewController *weakSelf = self;
|
||||
|
||||
OWSTableSection *section = [OWSTableSection new];
|
||||
|
@ -332,7 +332,7 @@ CGFloat kIconViewLength = 24;
|
|||
} actionBlock:^{
|
||||
[weakSelf tappedConversationSearch];
|
||||
}]];
|
||||
|
||||
|
||||
// Disappearing messages
|
||||
if (![self isOpenGroup]) {
|
||||
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
|
@ -358,13 +358,6 @@ CGFloat kIconViewLength = 24;
|
|||
switchView.on = strongSelf.disappearingMessagesConfiguration.isEnabled;
|
||||
[switchView addTarget:strongSelf action:@selector(disappearingMessagesSwitchValueDidChange:)
|
||||
forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
// Disable Disappearing Messages if the conversation hasn't been approved
|
||||
if (!self.thread.isGroupThread) {
|
||||
TSContactThread *thread = (TSContactThread *)self.thread;
|
||||
SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID];
|
||||
[switchView setEnabled:(contact.isApproved && contact.didApproveMe)];
|
||||
}
|
||||
|
||||
UIStackView *topRow =
|
||||
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]];
|
||||
|
@ -438,13 +431,6 @@ CGFloat kIconViewLength = 24;
|
|||
[slider autoPinTrailingToSuperviewMargin];
|
||||
[slider autoPinBottomToSuperviewMargin];
|
||||
|
||||
// Disable Disappearing Messages slider if the conversation hasn't been approved (just in case)
|
||||
if (!self.thread.isGroupThread) {
|
||||
TSContactThread *thread = (TSContactThread *)self.thread;
|
||||
SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID];
|
||||
[slider setEnabled:(contact.isApproved && contact.didApproveMe)];
|
||||
}
|
||||
|
||||
cell.userInteractionEnabled = !strongSelf.hasLeftGroup;
|
||||
|
||||
cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME(
|
||||
|
|
|
@ -73,13 +73,17 @@ final class ConversationTitleView : UIView {
|
|||
private func getTitle() -> String {
|
||||
if let thread = thread as? TSGroupThread {
|
||||
return thread.groupModel.groupName!
|
||||
} else if thread.isNoteToSelf() {
|
||||
}
|
||||
else if thread.isNoteToSelf() {
|
||||
return "Note to Self"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
let sessionID = (thread as! TSContactThread).contactSessionID()
|
||||
var result = sessionID
|
||||
Storage.read { transaction in
|
||||
result = Storage.shared.getContact(with: sessionID)?.displayName(for: .regular) ?? "Anonymous"
|
||||
let displayName: String = ((Storage.shared.getContact(with: sessionID)?.displayName(for: .regular)) ?? sessionID)
|
||||
let middleTruncatedHexKey: String = "\(sessionID.prefix(4))...\(sessionID.suffix(4))"
|
||||
result = (displayName == sessionID ? middleTruncatedHexKey : displayName)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -403,11 +403,13 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
|
|||
profilePictureViewContainer.addSubview(pathStatusView)
|
||||
pathStatusView.pin(.trailing, to: .trailing, of: profilePictureViewContainer)
|
||||
pathStatusView.pin(.bottom, to: .bottom, of: profilePictureViewContainer)
|
||||
|
||||
// Left bar button item
|
||||
let leftBarButtonItem = UIBarButtonItem(customView: profilePictureViewContainer)
|
||||
leftBarButtonItem.accessibilityLabel = "Settings button"
|
||||
leftBarButtonItem.isAccessibilityElement = true
|
||||
navigationItem.leftBarButtonItem = leftBarButtonItem
|
||||
|
||||
// Right bar button item - search button
|
||||
let rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(showSearchUI))
|
||||
rightBarButtonItem.accessibilityLabel = "Search button"
|
||||
|
|
|
@ -63,23 +63,16 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
|
|||
return result
|
||||
}()
|
||||
|
||||
private lazy var clearAllButton: UIButton = {
|
||||
let result: UIButton = UIButton()
|
||||
private lazy var clearAllButton: Button = {
|
||||
let result: Button = Button(style: .destructiveOutline, size: .large)
|
||||
result.translatesAutoresizingMaskIntoConstraints = false
|
||||
result.clipsToBounds = true
|
||||
result.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
|
||||
result.setTitle(NSLocalizedString("MESSAGE_REQUESTS_CLEAR_ALL", comment: ""), for: .normal)
|
||||
result.setTitleColor(Colors.destructive, for: .normal)
|
||||
result.setBackgroundImage(
|
||||
Colors.destructive
|
||||
.withAlphaComponent(isDarkMode ? 0.2 : 0.06)
|
||||
.toImage(isDarkMode: isDarkMode),
|
||||
for: .highlighted
|
||||
)
|
||||
result.isHidden = true
|
||||
result.layer.cornerRadius = (NewConversationButtonSet.collapsedButtonSize / 2)
|
||||
result.layer.borderColor = Colors.destructive.cgColor
|
||||
result.layer.borderWidth = 1.5
|
||||
result.addTarget(self, action: #selector(clearAllTapped), for: .touchUpInside)
|
||||
|
||||
return result
|
||||
|
@ -163,10 +156,11 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
|
|||
|
||||
clearAllButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
clearAllButton.bottomAnchor.constraint(
|
||||
equalTo: view.bottomAnchor,
|
||||
constant: -Values.newConversationButtonBottomOffset // Negative due to how the constraint is set up
|
||||
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
|
||||
constant: -Values.largeSpacing
|
||||
),
|
||||
clearAllButton.widthAnchor.constraint(equalToConstant: 155),
|
||||
// Note: The '182' is to match the 'Next' button on the New DM page (which doesn't have a fixed width)
|
||||
clearAllButton.widthAnchor.constraint(equalToConstant: 182),
|
||||
clearAllButton.heightAnchor.constraint(equalToConstant: NewConversationButtonSet.collapsedButtonSize)
|
||||
])
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ class MessageRequestsCell: UITableViewCell {
|
|||
}()
|
||||
|
||||
private func setUpViewHierarchy() {
|
||||
backgroundColor = Colors.cellBackground
|
||||
backgroundColor = Colors.cellPinned
|
||||
selectedBackgroundView = UIView()
|
||||
selectedBackgroundView?.backgroundColor = Colors.cellSelected
|
||||
|
||||
|
|
|
@ -139,9 +139,6 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
|
|||
setUpNavBarStyle()
|
||||
setNavBarTitle(NSLocalizedString("vc_settings_title", comment: ""))
|
||||
// Navigation bar buttons
|
||||
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
|
||||
backButton.tintColor = Colors.text
|
||||
navigationItem.backBarButtonItem = backButton
|
||||
updateNavigationBarButtons()
|
||||
// Profile picture view
|
||||
let profilePictureTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showEditProfilePictureUI))
|
||||
|
@ -254,8 +251,6 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
|
|||
pathStatusView.pin(.leading, to: .trailing, of: pathButton.titleLabel!, withInset: Values.smallSpacing)
|
||||
pathStatusView.autoVCenterInSuperview()
|
||||
|
||||
pathButton.titleEdgeInsets = UIEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: Values.smallSpacing)
|
||||
|
||||
return [
|
||||
getSeparator(),
|
||||
pathButton,
|
||||
|
|
|
@ -46,6 +46,7 @@ class BaseVC : UIViewController {
|
|||
|
||||
internal func setUpNavBarStyle() {
|
||||
guard let navigationBar = navigationController?.navigationBar else { return }
|
||||
|
||||
if #available(iOS 15.0, *) {
|
||||
let appearance = UINavigationBarAppearance()
|
||||
appearance.configureWithOpaqueBackground()
|
||||
|
@ -59,6 +60,11 @@ class BaseVC : UIViewController {
|
|||
navigationBar.isTranslucent = false
|
||||
navigationBar.barTintColor = Colors.navigationBarBackground
|
||||
}
|
||||
|
||||
// Back button (to appear on pushed screen)
|
||||
let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
||||
backButton.tintColor = Colors.text
|
||||
navigationItem.backBarButtonItem = backButton
|
||||
}
|
||||
|
||||
internal func setNavBarTitle(_ title: String, customFontSize: CGFloat? = nil) {
|
||||
|
|
|
@ -359,15 +359,20 @@ final class ConversationCell : UITableViewCell {
|
|||
if threadViewModel.isGroupThread {
|
||||
if threadViewModel.name.isEmpty {
|
||||
return "Unknown Group"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return threadViewModel.name
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if threadViewModel.threadRecord.isNoteToSelf() {
|
||||
return NSLocalizedString("NOTE_TO_SELF", comment: "")
|
||||
} else {
|
||||
let hexEncodedPublicKey = threadViewModel.contactSessionID!
|
||||
return Storage.shared.getContact(with: hexEncodedPublicKey)?.displayName(for: .regular) ?? hexEncodedPublicKey
|
||||
}
|
||||
else {
|
||||
let hexEncodedPublicKey: String = threadViewModel.contactSessionID!
|
||||
let displayName: String = (Storage.shared.getContact(with: hexEncodedPublicKey)?.displayName(for: .regular) ?? hexEncodedPublicKey)
|
||||
let middleTruncatedHexKey: String = "\(hexEncodedPublicKey.prefix(4))...\(hexEncodedPublicKey.suffix(4))"
|
||||
return (displayName == hexEncodedPublicKey ? middleTruncatedHexKey : displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,7 +117,8 @@ public final class OpenGroupManagerV2 : NSObject {
|
|||
// https://143.198.213.225:443/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c
|
||||
// 143.198.213.255:80/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c
|
||||
let useTLS = (url.scheme == "https")
|
||||
let room = String(url.path.dropFirst()) // Drop the leading slash
|
||||
let updatedPath = (url.path.starts(with: "/r/") ? url.path.substring(from: 2) : url.path)
|
||||
let room = String(updatedPath.dropFirst()) // Drop the leading slash
|
||||
let queryParts = query.split(separator: "=")
|
||||
guard !room.isEmpty && !room.contains("/"), queryParts.count == 2, queryParts[0] == "public_key" else { return nil }
|
||||
let publicKey = String(queryParts[1])
|
||||
|
|
|
@ -6,7 +6,7 @@ public final class Button : UIButton {
|
|||
private var heightConstraint: NSLayoutConstraint!
|
||||
|
||||
public enum Style {
|
||||
case unimportant, regular, prominentOutline, prominentFilled, regularBorderless
|
||||
case unimportant, regular, prominentOutline, prominentFilled, regularBorderless, destructiveOutline
|
||||
}
|
||||
|
||||
public enum Size {
|
||||
|
@ -41,6 +41,7 @@ public final class Button : UIButton {
|
|||
case .prominentOutline: fillColor = UIColor.clear
|
||||
case .prominentFilled: fillColor = isLightMode ? Colors.text : Colors.accent
|
||||
case .regularBorderless: fillColor = UIColor.clear
|
||||
case .destructiveOutline: fillColor = UIColor.clear
|
||||
}
|
||||
let borderColor: UIColor
|
||||
switch style {
|
||||
|
@ -49,6 +50,7 @@ public final class Button : UIButton {
|
|||
case .prominentOutline: borderColor = isLightMode ? Colors.text : Colors.accent
|
||||
case .prominentFilled: borderColor = isLightMode ? Colors.text : Colors.accent
|
||||
case .regularBorderless: borderColor = UIColor.clear
|
||||
case .destructiveOutline: borderColor = Colors.destructive
|
||||
}
|
||||
let textColor: UIColor
|
||||
switch style {
|
||||
|
@ -57,6 +59,7 @@ public final class Button : UIButton {
|
|||
case .prominentOutline: textColor = isLightMode ? Colors.text : Colors.accent
|
||||
case .prominentFilled: textColor = isLightMode ? UIColor.white : Colors.text
|
||||
case .regularBorderless: textColor = Colors.text
|
||||
case .destructiveOutline: textColor = Colors.destructive
|
||||
}
|
||||
let height: CGFloat
|
||||
switch size {
|
||||
|
|
|
@ -28,7 +28,7 @@ public final class ViewControllerUtilities : NSObject {
|
|||
}
|
||||
// Set up back button
|
||||
if hasCustomBackButton {
|
||||
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
|
||||
let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
||||
backButton.tintColor = Colors.text
|
||||
vc.navigationItem.backBarButtonItem = backButton
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue