-
Notifications
You must be signed in to change notification settings - Fork 11
issue #193 add attachment nodes #295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
661a61d
d623fd8
ae373d5
30b3df3
27b0ac1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "images" : [ | ||
| { | ||
| "idiom" : "universal", | ||
| "scale" : "1x" | ||
| }, | ||
| { | ||
| "filename" : "Light-M.png", | ||
| "idiom" : "universal", | ||
| "scale" : "2x" | ||
| }, | ||
| { | ||
| "idiom" : "universal", | ||
| "scale" : "3x" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,23 @@ | ||
| { | ||
| "images" : [ | ||
| { | ||
| "idiom" : "universal", | ||
| "filename" : "paperclip.png", | ||
| "idiom" : "universal", | ||
| "scale" : "1x" | ||
| }, | ||
| { | ||
| "idiom" : "universal", | ||
| "filename" : "paperclip@2x.png", | ||
| "idiom" : "universal", | ||
| "scale" : "2x" | ||
| }, | ||
| { | ||
| "idiom" : "universal", | ||
| "filename" : "paperclip@3x.png", | ||
| "idiom" : "universal", | ||
| "scale" : "3x" | ||
| } | ||
| ], | ||
| "info" : { | ||
| "version" : 1, | ||
| "author" : "xcode" | ||
| "author" : "xcode", | ||
| "version" : 1 | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,7 @@ final class MessageViewController: TableNodeViewController { | |
| } | ||
|
|
||
| enum Parts: Int, CaseIterable { | ||
| case sender, subject, text | ||
| case sender, subject, text, attachment | ||
|
|
||
| var indexPath: IndexPath { | ||
| IndexPath(row: rawValue, section: 0) | ||
|
|
@@ -53,6 +53,7 @@ final class MessageViewController: TableNodeViewController { | |
| private let messageProvider: MessageProvider | ||
| private let messageOperationsProvider: MessageOperationsProvider | ||
| private var message: NSAttributedString | ||
| private var attachments: [Attachment] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can initiate it here instead of inside init |
||
| private let trashFolderProvider: TrashFolderProviderType | ||
|
|
||
| init( | ||
|
|
@@ -73,6 +74,7 @@ final class MessageViewController: TableNodeViewController { | |
| self.core = core | ||
| self.trashFolderProvider = trashFolderProvider | ||
| self.onCompletion = completion | ||
| self.attachments = [] | ||
| self.message = decorator.attributed( | ||
| text: "loading_title".localized + "...", | ||
| color: .lightGray | ||
|
|
@@ -143,7 +145,7 @@ extension MessageViewController { | |
| self?.message = try awaitPromise(self!.fetchMessage()) | ||
| }.then(on: .main) { [weak self] in | ||
| self?.hideSpinner() | ||
| self?.node.reloadRows(at: [Parts.text.indexPath], with: .fade) | ||
| self?.node.reloadRows(at: [Parts.text.indexPath, Parts.attachment.indexPath], with: .fade) | ||
| self?.asyncMarkAsReadIfNotAlreadyMarked() | ||
| }.catch(on: .main) { [weak self] error in | ||
| self?.hideSpinner() | ||
|
|
@@ -170,6 +172,10 @@ extension MessageViewController { | |
| isEmail: true | ||
| ) | ||
| let decryptErrBlocks = decrypted.blocks.filter { $0.decryptErr != nil } | ||
| let decryptAttBlocks = decrypted.blocks.filter { $0.type == .plainAtt || $0.type == .encryptedAtt || $0.type == .decryptedAtt } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to have some computed property for MsgBlock and cover it with tests(not in scope of this PR)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be called |
||
|
|
||
| let attachments = decryptAttBlocks.map { Attachment(name: $0.attMeta?.name ?? "Attachment", size: $0.attMeta?.length ?? 0) } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same for Attachment. You can have and then it can be just this solution is more flexible and can be tested easily. |
||
| self.attachments = attachments | ||
|
|
||
| let message: NSAttributedString | ||
| if let decryptErrBlock = decryptErrBlocks.first { | ||
|
|
@@ -242,6 +248,10 @@ extension MessageViewController { | |
| showToast("Marking as unread will be implemented soon") | ||
| } | ||
|
|
||
| @objc private func handleAttachmentTap() { | ||
| showToast("Downloading attachments is not implemented yet") | ||
| } | ||
|
|
||
| @objc private func handleTrashTap() { | ||
| showSpinner() | ||
|
|
||
|
|
@@ -377,6 +387,10 @@ extension MessageViewController: ASTableDelegate, ASTableDataSource { | |
| return MessageSubjectNode(subject, time: time) | ||
| case .text: | ||
| return MessageTextSubjectNode(self.message) | ||
| case .attachment: | ||
| return AttachmentsNode(attachments: self.attachments) { [weak self] in | ||
| self?.handleAttachmentTap() | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| // | ||
| // AttachmentNode.swift | ||
| // FlowCryptUI | ||
| // | ||
| // Created by QSD BiH on 16. 4. 2021.. | ||
| // Copyright © 2021 FlowCrypt Limited. All rights reserved. | ||
| // | ||
|
|
||
| import AsyncDisplayKit | ||
|
|
||
| public struct Attachment { | ||
| var name, size: String | ||
|
|
||
| public init( | ||
| name: String, | ||
| size: Int | ||
| ) { | ||
| self.name = name | ||
| self.size = ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file) | ||
| } | ||
| } | ||
|
|
||
| public final class AttachmentsNode: CellNode { | ||
| public struct Input { | ||
| let name: String | ||
| let size: String | ||
|
|
||
| public init( | ||
| name: String, | ||
| size: String | ||
| ) { | ||
| self.name = name | ||
| self.size = size | ||
| } | ||
| } | ||
|
|
||
| private var attachmentNodes: [AttachmentNode] = [] | ||
| private var onTap: (() -> Void)? | ||
|
|
||
| public init(attachments: [Attachment], onTap: (() -> Void)?) { | ||
| super.init() | ||
| self.onTap = onTap | ||
| attachmentNodes = attachments.map { AttachmentNode(input: AttachmentNode.Input(name: $0.name, size: $0.size), | ||
| onTap: { | ||
| self.onTap?() | ||
| }) | ||
| } | ||
|
Comment on lines
+43
to
+47
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please change indentation here? hard for understanding
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can xcode be set to indent automatically on save?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have a script for that. Will check if it's possible to indent code during build phase. |
||
| } | ||
|
|
||
| public override func layoutSpecThatFits(_: ASSizeRange) -> ASLayoutSpec { | ||
| return ASInsetLayoutSpec( | ||
| insets: UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8), | ||
| child: ASStackLayoutSpec( | ||
| direction: .vertical, | ||
| spacing: 8, | ||
| justifyContent: .start, | ||
| alignItems: .stretch, | ||
| children: attachmentNodes)) | ||
| } | ||
| } | ||
|
|
||
| public final class AttachmentNode: CellNode { | ||
| public struct Input { | ||
| var name, size: String | ||
| } | ||
|
|
||
| private let titleNode = ASTextNode() | ||
| private let subtitleNode = ASTextNode2() | ||
| private let imageNode = ASImageNode() | ||
| private let buttonNode = ASButtonNode() | ||
|
|
||
| private var onTap: (() -> Void)? | ||
|
|
||
| public init(input: Input, onTap: (() -> Void)?) { | ||
| super.init() | ||
| self.onTap = onTap | ||
|
|
||
| self.borderWidth = 1.0 | ||
| self.cornerRadius = 8.0 | ||
| self.borderColor = UIColor.lightGray.cgColor | ||
|
|
||
| imageNode.tintColor = .gray | ||
| buttonNode.tintColor = .gray | ||
|
|
||
| imageNode.image = UIImage(named: "paperclip")?.tinted(.gray) | ||
| buttonNode.setImage(UIImage(named: "download")?.tinted(.gray), for: .normal) | ||
| buttonNode.addTarget(self, action: #selector(tapHandle), forControlEvents: .touchUpInside) | ||
| titleNode.attributedText = NSAttributedString.text(from: input.name, style: .regular(18), color: .gray, alignment: .left) | ||
| subtitleNode.attributedText = NSAttributedString.text(from: input.size, style: .medium(12), color: .gray, alignment: .left) | ||
| } | ||
|
|
||
| public override func layoutSpecThatFits(_: ASSizeRange) -> ASLayoutSpec { | ||
| let verticalStack = ASStackLayoutSpec.vertical() | ||
| verticalStack.spacing = 3 | ||
| verticalStack.style.flexShrink = 1.0 | ||
| verticalStack.style.flexGrow = 1.0 | ||
|
|
||
| verticalStack.children = [titleNode, subtitleNode] | ||
|
|
||
| let finalSpec = ASStackLayoutSpec( | ||
| direction: .horizontal, | ||
| spacing: 10, | ||
| justifyContent: .start, | ||
| alignItems: .center, | ||
| children: [imageNode, verticalStack, buttonNode] | ||
| ) | ||
|
|
||
| return ASInsetLayoutSpec( | ||
| insets: UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20), | ||
| child: finalSpec | ||
| ) | ||
| } | ||
|
|
||
| @objc private func tapHandle() { | ||
| onTap?() | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.