Revision f3813541

View differences:

ChatSecure.xcodeproj/project.pbxproj
109 109
		63FCB1371DA3224A00A801F2 /* OTRSignalEncryptionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63FCB1361DA3224A00A801F2 /* OTRSignalEncryptionHelper.swift */; };
110 110
		7A6540ECCA04445E88F06962 /* Pods_ChatSecureCorePods_ChatSecureTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 281981F599E0F5C8397E6A3F /* Pods_ChatSecureCorePods_ChatSecureTests.framework */; };
111 111
		8F56C3272EBE7F45BC8F925A /* OTRMessagesLoadingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8F56C50436DA64774EBB16E3 /* OTRMessagesLoadingView.xib */; };
112
		9212364E1FCD779D009F97F0 /* OTRMessageUnknownSenderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9212364C1FCD779C009F97F0 /* OTRMessageUnknownSenderCell.swift */; };
113
		921236501FCD77B7009F97F0 /* OTRMessageUnknownSenderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9212364D1FCD779C009F97F0 /* OTRMessageUnknownSenderCell.xib */; };
114 112
		9236F56B1F21FFA600C963D0 /* OTRGroupAvatarGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9236F56A1F21FFA600C963D0 /* OTRGroupAvatarGenerator.swift */; };
115 113
		924F67C51EA5541C00528FB6 /* MigrationInfoHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 924F67C41EA5541C00528FB6 /* MigrationInfoHeaderView.xib */; };
116 114
		924F67C71EA55C6F00528FB6 /* MigrationInfoHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924F67C61EA55C6F00528FB6 /* MigrationInfoHeaderView.swift */; };
......
1021 1019
		7A62FCE8FEC1E7C9644F8C38 /* Pods-ChatSecureCorePods-ChatSecure.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatSecureCorePods-ChatSecure.release.xcconfig"; path = "Pods/Target Support Files/Pods-ChatSecureCorePods-ChatSecure/Pods-ChatSecureCorePods-ChatSecure.release.xcconfig"; sourceTree = "<group>"; };
1022 1020
		8F56C50436DA64774EBB16E3 /* OTRMessagesLoadingView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OTRMessagesLoadingView.xib; sourceTree = "<group>"; };
1023 1021
		9118152C0A7B287ABD07FF70 /* Pods-ChatSecureCorePods-ChatSecureCore.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatSecureCorePods-ChatSecureCore.release.xcconfig"; path = "Pods/Target Support Files/Pods-ChatSecureCorePods-ChatSecureCore/Pods-ChatSecureCorePods-ChatSecureCore.release.xcconfig"; sourceTree = "<group>"; };
1024
		9212364C1FCD779C009F97F0 /* OTRMessageUnknownSenderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTRMessageUnknownSenderCell.swift; sourceTree = "<group>"; };
1025
		9212364D1FCD779C009F97F0 /* OTRMessageUnknownSenderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OTRMessageUnknownSenderCell.xib; sourceTree = "<group>"; };
1026 1022
		9236F56A1F21FFA600C963D0 /* OTRGroupAvatarGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTRGroupAvatarGenerator.swift; sourceTree = "<group>"; };
1027 1023
		924F67C41EA5541C00528FB6 /* MigrationInfoHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MigrationInfoHeaderView.xib; path = Interface/MigrationInfoHeaderView.xib; sourceTree = "<group>"; };
1028 1024
		924F67C61EA55C6F00528FB6 /* MigrationInfoHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationInfoHeaderView.swift; sourceTree = "<group>"; };
......
1749 1745
				D9C6E6A01B71575300572273 /* OTRUsernameCell.swift */,
1750 1746
				92CC68F01F42FF8D0006CDF8 /* OTRComposeGroupBuddyCell.swift */,
1751 1747
				92CC68F21F43054E0006CDF8 /* OTRComposeGroupBuddyCell.xib */,
1752
				9212364C1FCD779C009F97F0 /* OTRMessageUnknownSenderCell.swift */,
1753
				9212364D1FCD779C009F97F0 /* OTRMessageUnknownSenderCell.xib */,
1754 1748
			);
1755 1749
			path = Cells;
1756 1750
			sourceTree = "<group>";
......
2641 2635
				D97070921EEF382D004FEBDE /* MediaDownloadView.xib in Resources */,
2642 2636
				924F68591EA7A31A00528FB6 /* MigratedBuddyHeaderView.xib in Resources */,
2643 2637
				8F56C3272EBE7F45BC8F925A /* OTRMessagesLoadingView.xib in Resources */,
2644
				921236501FCD77B7009F97F0 /* OTRMessageUnknownSenderCell.xib in Resources */,
2645 2638
			);
2646 2639
			runOnlyForDeploymentPostprocessing = 0;
2647 2640
		};
......
3074 3067
				D93DDA861BA79A2400CD8331 /* OTREncryptionManager.m in Sources */,
3075 3068
				D93DDA881BA79A2400CD8331 /* OTROAuthRefresher.m in Sources */,
3076 3069
				6340431B1BD5BCD800ECA95A /* OTRXMPPRoomMessage.swift in Sources */,
3077
				9212364E1FCD779D009F97F0 /* OTRMessageUnknownSenderCell.swift in Sources */,
3078 3070
				D93DDA891BA79A2400CD8331 /* OTRProtocolManager.m in Sources */,
3079 3071
				63DC417B1BB3767100D42857 /* Errors.swift in Sources */,
3080 3072
				D93DDA8A1BA79A2400CD8331 /* OTRSettingsManager.m in Sources */,
ChatSecure/Classes/Controllers/FileTransferManager.swift
523 523
                    downloads = message.existingDownloads(with: transaction)
524 524
                    if let thread = message.threadOwner(with: transaction), let account = OTRAccount.fetchObject(withUniqueID: thread.threadAccountIdentifier, transaction: transaction) {
525 525
                        disableAutomaticURLFetching = account.disableAutomaticURLFetching
526
                        if !disableAutomaticURLFetching, let room = thread as? OTRXMPPRoom, let message = message as? OTRXMPPRoomMessage {
527
                            // For room messages, default to safe mode
528
                            disableAutomaticURLFetching = true
529
                            if let senderJidString = message.senderJID, let senderJID = XMPPJID(string: senderJidString), let roomJID = room.roomJID, let occupant = OTRXMPPRoomOccupant.occupant(jid: senderJID, realJID: senderJID, roomJID: roomJID, accountId: thread.threadAccountIdentifier, createIfNeeded: false, transaction: transaction), occupant.buddy(with: transaction) != nil {
530
                                // We have a buddy, i.e. we are friends with the sender.
531
                                disableAutomaticURLFetching = false
532
                            }
533
                        }
534 526
                    }
535 527
                }
536 528
            }
ChatSecure/Classes/View Controllers/OTRMessagesCollectionViewFlowLayout.swift
14 14
    func hasBubbleSizeForCellAtIndexPath(_ indexPath: IndexPath) -> Bool
15 15
}
16 16

  
17
@objc public class OTRMessagesCollectionSupplementaryViewInfo: NSObject {
18
    public var kind:String
19
    public var height:CGFloat
20

  
21
    @objc public init(kind:String, height:CGFloat) {
22
        self.kind = kind
23
        self.height = height
24
        super.init()
25
    }
26
}
27

  
28
@objc public protocol OTRMessagesCollectionViewFlowLayoutSupplementaryViewProtocol {
29
    func supplementaryViewsForCellAtIndexPath(_ indexPath: IndexPath) -> [OTRMessagesCollectionSupplementaryViewInfo]?
30
}
31

  
32 17
@objc open class OTRMessagesCollectionViewFlowLayout:JSQMessagesCollectionViewFlowLayout {
33 18
    
34 19
    @objc open weak var sizeDelegate:OTRMessagesCollectionViewFlowLayoutSizeProtocol?
35
    @objc open weak var supplementaryViewDelegate:OTRMessagesCollectionViewFlowLayoutSupplementaryViewProtocol?
36

  
20
    
37 21
    @objc override open func messageBubbleSizeForItem(at indexPath: IndexPath!) -> CGSize {
38 22
        guard let delegate = self.sizeDelegate, !delegate.hasBubbleSizeForCellAtIndexPath(indexPath) else {
39 23
            return super.messageBubbleSizeForItem(at: indexPath)
......
43 27
        return CGSize(width: 1, height: 0)
44 28
    }
45 29
    
46
    open override var collectionViewContentSize: CGSize {
47
        var size = super.collectionViewContentSize
48
        if let delegate = self.supplementaryViewDelegate {
49
            for section in 0..<self.collectionView.numberOfSections {
50
                for item in 0..<self.collectionView.numberOfItems(inSection: section) {
51
                    if let views = delegate.supplementaryViewsForCellAtIndexPath(IndexPath(item: item, section: section)) {
52
                        for view in views {
53
                            size.height += view.height
54
                        }
55
                    }
56
                }
57
            }
58
        }
59
        return size
60
    }
61
    
62
    override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
63
        guard var attributes = super.layoutAttributesForElements(in: rect) else { return nil }
64
        
65
        var offset:CGFloat = 0
66
        for attribute in attributes {
67
            if (attribute.representedElementCategory == UICollectionElementCategory.cell) {
68
                attribute.frame = attribute.frame.offsetBy(dx: 0, dy: offset)
69
                if let delegate = self.supplementaryViewDelegate {
70
                    if let views = delegate.supplementaryViewsForCellAtIndexPath(attribute.indexPath) {
71
                        for view in views {
72
                            offset += view.height
73
                            let suppViewAttrs = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: view.kind, with: attribute.indexPath)
74
                            suppViewAttrs.frame = CGRect(x: attribute.frame.origin.x, y: attribute.frame.origin.y+attribute.frame.size.height, width: attribute.frame.size.width, height: view.height)
75
                            attributes.append(suppViewAttrs)
76
                        }
77
                    }
78
                }
79
            }
80
        }
81
        return attributes
82
    }
83 30
}
ChatSecure/Classes/View Controllers/OTRMessagesViewController.m
69 69
    OTRDropDownTypePush          = 2
70 70
};
71 71

  
72
@interface OTRMessagesViewController () <UITextViewDelegate, OTRAttachmentPickerDelegate, OTRYapViewHandlerDelegateProtocol, OTRMessagesCollectionViewFlowLayoutSizeProtocol, OTRMessagesCollectionViewFlowLayoutSupplementaryViewProtocol, OTRRoomOccupantsViewControllerDelegate> {
72
@interface OTRMessagesViewController () <UITextViewDelegate, OTRAttachmentPickerDelegate, OTRYapViewHandlerDelegateProtocol, OTRMessagesCollectionViewFlowLayoutSizeProtocol, OTRRoomOccupantsViewControllerDelegate> {
73 73
    JSQMessagesAvatarImage *_warningAvatarImage;
74 74
    JSQMessagesAvatarImage *_accountAvatarImage;
75 75
    JSQMessagesAvatarImage *_buddyAvatarImage;
......
102 102
@property (nonatomic, strong) id currentMessage;
103 103
@property (nonatomic, strong) NSCache *messageSizeCache;
104 104

  
105
@property (nonatomic) BOOL automaticURLFetchingDisabled;
106
@property (nonatomic, strong) OTRMessagesUnknownSenderCell *prototypeCellUnknownSender;
107

  
108 105
@end
109 106

  
110 107
@implementation OTRMessagesViewController
......
178 175
    ///Custom Layout to account for no bubble cells
179 176
    OTRMessagesCollectionViewFlowLayout *layout = [[OTRMessagesCollectionViewFlowLayout alloc] init];
180 177
    layout.sizeDelegate = self;
181
    layout.supplementaryViewDelegate = self;
182 178
    self.collectionView.collectionViewLayout = layout;
183
    UINib *nib = [UINib nibWithNibName:@"OTRMessageUnknownSenderCell" bundle:OTRAssets.resourcesBundle];
184
    [self.collectionView registerNib:nib forSupplementaryViewOfKind:[OTRMessagesUnknownSenderCell reuseIdentifier] withReuseIdentifier:[OTRMessagesUnknownSenderCell reuseIdentifier]];
185
    
179

  
186 180
    ///"Loading Earlier" header view
187 181
    [self.collectionView registerNib:[UINib nibWithNibName:@"OTRMessagesLoadingView" bundle:OTRAssets.resourcesBundle]
188 182
          forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
......
387 381
    self.threadCollection = collection;
388 382
    [self.readOnlyDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
389 383
        self.senderId = [[self threadObjectWithTransaction:transaction] threadAccountIdentifier];
390
        self.automaticURLFetchingDisabled = [[self accountWithTransaction:transaction] disableAutomaticURLFetching];
391 384
    }];
392 385
    
393 386
    // Clear out old state (don't just alloc a new object, we have KVOs attached to this!)
......
2294 2287
        [self.navigationController.navigationController popViewControllerAnimated:YES];
2295 2288
    }
2296 2289
}
2297

  
2298
#pragma - mark OTRMessagesCollectionViewFlowLayoutSupplementaryViewProtocol
2299

  
2300
- (nullable NSArray *)supplementaryViewsForCellAtIndexPath:(NSIndexPath *)indexPath {
2301
    id<OTRMessageProtocol,JSQMessageData> message = [self messageAtIndexPath:indexPath];
2302
    if ([self isGroupChat] && [message isKindOfClass:[OTRGroupDownloadMessage class]]) {
2303
        OTRGroupDownloadMessage *roomMessage = (OTRGroupDownloadMessage *)message;
2304
        // A message that is not automatically downloaded, even though auto download not disabled, means that this is group download message from someone who is not our friend.
2305
        if ([roomMessage.messageError isAutomaticDownloadError] && !self.automaticURLFetchingDisabled && [roomMessage.media isKindOfClass:[OTRImageItem class]]) {
2306
            if (!_prototypeCellUnknownSender) {
2307
                UINib *nib = [UINib nibWithNibName:@"OTRMessageUnknownSenderCell" bundle:OTRAssets.resourcesBundle];
2308
                _prototypeCellUnknownSender = (OTRMessagesUnknownSenderCell *)[nib instantiateWithOwner:self options:nil][0];
2309
            }
2310
            [self populateUnknownSenderCell:_prototypeCellUnknownSender withMessage:message];
2311
            [_prototypeCellUnknownSender setNeedsLayout];
2312
            [_prototypeCellUnknownSender layoutIfNeeded];
2313
            _prototypeCellUnknownSender.frame = CGRectMake(0, 0, self.collectionView.bounds.size.width, _prototypeCellUnknownSender.frame.size.height);
2314
            int height = [_prototypeCellUnknownSender systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 1;
2315
            
2316
            OTRMessagesCollectionSupplementaryViewInfo *info = [[OTRMessagesCollectionSupplementaryViewInfo alloc] initWithKind:[OTRMessagesUnknownSenderCell reuseIdentifier] height:height];
2317
            return [NSArray arrayWithObject:info];
2318
        }
2319
    }
2320
    return nil;
2321
}
2322

  
2323
- (void)populateUnknownSenderCell:(OTRMessagesUnknownSenderCell *)cell withMessage:(id<OTRMessageProtocol,JSQMessageData>)message {
2324
    cell.titleLabel.text = [NSString stringWithFormat:ADD_FRIEND_TO_AUTO_DOWNLOAD(), message.senderDisplayName];
2325
}
2326

  
2327
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
2328
    if ([OTRMessagesUnknownSenderCell.reuseIdentifier isEqualToString:kind]) {
2329
        id<OTRMessageProtocol,JSQMessageData> message = [self messageAtIndexPath:indexPath];
2330
        OTRMessagesUnknownSenderCell *cell = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kind forIndexPath:indexPath];
2331
        [self populateUnknownSenderCell:cell withMessage:message];
2332
        return cell;
2333
    }
2334
    // We should never get there, but if we do, don't return nil
2335
    return [[UICollectionReusableView alloc] initWithFrame:CGRectZero];
2336
}
2337

  
2338 2290
@end
ChatSecure/Classes/Views/Cells/OTRMessageUnknownSenderCell.swift
1
//
2
//  OTRMessageUnknownSenderCell.swift
3
//  ChatSecureCore
4
//
5
//  Created by N-Pex on 2017-11-27.
6
//  Copyright © 2017 Chris Ballinger. All rights reserved.
7
//
8

  
9
@objc public class OTRMessagesUnknownSenderCell: UICollectionReusableView {
10
    @objc public static let reuseIdentifier = "unknownSenderCell"
11
    
12
    @objc @IBOutlet open weak var titleLabel:UILabel!
13
    
14
    override open func layoutSubviews() {
15
        super.layoutSubviews()
16
        for view in subviews {
17
            if let label = view as? UILabel {
18
                if label.numberOfLines == 0 {
19
                    label.preferredMaxLayoutWidth = label.bounds.width
20
                }
21
            }
22
        }
23
        
24
    }
25
}
ChatSecure/Classes/Views/Cells/OTRMessageUnknownSenderCell.xib
1
<?xml version="1.0" encoding="UTF-8"?>
2
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3
    <device id="retina4_7" orientation="portrait">
4
        <adaptation id="fullscreen"/>
5
    </device>
6
    <dependencies>
7
        <deployment identifier="iOS"/>
8
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
9
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10
    </dependencies>
11
    <objects>
12
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14
        <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="22J-kO-64R" customClass="OTRMessagesUnknownSenderCell" customModule="ChatSecureCore">
15
            <rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
16
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
17
            <subviews>
18
                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="1000" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" verticalCompressionResistancePriority="1000" text="No data" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tP4-Uw-Q8q">
19
                    <rect key="frame" x="10" y="10" width="355" height="30"/>
20
                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
21
                    <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
22
                    <nil key="highlightedColor"/>
23
                </label>
24
            </subviews>
25
            <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
26
            <constraints>
27
                <constraint firstAttribute="bottom" secondItem="tP4-Uw-Q8q" secondAttribute="bottom" constant="10" id="PTO-Cn-PH4"/>
28
                <constraint firstAttribute="trailing" secondItem="tP4-Uw-Q8q" secondAttribute="trailing" constant="10" id="ZqZ-wZ-92N"/>
29
                <constraint firstItem="tP4-Uw-Q8q" firstAttribute="leading" secondItem="22J-kO-64R" secondAttribute="leading" constant="10" id="lTY-I5-fsW"/>
30
                <constraint firstItem="tP4-Uw-Q8q" firstAttribute="top" secondItem="22J-kO-64R" secondAttribute="top" constant="10" id="vjV-ke-Pc2"/>
31
            </constraints>
32
            <connections>
33
                <outlet property="titleLabel" destination="tP4-Uw-Q8q" id="b4e-Ao-C3K"/>
34
            </connections>
35
        </collectionReusableView>
36
    </objects>
37
</document>
OTRAssets/Strings/OTRStrings.h
18 18
FOUNDATION_EXPORT NSString* ADD_BUDDY_STRING();
19 19
/** "Add Existing Account", Label for button to create account by logging into an existing account */
20 20
FOUNDATION_EXPORT NSString* ADD_EXISTING_STRING();
21
/** "Is %@ your friend? Add him/her to auto-download pictures in the future.", Shown in chat view to prompt user to add friend for auto-download of group media messages. */
22
FOUNDATION_EXPORT NSString* ADD_FRIEND_TO_AUTO_DOWNLOAD();
23 21
/** "Add", Button title to add someone as a buddy */
24 22
FOUNDATION_EXPORT NSString* ADD_STRING();
25 23
/** "Advanced", String to describe advanced set of settings */
OTRAssets/Strings/OTRStrings.m
18 18
NSString* ADD_BUDDY_STRING() { return [OTRLanguageManager translatedString:@"Add Buddy"]; }
19 19
/** "Add Existing Account", Label for button to create account by logging into an existing account */
20 20
NSString* ADD_EXISTING_STRING() { return [OTRLanguageManager translatedString:@"Add Existing Account"]; }
21
/** "Is %@ your friend? Add him/her to auto-download pictures in the future.", Shown in chat view to prompt user to add friend for auto-download of group media messages. */
22
NSString* ADD_FRIEND_TO_AUTO_DOWNLOAD() { return [OTRLanguageManager translatedString:@"Is %@ your friend? Add him/her to auto-download pictures in the future."]; }
23 21
/** "Add", Button title to add someone as a buddy */
24 22
NSString* ADD_STRING() { return [OTRLanguageManager translatedString:@"Add"]; }
25 23
/** "Advanced", String to describe advanced set of settings */
OTRAssets/Strings/strings.json
1182 1182
    }, "GROUP_INFO_YOU": {
1183 1183
        "comment": "This will be shown after your own JID in the group profile view",
1184 1184
        "string": "you"
1185
    }, "ADD_FRIEND_TO_AUTO_DOWNLOAD": {
1186
        "comment": "Shown in chat view to prompt user to add friend for auto-download of group media messages.",
1187
        "string": "Is %@ your friend? Add him/her to auto-download pictures in the future."
1188 1185
    }
1189 1186
}

Also available in: Unified diff