浏览代码

Merge pull request #272 from deltachat/join_group_with_QR_code

 implement group join with qr code (#239)
björn petersen 5 年之前
父节点
当前提交
0914ab7b1f

+ 4 - 0
deltachat-ios.xcodeproj/project.pbxproj

@@ -11,6 +11,7 @@
 		3022E6BE22E8768800763272 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3022E6C022E8768800763272 /* InfoPlist.strings */; };
 		3060119C22DDE24000C1CE6F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3060119E22DDE24000C1CE6F /* Localizable.strings */; };
 		306011B622E5E7FB00C1CE6F /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 306011B422E5E7FB00C1CE6F /* Localizable.stringsdict */; };
+		30A4D9AE2332672700544344 /* QrInviteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A4D9AD2332672600544344 /* QrInviteViewController.swift */; };
 		30BD261422F8679200F399DF /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BD261322F8679200F399DF /* ProfileView.swift */; };
 		30BD261622F8812700F399DF /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30BD261522F8812700F399DF /* UIView+Extension.swift */; };
 		6795F63A82E94FF7CD2CEC0F /* Pods_deltachat_iosTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F7009234DB9408201A6CDCB /* Pods_deltachat_iosTests.framework */; };
@@ -145,6 +146,7 @@
 		306011C722E5E82E00C1CE6F /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lt; path = lt.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
 		306011C822E5E83100C1CE6F /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
 		306011C922E5E83500C1CE6F /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+		30A4D9AD2332672600544344 /* QrInviteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrInviteViewController.swift; sourceTree = "<group>"; };
 		30BD261322F8679200F399DF /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; usesTabs = 0; };
 		30BD261522F8812700F399DF /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = "<group>"; usesTabs = 0; };
 		6241BE1534A653E79AD5D01D /* Pods_deltachat_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_deltachat_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -356,6 +358,7 @@
 				7AE0A5481FC42F65005ECB4B /* NewChatViewController.swift */,
 				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
 				30149D9222F21129003C12B5 /* QrViewController.swift */,
+				30A4D9AD2332672600544344 /* QrInviteViewController.swift */,
 				78E45E3921D3CFBC00D4B15E /* SettingsController.swift */,
 				7070FB9A2101ECBB000DC258 /* GroupNameController.swift */,
 				AE851ACF227DF50900ED86F0 /* GroupChatDetailViewController.swift */,
@@ -720,6 +723,7 @@
 				78E45E3E21D3D28C00D4B15E /* DcNavigationController.swift in Sources */,
 				AE18F294228C602A0007B1BE /* SecuritySettingsController.swift in Sources */,
 				78ED838D21D577D000243125 /* events.swift in Sources */,
+				30A4D9AE2332672700544344 /* QrInviteViewController.swift in Sources */,
 				AE851AC7227C776400ED86F0 /* Location.swift in Sources */,
 				7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */,
 				AE25F09022807AD800CDEA66 /* GroupNameCell.swift in Sources */,

+ 39 - 21
deltachat-ios/Controller/GroupChatDetailViewController.swift

@@ -1,6 +1,14 @@
 import UIKit
 
 class GroupChatDetailViewController: UIViewController {
+
+    private let sectionConfig = 0
+    private let sectionMembers = 1
+    private let sectionLeaveGroup = 2
+    private let sectionMembersRowAddMember = 0
+    private let sectionMembersRowJoinQR = 1
+
+
     private var currentUser: DcContact? {
         return groupMembers.filter { $0.email == DcConfig.addr }.first
     }
@@ -54,7 +62,7 @@ class GroupChatDetailViewController: UIViewController {
 
     private var groupMembers: [DcContact] = []
 
-    private let staticCellCountMemberSection = 1 //
+    private let staticCellCountMemberSection = 2
 
     override func viewDidLoad() {
         super.viewDidLoad()
@@ -100,7 +108,7 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
     }
 
     func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? {
-        if section == 0 {
+        if section == sectionConfig {
             let header = ContactDetailHeader()
             header.updateDetails(title: chat.name, subtitle: chat.subtitle)
             if let img = chat.profileImage {
@@ -129,13 +137,14 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
     }
 
     func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
-        if section == 0 {
+        switch section {
+        case sectionConfig:
             return 1
-        } else if section == 1 {
-            return groupMembers.count + staticCellCountMemberSection // first cell is addGroupMemberCell
-        } else if section == 2 {
+        case sectionMembers:
+            return groupMembers.count + staticCellCountMemberSection
+        case sectionLeaveGroup:
             return 1
-        } else {
+        default:
             return 0
         }
     }
@@ -143,20 +152,27 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let section = indexPath.section
         let row = indexPath.row
-
-        if section == 0 {
+        switch section {
+        case sectionConfig:
             let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
             cell.textLabel?.text = String.localized("pref_notifications")
             cell.selectionStyle = .none
             return cell
-        } else if section == 1 {
-            if row == 0 {
+        case sectionMembers:
+            switch row {
+            case sectionMembersRowAddMember:
                 let cell = tableView.dequeueReusableCell(withIdentifier: "actionCell", for: indexPath)
                 if let actionCell = cell as? ActionCell {
                     actionCell.actionTitle = String.localized("group_add_members")
                 }
                 return cell
-            } else {
+            case sectionMembersRowJoinQR:
+                let cell = tableView.dequeueReusableCell(withIdentifier: "actionCell", for: indexPath)
+                if let actionCell = cell as? ActionCell {
+                    actionCell.actionTitle = String.localized("qrshow_join_group_title")
+                }
+                return cell
+            default:
                 let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath)
                 if let contactCell = cell as? ContactCell {
                     let contact = groupMembers[row - staticCellCountMemberSection]
@@ -168,29 +184,31 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
                 }
                 return cell
             }
-        } else if section == 2 {
+        case sectionLeaveGroup:
             let cell = tableView.dequeueReusableCell(withIdentifier: "actionCell", for: indexPath)
             if let actionCell = cell as? ActionCell {
                 actionCell.actionTitle = String.localized("menu_leave_group")
                 actionCell.actionColor = UIColor.red
             }
             return cell
+        default:
+            return UITableViewCell(frame: .zero)
         }
-
-        return UITableViewCell(frame: .zero)
     }
 
     func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
         let section = indexPath.section
         let row = indexPath.row
-        if section == 0 {
+        if section == sectionConfig {
             showNotificationSetup()
-        } else if section == 1 {
-            if row == 0 {
+        } else if section == sectionMembers {
+            if row == sectionMembersRowAddMember {
                 coordinator?.showAddGroupMember(chatId: chat.id)
+            } else if row == sectionMembersRowJoinQR {
+                coordinator?.showQrCodeInvite(chatId: chat.id)
             }
             // ignore for now - in Telegram tapping a contactCell leads into ContactDetail
-        } else if section == 2 {
+        } else if section == sectionLeaveGroup {
             leaveGroup()
         }
     }
@@ -200,7 +218,7 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
         let row = indexPath.row
 
         if let currentUser = currentUser {
-            if section == 1, row > 0, groupMembers[row - staticCellCountMemberSection].id != currentUser.id {
+            if section == sectionMembers, row >= staticCellCountMemberSection, groupMembers[row - staticCellCountMemberSection].id != currentUser.id {
                 return true
             }
         }
@@ -212,7 +230,7 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
         let row = indexPath.row
 
         // assigning swipe by delete to members (except for current user)
-        if section == 1, row >= staticCellCountMemberSection, groupMembers[row - staticCellCountMemberSection].id != currentUser?.id {
+        if section == sectionMembers, row >= staticCellCountMemberSection, groupMembers[row - staticCellCountMemberSection].id != currentUser?.id {
             let delete = UITableViewRowAction(style: .destructive, title: String.localized("global_menu_edit_delete_desktop")) { [unowned self] _, indexPath in
 
                 let memberId = self.groupMembers[row - self.staticCellCountMemberSection].id

+ 117 - 0
deltachat-ios/Controller/QrInviteViewController.swift

@@ -0,0 +1,117 @@
+import Foundation
+import UIKit
+
+class QrInviteViewController: UITableViewController {
+    private let rowQRCode = 0
+    private let rowDescription = 1
+
+    let dcContext: DcContext
+    let chatId: Int
+
+    init(dcContext: DcContext, chatId: Int) {
+        self.dcContext = dcContext
+        self.chatId = chatId
+        super.init(nibName: nil, bundle: nil)
+    }
+
+    required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        title = String.localized("qrshow_join_contact_title")
+        tableView.separatorStyle = .none
+    }
+
+    override func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let row = indexPath.row
+        switch row {
+        case rowQRCode:
+            return createQRCodeCell()
+        case rowDescription:
+            return createInfoLabelCell()
+        default:
+            return UITableViewCell(style: .default, reuseIdentifier: nil)
+        }
+    }
+
+    override func viewWillAppear(_ animated: Bool) {
+        NavBarUtils.setSmallTitle(navigationController: navigationController)
+    }
+
+    override func numberOfSections(in _: UITableView) -> Int {
+        return 1
+    }
+
+    override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
+        return 2
+    }
+
+    override func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        switch indexPath.row {
+        case rowQRCode:
+            return 225
+        case rowDescription:
+            return 40
+        default:
+            return 10
+        }
+    }
+
+    private func createQRCodeCell() -> UITableViewCell {
+        let cell = UITableViewCell(style: .default, reuseIdentifier: "qrCodeCell")
+        let qrCode = createQRCodeView()
+        cell.contentView.addSubview(qrCode)
+        cell.selectionStyle = .none
+
+        let qrCodeConstraints = [qrCode.constraintAlignTopTo(cell.contentView, paddingTop: 50),
+                                 qrCode.constraintCenterXTo(cell.contentView)]
+        cell.contentView.addConstraints(qrCodeConstraints)
+        return cell
+    }
+
+    private func createInfoLabelCell() -> UITableViewCell {
+        let label = createDescriptionView()
+        let cell = UITableViewCell(style: .default, reuseIdentifier: "qrCodeCell")
+        cell.contentView.addSubview(label)
+        cell.selectionStyle = .none
+        let labelConstraints = [label.constraintCenterXTo(cell.contentView),
+                                label.constraintAlignTopTo(cell.contentView, paddingTop: 45),
+                                label.constraintAlignLeadingTo(cell.contentView, paddingLeading: 30),
+                                label.constraintAlignTrailingTo(cell.contentView, paddingTrailing: 30)]
+         cell.contentView.addConstraints(labelConstraints)
+        return cell
+    }
+
+    private func createQRCodeView() -> UIView {
+        let width: CGFloat = 200
+        let frame = CGRect(origin: .zero, size: .init(width: width, height: width))
+        let imageView = QRCodeView(frame: frame)
+        if let qrCode = dcContext.getSecurejoinQr(chatId: chatId) {
+            imageView.generateCode(
+                qrCode,
+                foregroundColor: .darkText,
+                backgroundColor: .white
+            )
+        }
+        imageView.translatesAutoresizingMaskIntoConstraints = false
+        imageView.widthAnchor.constraint(equalToConstant: width).isActive = true
+        imageView.heightAnchor.constraint(equalToConstant: width).isActive = true
+        return imageView
+    }
+
+    private func createDescriptionView() -> UIView {
+        let label = UILabel.init()
+        label.translatesAutoresizingMaskIntoConstraints = false
+        let dcChat = DcChat(id: chatId)
+        if !dcChat.name.isEmpty {
+            label.text = String.localizedStringWithFormat(String.localized("qrshow_join_group_hint"), dcChat.name)
+        }
+        label.lineBreakMode = .byWordWrapping
+        label.numberOfLines = 0
+        label.textAlignment = .center
+        label.font = UIFont.systemFont(ofSize: 14)
+        return label
+    }
+}

+ 5 - 0
deltachat-ios/Coordinator/AppCoordinator.swift

@@ -348,6 +348,11 @@ class GroupChatDetailCoordinator: Coordinator {
         navigationController.pushViewController(groupMemberViewController, animated: true)
     }
 
+    func showQrCodeInvite(chatId: Int) {
+        let qrInviteCodeController = QrInviteViewController(dcContext: dcContext, chatId: chatId)
+        navigationController.pushViewController(qrInviteCodeController, animated: true)
+    }
+
     func showGroupChatEdit(chat: DcChat) {
         let editGroupViewController = EditGroupViewController(chat: chat)
         let coordinator = EditGroupCoordinator(navigationController: navigationController)