IOS-476 basic code for providing identity images
authorDirk Zimmermann <dirk@pep-project.org>
Thu, 23 Mar 2017 14:03:56 +0100
changeset 190664338c65fa64
parent 1905 1334caddb4ee
child 1907 db508c355810
IOS-476 basic code for providing identity images
pEpForiOS.xcodeproj/project.pbxproj
pEpForiOS/UI/EmailDisplay/EmailListViewCell.swift
pEpForiOS/UI/EmailDisplay/EmailListViewController.swift
pEpForiOS/UI/EmailDisplay/Util/IdentityImageOperation.swift
pEpForiOS/UI/EmailDisplay/Util/IdentityImageProvider.swift
     1.1 --- a/pEpForiOS.xcodeproj/project.pbxproj	Thu Mar 23 11:14:33 2017 +0100
     1.2 +++ b/pEpForiOS.xcodeproj/project.pbxproj	Thu Mar 23 14:03:56 2017 +0100
     1.3 @@ -65,6 +65,8 @@
     1.4  		432198E81DF6B51B00318A74 /* LoginImapOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432198E71DF6B51B00318A74 /* LoginImapOperation.swift */; };
     1.5  		432198ED1DF6B66800318A74 /* SharedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432198EC1DF6B66800318A74 /* SharedObjects.swift */; };
     1.6  		4323FE861E83D6FF006785E1 /* ImapFolderBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4323FE851E83D6FF006785E1 /* ImapFolderBuilder.swift */; };
     1.7 +		4323FE891E83E517006785E1 /* IdentityImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4323FE881E83E517006785E1 /* IdentityImageProvider.swift */; };
     1.8 +		4323FE8B1E83E5E6006785E1 /* IdentityImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4323FE8A1E83E5E6006785E1 /* IdentityImageOperation.swift */; };
     1.9  		43264E9B1D76B7110098DCAC /* SyncFlagsToServerOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43264E9A1D76B7110098DCAC /* SyncFlagsToServerOperation.swift */; };
    1.10  		432A24D71DE714A200DAAC5C /* MessagePantomimeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432A24D61DE714A200DAAC5C /* MessagePantomimeTests.swift */; };
    1.11  		432F7D611D2102F10094F097 /* PEPSessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432F7D601D2102F10094F097 /* PEPSessionTest.swift */; };
    1.12 @@ -287,6 +289,8 @@
    1.13  		432198E71DF6B51B00318A74 /* LoginImapOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginImapOperation.swift; sourceTree = "<group>"; };
    1.14  		432198EC1DF6B66800318A74 /* SharedObjects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedObjects.swift; sourceTree = "<group>"; };
    1.15  		4323FE851E83D6FF006785E1 /* ImapFolderBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImapFolderBuilder.swift; sourceTree = "<group>"; };
    1.16 +		4323FE881E83E517006785E1 /* IdentityImageProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityImageProvider.swift; sourceTree = "<group>"; };
    1.17 +		4323FE8A1E83E5E6006785E1 /* IdentityImageOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityImageOperation.swift; sourceTree = "<group>"; };
    1.18  		43264E9A1D76B7110098DCAC /* SyncFlagsToServerOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncFlagsToServerOperation.swift; sourceTree = "<group>"; };
    1.19  		432A24D61DE714A200DAAC5C /* MessagePantomimeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePantomimeTests.swift; sourceTree = "<group>"; };
    1.20  		432F7D601D2102F10094F097 /* PEPSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PEPSessionTest.swift; sourceTree = "<group>"; };
    1.21 @@ -610,6 +614,15 @@
    1.22  			path = AccountsAndFolders;
    1.23  			sourceTree = "<group>";
    1.24  		};
    1.25 +		4323FE871E83E502006785E1 /* Util */ = {
    1.26 +			isa = PBXGroup;
    1.27 +			children = (
    1.28 +				4323FE8A1E83E5E6006785E1 /* IdentityImageOperation.swift */,
    1.29 +				4323FE881E83E517006785E1 /* IdentityImageProvider.swift */,
    1.30 +			);
    1.31 +			path = Util;
    1.32 +			sourceTree = "<group>";
    1.33 +		};
    1.34  		437432061CFC49A4000F8D35 /* Util */ = {
    1.35  			isa = PBXGroup;
    1.36  			children = (
    1.37 @@ -869,6 +882,7 @@
    1.38  		43ED53621CC77F95006AB156 /* EmailDisplay */ = {
    1.39  			isa = PBXGroup;
    1.40  			children = (
    1.41 +				4323FE871E83E502006785E1 /* Util */,
    1.42  				220DCE281E0AB4DE002FE716 /* Cells */,
    1.43  				220DCE2D1E0AB544002FE716 /* MessageData.plist */,
    1.44  				43ED53631CC77F95006AB156 /* EmailListViewCell.swift */,
    1.45 @@ -1227,6 +1241,7 @@
    1.46  				4382E6431CC600FF00AA27EA /* PersistentImapFolder.swift in Sources */,
    1.47  				43CE63CF1DE8845E00FAC505 /* CdAttachment+pEp.swift in Sources */,
    1.48  				43B7154D1CECAADA0027861A /* ViewWidthsAligner.swift in Sources */,
    1.49 +				4323FE891E83E517006785E1 /* IdentityImageProvider.swift in Sources */,
    1.50  				43549A8E1E48B54100210D86 /* TrashMailsOperation.swift in Sources */,
    1.51  				222B358A1DF99C48007A1F82 /* Actionsheet+Extension.swift in Sources */,
    1.52  				43A0E73E1D16C99900159F41 /* NSLayoutConstraint+PureLayout.m in Sources */,
    1.53 @@ -1252,6 +1267,7 @@
    1.54  				431AE5D51D2EC0C000F609D3 /* ComposeTableViewController.swift in Sources */,
    1.55  				439A6C741E535827004CBAA6 /* HandshakeTableViewCell.swift in Sources */,
    1.56  				431B04801DE5774800E40CD3 /* CdMessage+Pantomime.swift in Sources */,
    1.57 +				4323FE8B1E83E5E6006785E1 /* IdentityImageOperation.swift in Sources */,
    1.58  				431144B71CC11D6A0007639D /* BaseOperation.swift in Sources */,
    1.59  				432198E81DF6B51B00318A74 /* LoginImapOperation.swift in Sources */,
    1.60  				43A0E73D1D16C99900159F41 /* NSArray+PureLayout.m in Sources */,
     2.1 --- a/pEpForiOS/UI/EmailDisplay/EmailListViewCell.swift	Thu Mar 23 11:14:33 2017 +0100
     2.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailListViewCell.swift	Thu Mar 23 14:03:56 2017 +0100
     2.3 @@ -30,6 +30,9 @@
     2.4      
     2.5      let dateFormatter = UIHelper.dateFormatterEmailList()
     2.6  
     2.7 +    var identityForImage: Identity?
     2.8 +    var config: EmailListConfig?
     2.9 +
    2.10      override func awakeFromNib() {
    2.11          super.awakeFromNib()
    2.12          self.selectionStyle = UITableViewCellSelectionStyle.none
    2.13 @@ -58,6 +61,8 @@
    2.14      }
    2.15  
    2.16      func configureCell(config: EmailListConfig?, indexPath: IndexPath) -> Message? {
    2.17 +        self.config = config
    2.18 +
    2.19          if let message = messageAt(indexPath: indexPath, config: config) {
    2.20              UIHelper.putString(message.from?.userName, toLabel: self.senderLabel)
    2.21              UIHelper.putString(message.shortMessage, toLabel: self.subjectLabel)
    2.22 @@ -85,10 +90,22 @@
    2.23              updateFlags(message: message)
    2.24              updatePepRating(message: message)
    2.25  
    2.26 +            identityForImage = message.from
    2.27 +            if let ident = identityForImage, let imgProvider = config?.imageProvider {
    2.28 +                imgProvider.image(forIdentity: ident) { img in
    2.29 +                }
    2.30 +            }
    2.31 +
    2.32              return message
    2.33          }
    2.34          return nil
    2.35      }
    2.36 +
    2.37 +    override func prepareForReuse() {
    2.38 +        if let ident = identityForImage {
    2.39 +            config?.imageProvider.cancel(identity: ident)
    2.40 +        }
    2.41 +    }
    2.42      
    2.43      /**
    2.44       The message at the given position.
     3.1 --- a/pEpForiOS/UI/EmailDisplay/EmailListViewController.swift	Thu Mar 23 11:14:33 2017 +0100
     3.2 +++ b/pEpForiOS/UI/EmailDisplay/EmailListViewController.swift	Thu Mar 23 14:03:56 2017 +0100
     3.3 @@ -16,6 +16,8 @@
     3.4  
     3.5      /** The folder to display, if it exists */
     3.6      var folder: Folder?
     3.7 +
     3.8 +    let imageProvider = IdentityImageProvider()
     3.9  }
    3.10  
    3.11  class EmailListViewController: UITableViewController, FilterUpdateProtocol {
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pEpForiOS/UI/EmailDisplay/Util/IdentityImageOperation.swift	Thu Mar 23 14:03:56 2017 +0100
     4.3 @@ -0,0 +1,18 @@
     4.4 +//
     4.5 +//  IdentityImageOperation.swift
     4.6 +//  pEpForiOS
     4.7 +//
     4.8 +//  Created by Dirk Zimmermann on 23/03/2017.
     4.9 +//  Copyright © 2017 p≡p Security S.A. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +import MessageModel
    4.13 +
    4.14 +class IdentityImageOperation: Operation {
    4.15 +    let identity: Identity
    4.16 +    var image: UIImage?
    4.17 +
    4.18 +    init(identity: Identity) {
    4.19 +        self.identity = identity
    4.20 +    }
    4.21 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/pEpForiOS/UI/EmailDisplay/Util/IdentityImageProvider.swift	Thu Mar 23 14:03:56 2017 +0100
     5.3 @@ -0,0 +1,70 @@
     5.4 +//
     5.5 +//  IdentityImageProvider.swift
     5.6 +//  pEpForiOS
     5.7 +//
     5.8 +//  Created by Dirk Zimmermann on 23/03/2017.
     5.9 +//  Copyright © 2017 p≡p Security S.A. All rights reserved.
    5.10 +//
    5.11 +
    5.12 +import MessageModel
    5.13 +
    5.14 +typealias ImageReadyFunc = (UIImage) -> Void
    5.15 +
    5.16 +class IdentityImageProvider {
    5.17 +    fileprivate var runningOperations = [Identity: (IdentityImageOperation, [ImageReadyFunc])]()
    5.18 +    fileprivate let dispatchQueue = DispatchQueue(label: "IdentityImageProvider Queue")
    5.19 +    fileprivate let backgroundQueue = OperationQueue()
    5.20 +
    5.21 +    /**
    5.22 +     Request an image.
    5.23 +     */
    5.24 +    open func image(forIdentity identity: Identity, callback: @escaping ImageReadyFunc) {
    5.25 +        dispatchQueue.async {
    5.26 +            self.internalImage(forIdentity: identity, callback: callback)
    5.27 +        }
    5.28 +    }
    5.29 +
    5.30 +    /**
    5.31 +     Cancel an image request.
    5.32 +     */
    5.33 +    open func cancel(identity: Identity) {
    5.34 +        dispatchQueue.async {
    5.35 +            self.internalCancel(identity: identity)
    5.36 +        }
    5.37 +    }
    5.38 +
    5.39 +    fileprivate func internalImage(forIdentity identity: Identity,
    5.40 +                                   callback: @escaping ImageReadyFunc) {
    5.41 +        if let (op, funs) = runningOperations[identity] {
    5.42 +            var newFuns = funs
    5.43 +            newFuns.append(callback)
    5.44 +            runningOperations[identity] = (op, newFuns)
    5.45 +        } else {
    5.46 +            let op = IdentityImageOperation(identity: identity)
    5.47 +            op.completionBlock = { [weak self, weak identity] in
    5.48 +                self?.dispatchQueue.async {
    5.49 +                    if let theSelf = self, let theIdentity = identity {
    5.50 +                        theSelf.finished(identity: theIdentity)
    5.51 +                    }
    5.52 +                }
    5.53 +            }
    5.54 +            runningOperations[identity] = (op, [callback])
    5.55 +        }
    5.56 +    }
    5.57 +
    5.58 +    fileprivate func internalCancel(identity: Identity) {
    5.59 +        if let (op, _) = runningOperations.removeValue(forKey: identity) {
    5.60 +            op.cancel()
    5.61 +        }
    5.62 +    }
    5.63 +
    5.64 +    fileprivate func finished(identity: Identity) {
    5.65 +        if let (op, funs) = runningOperations.removeValue(forKey: identity), let img = op.image {
    5.66 +            for f in funs {
    5.67 +                GCD.onMain {
    5.68 +                    f(img)
    5.69 +                }
    5.70 +            }
    5.71 +        }
    5.72 +    }
    5.73 +}