Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed Privitty.framework.zip
Binary file not shown.
15 changes: 15 additions & 0 deletions deltachat-ios/Assets.xcassets/download.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "download.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
15 changes: 15 additions & 0 deletions deltachat-ios/Assets.xcassets/forward.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "forward.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
15 changes: 15 additions & 0 deletions deltachat-ios/Assets.xcassets/no_download.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "no_download.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
15 changes: 15 additions & 0 deletions deltachat-ios/Assets.xcassets/no_forward.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "no_forward.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Binary file not shown.
96 changes: 4 additions & 92 deletions deltachat-ios/Chat/ChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1250,76 +1250,6 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate {
present(alert, animated: true, completion: nil)
}

private func showRevokeAccessDialog(for message: DcMsg) {
guard message.isFromCurrentSender, let filePath = message.file else {
logger.warning("Cannot revoke access: message is not from current sender or has no file")
return
}

let alert = UIAlertController(
title: String.localized("revoke_access_title"),
message: String.localized("revoke_access_message"),
preferredStyle: .alert
)

alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel))

alert.addAction(UIAlertAction(title: String.localized("revoke_access_title"), style: .destructive) { [weak self] _ in
guard let self else { return }

DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let self else { return }

let chatIdString = String(self.chatId)
let result = PrvContext.shared.processInitAccessRevokeRequest(
chatId: chatIdString,
filePath: filePath,
reason: "Access revoked by owner"
)

DispatchQueue.main.async { [weak self] in
guard let self else { return }

if result.success {
// Send the PDU message if we have one
if let data = result.data, let pdu = data["pdu"] as? String {
logger.info("Sending revoke PDU to chat \(self.chatId)")
let responseMsg = self.dcContext.newMessage(viewType: DC_MSG_TEXT)
responseMsg.text = pdu
self.dcContext.sendMessage(chatId: self.chatId, message: responseMsg)
}

// Show success message
let successMessage = result.message ?? String.localized("revoke_access_success")
let successAlert = UIAlertController(
title: nil,
message: successMessage,
preferredStyle: .alert
)
successAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default))
self.present(successAlert, animated: true)

logger.info("Access revoked successfully for file: \(filePath)")
} else {
// Show error message
let errorMessage = result.error ?? String.localized("revoke_access_failed")
let errorAlert = UIAlertController(
title: String.localized("revoke_access_failed"),
message: errorMessage,
preferredStyle: .alert
)
errorAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default))
self.present(errorAlert, animated: true)

logger.error("Failed to revoke access: \(errorMessage)")
}
}
}
})

present(alert, animated: true)
}

private func onMultipleSaveOrUnsave(doSave: Bool) {
guard let rows = tableView.indexPathsForSelectedRows else { return }
let msgIds = rows.compactMap { messageIds[$0.row] }
Expand Down Expand Up @@ -2192,11 +2122,6 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate {
Utils.share(message: dcContext.getMessage(id: msgId), parentViewController: self, sourceView: view)
}

private func revokeAccessSingle(_ msgId: Int) {
let message = dcContext.getMessage(id: msgId)
showRevokeAccessDialog(for: message)
}

private func resendSingle(_ msgId: Int) {
dcContext.resendMessages(msgIds: [msgId])
}
Expand Down Expand Up @@ -2476,22 +2401,6 @@ extension ChatViewController {
if message.file != nil {
// DISABLED: Share option
// moreOptions.append(UIAction.menuAction(localizationKey: "menu_share", systemImageName: "square.and.arrow.up", with: messageId, action: shareSingle))

// Add Revoke Access option for outgoing Privitty files
if message.isFromCurrentSender && message.file != nil {
let filePath = message.file ?? ""
if filePath.hasSuffix(".prv") {
moreOptions.append(
UIAction.menuAction(
localizationKey: "menu_revoke_access",
attributes: [.destructive],
systemImageName: "slash.circle",
with: messageId,
action: revokeAccessSingle
)
)
}
}
}

children.append(
Expand Down Expand Up @@ -2889,13 +2798,16 @@ extension ChatViewController: BaseMessageCellDelegate {
let fileName = message.filename ?? "Unknown"

// Open File Access Control screen (full page, matches Android)
// Peer 2 (recipient) when file was received from someone else; Peer 1 (owner) when we sent/shared the file.
logger.info("Opening File Access Control for file: \(fileName)")
let isPeer2Mode = !message.isFromCurrentSender
let fileAccessVC = FileAccessControlViewController(
chatId: chatId,
filePath: filePath,
fileName: fileName,
msgId: message.id,
dcContext: dcContext
dcContext: dcContext,
isPeer2Mode: isPeer2Mode
)

// Push onto navigation stack for full-page presentation
Expand Down
5 changes: 2 additions & 3 deletions deltachat-ios/Chat/Views/Cells/FileTextCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,8 @@ public class FileTextCell: BaseMessageCell, ReusableCell {

public func applyFileAccessStatus(_ status: PrvContext.FileAccessStatusData?, message: DcMsg) {
fileAccessStatusData = status
// Update parent's fileAccessStatus property for status icon display
// This MUST be set before update() is called
fileAccessStatus = status?.status
let displayStatus: PrvContext.FileAccessStatus? = (message.isFromCurrentSender && status?.status == .revoked) ? .active : status?.status
fileAccessStatus = displayStatus
fileView.configure(message: message, status: status)
}

Expand Down
18 changes: 10 additions & 8 deletions deltachat-ios/Chat/Views/FileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ public class FileView: UIView {
let hideBellForForwarder = isOutgoing && isForwarded
var hasPendingRequests = false


let displayStatus: PrvContext.FileAccessStatus = (message.isFromCurrentSender && status?.status == .revoked) ? .active : (status?.status ?? .active)

if let status = status {
// Check for WAITING_OWNER_ACTION in direct shared_info
let isWaitingOwnerAction = (status.status == .waitingOwnerAction)
Expand All @@ -322,25 +325,24 @@ public class FileView: UIView {
// Red badge: Only show when there are pending WAITING_OWNER_ACTION requests
notificationBadge.isHidden = !hasPendingRequests

// Apply colors based on access status
if let status = status {
currentStatus = status.status
applyColors(for: status.status)
currentStatus = displayStatus
applyColors(for: displayStatus)

// Show "Access Until" label with expiry date
if let expiryTime = status.expiryTime, status.status == .active {
if let expiryTime = status.expiryTime, displayStatus == .active {
accessUntilLabel.text = "Access Until: \(formatExpiryDate(expiryTime))"
accessUntilLabel.isHidden = false
} else if status.status == .expired, let expiryTime = status.expiryTime {
} else if displayStatus == .expired, let expiryTime = status.expiryTime {
accessUntilLabel.text = "Expired: \(formatExpiryDate(expiryTime))"
accessUntilLabel.isHidden = false
} else if status.status == .requested || status.status == .waitingOwnerAction {
} else if displayStatus == .requested || displayStatus == .waitingOwnerAction {
accessUntilLabel.text = "Requesting access..."
accessUntilLabel.isHidden = false
} else if status.status == .denied {
} else if displayStatus == .denied {
accessUntilLabel.text = "Access denied"
accessUntilLabel.isHidden = false
} else if status.status == .revoked {
} else if displayStatus == .revoked {
accessUntilLabel.text = "Access revoked"
accessUntilLabel.isHidden = false
} else {
Expand Down
Loading
Loading