瀏覽代碼

Merge pull request #810 from deltachat/adaptive_font_sizes

Adaptive font sizes
cyBerta 5 年之前
父節點
當前提交
d690ff21eb
共有 33 個文件被更改,包括 554 次插入455 次删除
  1. 2 1
      DcShare/View/ChatListCell.swift
  2. 0 12
      deltachat-ios.xcodeproj/project.pbxproj
  3. 0 2
      deltachat-ios/Controller/AccountSetupController.swift
  4. 11 24
      deltachat-ios/Controller/AddGroupMembersViewController.swift
  5. 19 23
      deltachat-ios/Controller/ChatListController.swift
  6. 13 9
      deltachat-ios/Controller/ContactDetailViewController.swift
  7. 1 7
      deltachat-ios/Controller/EditGroupViewController.swift
  8. 2 16
      deltachat-ios/Controller/EditSettingsController.swift
  9. 19 17
      deltachat-ios/Controller/GroupChatDetailViewController.swift
  10. 2 2
      deltachat-ios/Controller/NewChatViewController.swift
  11. 2 2
      deltachat-ios/Controller/NewContactController.swift
  12. 8 10
      deltachat-ios/Controller/NewGroupController.swift
  13. 1 10
      deltachat-ios/Controller/ProfileInfoViewController.swift
  14. 5 1
      deltachat-ios/Controller/QrCodeReaderController.swift
  15. 0 120
      deltachat-ios/Controller/QrInviteViewController.swift
  16. 17 3
      deltachat-ios/Controller/QrPageController.swift
  17. 18 26
      deltachat-ios/Controller/QrViewController.swift
  18. 16 13
      deltachat-ios/Controller/SettingsController.swift
  19. 10 0
      deltachat-ios/Extensions/Extensions.swift
  20. 6 0
      deltachat-ios/Extensions/String+Extension.swift
  21. 84 28
      deltachat-ios/Extensions/UIView+Extensions.swift
  22. 0 6
      deltachat-ios/Helper/Constants.swift
  23. 2 1
      deltachat-ios/MessageKit/Views/AudioPlayerView.swift
  24. 11 2
      deltachat-ios/View/ActionCell.swift
  25. 4 2
      deltachat-ios/View/AvatarSelectionCell.swift
  26. 0 41
      deltachat-ios/View/Cell/ProfileCell.swift
  27. 80 14
      deltachat-ios/View/ContactCell.swift
  28. 4 2
      deltachat-ios/View/ContactDetailHeader.swift
  29. 23 4
      deltachat-ios/View/MultilineTextFieldCell.swift
  30. 165 20
      deltachat-ios/View/TextFieldCell.swift
  31. 0 37
      deltachat-ios/View/TextFieldTableViewCell.swift
  32. 2 0
      deltachat-ios/ViewModel/ChatListViewModel.swift
  33. 27 0
      deltachat-ios/ViewModel/ContactCellViewModel.swift

+ 2 - 1
DcShare/View/ChatListCell.swift

@@ -15,7 +15,8 @@ class ChatListCell: UITableViewCell {
 
     let titleLabel: UILabel = {
         let label = UILabel()
-        label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
+        label.font = UIFont.preferredFont(forTextStyle: .headline)
+        label.adjustsFontForContentSizeCategory = true
         label.lineBreakMode = .byTruncatingTail
         label.textColor = DcColors.defaultTextColor
         label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1), for: NSLayoutConstraint.Axis.horizontal)

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

@@ -99,7 +99,6 @@
 		308FEA52246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FEA51246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift */; };
 		3095A351237DD1F700AB07F7 /* MediaPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3095A350237DD1F700AB07F7 /* MediaPicker.swift */; };
 		30A2EC36247D72720024ADD8 /* AnimatedImageMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A2EC35247D72720024ADD8 /* AnimatedImageMessageCell.swift */; };
-		30A4D9AE2332672700544344 /* QrInviteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A4D9AD2332672600544344 /* QrInviteViewController.swift */; };
 		30B0ACFA24AB5B99004D5E29 /* SettingsEphemeralMessageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0ACF924AB5B99004D5E29 /* SettingsEphemeralMessageController.swift */; };
 		30C0D49D237C4908008E2A0E /* CertificateCheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */; };
 		30E8F2132447285600CE2C90 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E8F2122447285600CE2C90 /* ShareViewController.swift */; };
@@ -120,7 +119,6 @@
 		785BE16821E247F1003BE98C /* MessageInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 785BE16721E247F1003BE98C /* MessageInfoViewController.swift */; };
 		789E879621D6CB58003ED1C5 /* QrCodeReaderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */; };
 		78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3921D3CFBC00D4B15E /* SettingsController.swift */; };
-		78E45E3C21D3D03700D4B15E /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3B21D3D03700D4B15E /* TextFieldTableViewCell.swift */; };
 		78E45E4421D3F14A00D4B15E /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */; };
 		78E45E4C21D404AE00D4B15E /* InfoMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E4B21D404AE00D4B15E /* InfoMessageCell.swift */; };
 		78ED838321D5379000243125 /* TextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78ED838221D5379000243125 /* TextFieldCell.swift */; };
@@ -144,7 +142,6 @@
 		AE25F09022807AD800CDEA66 /* AvatarSelectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE25F08F22807AD800CDEA66 /* AvatarSelectionCell.swift */; };
 		AE38B31822672DFC00EC37A1 /* ActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE38B31722672DFC00EC37A1 /* ActionCell.swift */; };
 		AE39D323249CFC1A007346A1 /* DocumentGalleryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE39D322249CFC1A007346A1 /* DocumentGalleryController.swift */; };
-		AE406EF0240FF8FF005F7022 /* ProfileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE406EEF240FF8FF005F7022 /* ProfileCell.swift */; };
 		AE4AEE3522B1030D000AA495 /* PreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE4AEE3422B1030D000AA495 /* PreviewController.swift */; };
 		AE52EA19229EB53C00C586C9 /* ContactDetailHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE52EA18229EB53C00C586C9 /* ContactDetailHeader.swift */; };
 		AE52EA20229EB9F000C586C9 /* EditGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE52EA1F229EB9F000C586C9 /* EditGroupViewController.swift */; };
@@ -385,7 +382,6 @@
 		308FEA51246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMessageSizeCalculator.swift; sourceTree = "<group>"; };
 		3095A350237DD1F700AB07F7 /* MediaPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPicker.swift; sourceTree = "<group>"; };
 		30A2EC35247D72720024ADD8 /* AnimatedImageMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatedImageMessageCell.swift; sourceTree = "<group>"; };
-		30A4D9AD2332672600544344 /* QrInviteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrInviteViewController.swift; sourceTree = "<group>"; };
 		30AC265E237F1807002A943F /* AvatarHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarHelper.swift; sourceTree = "<group>"; };
 		30B0ACF924AB5B99004D5E29 /* SettingsEphemeralMessageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsEphemeralMessageController.swift; sourceTree = "<group>"; };
 		30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertificateCheckController.swift; sourceTree = "<group>"; };
@@ -409,7 +405,6 @@
 		789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeReaderController.swift; sourceTree = "<group>"; };
 		78C7036A21D46752005D4525 /* deltachat-ios.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "deltachat-ios.entitlements"; sourceTree = "<group>"; };
 		78E45E3921D3CFBC00D4B15E /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
-		78E45E3B21D3D03700D4B15E /* TextFieldTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldTableViewCell.swift; sourceTree = "<group>"; };
 		78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
 		78E45E4B21D404AE00D4B15E /* InfoMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoMessageCell.swift; sourceTree = "<group>"; };
 		78ED838221D5379000243125 /* TextFieldCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldCell.swift; sourceTree = "<group>"; };
@@ -437,7 +432,6 @@
 		AE25F08F22807AD800CDEA66 /* AvatarSelectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarSelectionCell.swift; sourceTree = "<group>"; };
 		AE38B31722672DFC00EC37A1 /* ActionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCell.swift; sourceTree = "<group>"; };
 		AE39D322249CFC1A007346A1 /* DocumentGalleryController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentGalleryController.swift; sourceTree = "<group>"; };
-		AE406EEF240FF8FF005F7022 /* ProfileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCell.swift; sourceTree = "<group>"; };
 		AE4AEE3422B1030D000AA495 /* PreviewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewController.swift; sourceTree = "<group>"; };
 		AE52EA18229EB53C00C586C9 /* ContactDetailHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDetailHeader.swift; sourceTree = "<group>"; };
 		AE52EA1F229EB9F000C586C9 /* EditGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditGroupViewController.swift; sourceTree = "<group>"; };
@@ -866,7 +860,6 @@
 		AE406EEE240FA454005F7022 /* Cell */ = {
 			isa = PBXGroup;
 			children = (
-				AE406EEF240FF8FF005F7022 /* ProfileCell.swift */,
 				AE0AA951247800E700D42A7F /* GalleryCell.swift */,
 				AE8DD450249D1DFB009A4BC1 /* FileTableViewCell.swift */,
 			);
@@ -926,7 +919,6 @@
 				AE4AEE3422B1030D000AA495 /* PreviewController.swift */,
 				AEA0F6A024474146009F887B /* ProfileInfoViewController.swift */,
 				789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */,
-				30A4D9AD2332672600544344 /* QrInviteViewController.swift */,
 				AECEF03D244F2D55006C90DA /* QrPageController.swift */,
 				30149D9222F21129003C12B5 /* QrViewController.swift */,
 				B21005DA23383664004C70C5 /* SettingsClassicViewController.swift */,
@@ -981,7 +973,6 @@
 				78ED839321D5AF8A00243125 /* QrCodeView.swift */,
 				78ED838221D5379000243125 /* TextFieldCell.swift */,
 				30260CA6238F02F700D8D52C /* MultilineTextFieldCell.swift */,
-				78E45E3B21D3D03700D4B15E /* TextFieldTableViewCell.swift */,
 				AE38B31722672DFC00EC37A1 /* ActionCell.swift */,
 				AE25F08F22807AD800CDEA66 /* AvatarSelectionCell.swift */,
 				AE728F14229D5C390047565B /* PhotoPickerAlertAction.swift */,
@@ -1366,7 +1357,6 @@
 				305961DC2346125100C80F33 /* MessagesLayoutDelegate.swift in Sources */,
 				3059620A2346125100C80F33 /* TextMessageSizeCalculator.swift in Sources */,
 				78ED839421D5AF8A00243125 /* QrCodeView.swift in Sources */,
-				AE406EF0240FF8FF005F7022 /* ProfileCell.swift in Sources */,
 				305961F02346125100C80F33 /* NSConstraintLayoutSet.swift in Sources */,
 				3059620E234614E700C80F33 /* DcContact+Extension.swift in Sources */,
 				AED423D7249F580700B6B2BB /* BlockedContactsViewController.swift in Sources */,
@@ -1405,7 +1395,6 @@
 				AEC67A1C241CE9E4007DDBE1 /* AppStateRestorer.swift in Sources */,
 				305961D32346125100C80F33 /* MessagesViewController+Keyboard.swift in Sources */,
 				305961EF2346125100C80F33 /* HorizontalEdgeInsets.swift in Sources */,
-				30A4D9AE2332672700544344 /* QrInviteViewController.swift in Sources */,
 				305961D62346125100C80F33 /* MessageInputBar.swift in Sources */,
 				305961ED2346125100C80F33 /* DetectorType.swift in Sources */,
 				305962062346125100C80F33 /* TypingIndicatorCellSizeCalculator.swift in Sources */,
@@ -1430,7 +1419,6 @@
 				3059620B2346125100C80F33 /* LocationMessageSizeCalculator.swift in Sources */,
 				305962072346125100C80F33 /* MessagesCollectionViewFlowLayout.swift in Sources */,
 				78ED838321D5379000243125 /* TextFieldCell.swift in Sources */,
-				78E45E3C21D3D03700D4B15E /* TextFieldTableViewCell.swift in Sources */,
 				AEFBE23123FF09B20045327A /* TypeAlias.swift in Sources */,
 				AE19887523EB264000B4CD5F /* HelpViewController.swift in Sources */,
 				305961D52346125100C80F33 /* MessagesViewController+Menu.swift in Sources */,

+ 0 - 2
deltachat-ios/Controller/AccountSetupController.swift

@@ -79,7 +79,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
         cell.tag = tagEmailCell
         cell.textField.addTarget(self, action: #selector(emailCellEdited), for: .editingChanged)
         cell.textField.tag = tagTextFieldEmail // will be used to eventually show oAuth-Dialogue when pressing return key
-        cell.textField.delegate = self
         cell.textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
         return cell
     }()
@@ -89,7 +88,6 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
         cell.tag = tagPasswordCell
         cell.textField.tag = tagTextFieldPassword  // will be used to eventually show oAuth-Dialogue when selecting
         cell.textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
-        cell.textField.delegate = self
         return cell
     }()
 

+ 11 - 24
deltachat-ios/Controller/AddGroupMembersViewController.swift

@@ -13,7 +13,15 @@ class AddGroupMembersViewController: GroupMembersViewController {
         return button
     }()
 
-    lazy var doneButton: UIBarButtonItem = {
+    private lazy var newContactCell: ActionCell = {
+        let cell = ActionCell()
+        cell.actionColor = SystemColor.blue.uiColor
+        cell.actionTitle = String.localized("menu_new_contact")
+        cell.selectionStyle = .none
+        return cell
+    }()
+
+    private lazy var doneButton: UIBarButtonItem = {
         let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonPressed))
         return button
     }()
@@ -99,20 +107,13 @@ class AddGroupMembersViewController: GroupMembersViewController {
     }
 
     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-        switch indexPath.section {
-        case sectionNewContact:
-            return Constants.defaultCellHeight
-        case sectionMemberList:
-            return ContactCell.cellHeight
-        default:
-            return Constants.defaultCellHeight
-        }
+        return indexPath.section == sectionMemberList ? ContactCell.cellHeight : UITableView.automaticDimension
     }
 
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         switch indexPath.section {
         case sectionNewContact:
-            return getNewContactCell()
+            return newContactCell
         case sectionMemberList:
             return updateContactCell(for: indexPath)
         default:
@@ -153,20 +154,6 @@ class AddGroupMembersViewController: GroupMembersViewController {
         navigationController?.popViewController(animated: true)
     }
 
-    func getNewContactCell() -> UITableViewCell {
-        let cell: UITableViewCell
-        if let c = tableView.dequeueReusableCell(withIdentifier: "actionCell") {
-            cell = c
-        } else {
-            cell = UITableViewCell(style: .default, reuseIdentifier: "actionCell")
-        }
-        cell.textLabel?.text = String.localized("menu_new_contact")
-        cell.textLabel?.textColor = view.tintColor
-        cell.textLabel?.textAlignment = .center
-
-        return cell
-    }
-
     // MARK: - coordinator
     private func showNewContactController() {
         let newContactController = NewContactController(dcContext: dcContext)

+ 19 - 23
deltachat-ios/Controller/ChatListController.swift

@@ -22,6 +22,11 @@ class ChatListController: UITableViewController {
         return searchController
     }()
 
+    private lazy var archiveCell: ActionCell = {
+        let actionCell = ActionCell()
+        return actionCell
+    }()
+
     private lazy var newButton: UIBarButtonItem = {
         let button = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.compose, target: self, action: #selector(didPressNewChat))
         button.tintColor = DcColors.primary
@@ -39,14 +44,6 @@ class ChatListController: UITableViewController {
         return label
     }()
 
-    func getArchiveCell(title: String) -> UITableViewCell {
-        let cell = UITableViewCell()
-        cell.textLabel?.textColor = .systemBlue
-        cell.textLabel?.text = title
-        cell.textLabel?.textAlignment = .center
-        return cell
-    }
-
     init(dcContext: DcContext, viewModel: ChatListViewModelProtocol) {
         self.viewModel = viewModel
         self.dcContext = dcContext
@@ -154,7 +151,7 @@ class ChatListController: UITableViewController {
         tableView.register(ContactCell.self, forCellReuseIdentifier: chatCellReuseIdentifier)
         tableView.register(ContactCell.self, forCellReuseIdentifier: deadDropCellReuseIdentifier)
         tableView.register(ContactCell.self, forCellReuseIdentifier: contactCellReuseIdentifier)
-        tableView.rowHeight = 80
+        tableView.rowHeight = ContactCell.cellHeight
     }
 
     // MARK: - actions
@@ -169,6 +166,12 @@ class ChatListController: UITableViewController {
         updateTitle()
     }
 
+    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+        if previousTraitCollection?.preferredContentSizeCategory !=
+            traitCollection.preferredContentSizeCategory {
+            tableView.rowHeight = ContactCell.cellHeight
+        }
+    }
     private func quitSearch(animated: Bool) {
         searchController.searchBar.text = nil
         self.viewModel.endSearch()
@@ -179,6 +182,7 @@ class ChatListController: UITableViewController {
 
     // MARK: - UITableViewDelegate + UITableViewDatasource
 
+    
     override func numberOfSections(in tableView: UITableView) -> Int {
         return viewModel.numberOfSections
     }
@@ -201,7 +205,8 @@ class ChatListController: UITableViewController {
         case .chat(let chatData):
             let chatId = chatData.chatId
             if chatId == DC_CHAT_ID_ARCHIVED_LINK {
-                return getArchiveCell(title: dcContext.getChat(chatId: chatId).name)
+                archiveCell.actionTitle = dcContext.getChat(chatId: chatId).name
+                return archiveCell
             } else if let chatCell = tableView.dequeueReusableCell(withIdentifier: chatCellReuseIdentifier, for: indexPath) as? ContactCell {
                 // default chatCell
                 chatCell.updateCell(cellViewModel: cellData)
@@ -213,6 +218,8 @@ class ChatListController: UITableViewController {
                 contactCell.updateCell(cellViewModel: cellData)
                 return contactCell
             }
+        case .profile:
+            safe_fatalError("CellData type profile not allowed")
         }
         safe_fatalError("Could not find/dequeue or recycle UITableViewCell.")
         return UITableViewCell()
@@ -242,6 +249,8 @@ class ChatListController: UITableViewController {
             } else {
                 self.askToChatWith(contactId: contactId)
             }
+        case .profile:
+            safe_fatalError("CellData type profile not allowed")
         }
         tableView.deselectRow(at: indexPath, animated: false)
     }
@@ -314,19 +323,6 @@ class ChatListController: UITableViewController {
         }
     }
 
-    func getArchiveCell(_ tableView: UITableView, title: String) -> UITableViewCell {
-        let archiveCell: UITableViewCell
-        if let cell = tableView.dequeueReusableCell(withIdentifier: "ArchiveCell") {
-            archiveCell = cell
-        } else {
-            archiveCell = UITableViewCell(style: .default, reuseIdentifier: "ArchiveCell")
-        }
-        archiveCell.textLabel?.textAlignment = .center
-        archiveCell.textLabel?.text = title
-        archiveCell.textLabel?.textColor = UIColor.systemBlue
-        return archiveCell
-    }
-
     // MARK: - alerts
     private func showDeleteChatConfirmationAlert(chatId: Int) {
         let alert = UIAlertController(

+ 13 - 9
deltachat-ios/Controller/ContactDetailViewController.swift

@@ -67,7 +67,7 @@ class ContactDetailViewController: UITableViewController {
     }()
 
     private lazy var galleryCell: UITableViewCell = {
-        let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
+        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("gallery")
         cell.accessoryType = .disclosureIndicator
         if viewModel.chatId == 0 {
@@ -78,7 +78,7 @@ class ContactDetailViewController: UITableViewController {
     }()
 
     private lazy var documentsCell: UITableViewCell = {
-        let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
+        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("documents")
         cell.accessoryType = .disclosureIndicator
         if viewModel.chatId == 0 {
@@ -120,10 +120,18 @@ class ContactDetailViewController: UITableViewController {
         tableView.register(ContactCell.self, forCellReuseIdentifier: ContactCell.reuseIdentifier)
         headerCell.frame = CGRect(0, 0, tableView.frame.width, ContactCell.cellHeight)
         tableView.tableHeaderView = headerCell
+        tableView.sectionHeaderHeight =  UITableView.automaticDimension
+        tableView.rowHeight = UITableView.automaticDimension
     }
 
     // MARK: - UITableViewDatasource, UITableViewDelegate
-
+    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+        if previousTraitCollection?.preferredContentSizeCategory !=
+            traitCollection.preferredContentSizeCategory {
+            headerCell.frame = CGRect(0, 0, tableView.frame.width, ContactCell.cellHeight)
+        }
+    }
+    
     override func numberOfSections(in tableView: UITableView) -> Int {
         return viewModel.numberOfSections
     }
@@ -183,10 +191,10 @@ class ContactDetailViewController: UITableViewController {
     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
         let type = viewModel.typeFor(section: indexPath.section)
         switch type {
-        case .chatActions, .chatOptions:
-            return Constants.defaultCellHeight
         case .sharedChats:
             return ContactCell.cellHeight
+        default:
+            return UITableView.automaticDimension
         }
     }
 
@@ -194,10 +202,6 @@ class ContactDetailViewController: UITableViewController {
         return viewModel.titleFor(section: section)
     }
 
-    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        return Constants.defaultHeaderHeight
-    }
-
     // MARK: - updates
     private func updateHeader() {
         headerCell.updateDetails(title: viewModel.contact.displayName, subtitle: viewModel.contact.email)

+ 1 - 7
deltachat-ios/Controller/EditGroupViewController.swift

@@ -51,6 +51,7 @@ class EditGroupViewController: UITableViewController, MediaPickerDelegate {
         super.viewDidLoad()
         navigationItem.rightBarButtonItem = doneButton
         navigationItem.leftBarButtonItem = cancelButton
+        tableView.rowHeight = UITableView.automaticDimension
     }
 
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@@ -68,13 +69,6 @@ class EditGroupViewController: UITableViewController, MediaPickerDelegate {
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         return 2
     }
-
-    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-        if indexPath.row == rowAvatar {
-            return AvatarSelectionCell.cellHeight
-        }
-        return Constants.defaultCellHeight
-    }
     
     @objc func saveContactButtonPressed() {
         let newName = groupNameCell.getText()

+ 2 - 16
deltachat-ios/Controller/EditSettingsController.swift

@@ -32,7 +32,7 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
     }()
 
     private lazy var accountSettingsCell: UITableViewCell = {
-        let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
+        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("pref_password_and_account_settings")
         cell.accessoryType = .disclosureIndicator
         cell.tag = tagAccountSettingsCell
@@ -65,6 +65,7 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
         avatarSelectionCell.onAvatarTapped = { [weak self] in
             self?.onAvatarTapped()
         }
+        tableView.rowHeight = UITableView.automaticDimension
     }
 
     override func viewWillDisappear(_ animated: Bool) {
@@ -102,21 +103,6 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
         }
     }
 
-    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-        if indexPath.section == section1 {
-            switch indexPath.row {
-            case section1Avatar:
-                return AvatarSelectionCell.cellHeight
-            case section1Status:
-                return MultilineTextFieldCell.cellHeight
-            default:
-                 return Constants.defaultCellHeight
-            }
-        } else {
-            return Constants.defaultCellHeight
-        }
-    }
-
     override func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? {
         if section == section1 {
             return String.localized("pref_who_can_see_profile_explain")

+ 19 - 17
deltachat-ios/Controller/GroupChatDetailViewController.swift

@@ -132,14 +132,14 @@ class GroupChatDetailViewController: UIViewController {
     }()
 
     private lazy var galleryCell: UITableViewCell = {
-        let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
+        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("gallery")
         cell.accessoryType = .disclosureIndicator
         return cell
     }()
 
     private lazy var documentsCell: UITableViewCell = {
-        let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
+        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
         cell.textLabel?.text = String.localized("documents")
         cell.accessoryType = .disclosureIndicator
         return cell
@@ -183,6 +183,13 @@ class GroupChatDetailViewController: UIViewController {
         updateHeader()
     }
 
+    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+        if previousTraitCollection?.preferredContentSizeCategory !=
+            traitCollection.preferredContentSizeCategory {
+            groupHeader.frame = CGRect(0, 0, tableView.frame.width, ContactCell.cellHeight)
+        }
+    }
+
     // MARK: - update
     private func updateGroupMembers() {
         groupMemberIds = chat.contactIds
@@ -237,7 +244,12 @@ class GroupChatDetailViewController: UIViewController {
     }
 
     private func showQrCodeInvite(chatId: Int) {
-        let qrInviteCodeController = QrInviteViewController(dcContext: dcContext, chatId: chatId)
+        var hint = ""
+        let dcChat = dcContext.getChat(chatId: chatId)
+        if !dcChat.name.isEmpty {
+            hint = String.localizedStringWithFormat(String.localized("qrshow_join_group_hint"), dcChat.name)
+        }
+        let qrInviteCodeController = QrViewController(dcContext: dcContext, chatId: chatId, qrCodeHint: hint)
         navigationController?.pushViewController(qrInviteCodeController, animated: true)
     }
 
@@ -306,16 +318,10 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
         let sectionType = sections[indexPath.section]
         let row = indexPath.row
-        switch sectionType {
-        case .chatOptions, .chatActions:
-            return Constants.defaultCellHeight
-        case .members:
-            switch row {
-            case membersRowAddMembers, membersRowQrInvite:
-                return Constants.defaultCellHeight
-            default:
-                return ContactCell.cellHeight
-            }
+        if sectionType == .members && row != membersRowAddMembers && row != membersRowQrInvite {
+            return ContactCell.cellHeight
+        } else {
+            return UITableView.automaticDimension
         }
     }
 
@@ -425,10 +431,6 @@ extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSou
         return nil
     }
 
-    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        return Constants.defaultHeaderHeight
-    }
-
     func tableView(_: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
         guard let currentUser = self.currentUser else {
             return false

+ 2 - 2
deltachat-ios/Controller/NewChatViewController.swift

@@ -130,12 +130,12 @@ class NewChatViewController: UITableViewController {
     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
         let section = indexPath.section
         if section == sectionNew {
-           return Constants.defaultCellHeight
+            return UITableView.automaticDimension
         } else if section == sectionImportedContacts {
             if deviceContactAccessGranted {
                 return ContactCell.cellHeight
             } else {
-                return Constants.defaultCellHeight
+                return UITableView.automaticDimension
             }
         } else {
             return ContactCell.cellHeight

+ 2 - 2
deltachat-ios/Controller/NewContactController.swift

@@ -32,8 +32,8 @@ class NewContactController: UITableViewController {
         self.dcContext = dcContext
         cells = [emailCell, nameCell]
         super.init(style: .grouped)
-        emailCell.textField.delegate = self
-        nameCell.textField.delegate = self
+        emailCell.textFieldDelegate = self
+        nameCell.textFieldDelegate = self
 
         // always show return key with name field, because
         // name is optional

+ 8 - 10
deltachat-ios/Controller/NewGroupController.swift

@@ -201,16 +201,9 @@ class NewGroupController: UITableViewController, MediaPickerDelegate {
 
     override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
         let section = indexPath.section
-        let row = indexPath.row
         switch section {
-        case sectionGroupDetails:
-            if row == sectionGroupDetailsRowAvatar {
-                return AvatarSelectionCell.cellHeight
-            } else {
-                return Constants.defaultCellHeight
-            }
-        case sectionInvite:
-            return Constants.defaultCellHeight
+        case sectionGroupDetails, sectionInvite:
+            return UITableView.automaticDimension
         default:
             return ContactCell.cellHeight
         }
@@ -359,7 +352,12 @@ class NewGroupController: UITableViewController, MediaPickerDelegate {
     }
 
     private func showQrCodeInvite(chatId: Int) {
-        let qrInviteCodeController = QrInviteViewController(dcContext: dcContext, chatId: chatId)
+        var hint = ""
+        let dcChat = dcContext.getChat(chatId: chatId)
+        if !dcChat.name.isEmpty {
+            hint = String.localizedStringWithFormat(String.localized("qrshow_join_group_hint"), dcChat.name)
+        }
+        let qrInviteCodeController = QrViewController(dcContext: dcContext, chatId: chatId, qrCodeHint: hint)
         qrInviteCodeController.onDismissed = { [weak self] in
             self?.updateGroupContactIdsOnQRCodeInvite()
         }

+ 1 - 10
deltachat-ios/Controller/ProfileInfoViewController.swift

@@ -46,7 +46,6 @@ class ProfileInfoViewController: UITableViewController {
     init(context: DcContext) {
         self.dcContext = context
         super.init(style: .grouped)
-        tableView.estimatedRowHeight = Constants.defaultCellHeight
     }
 
     required init?(coder: NSCoder) {
@@ -58,6 +57,7 @@ class ProfileInfoViewController: UITableViewController {
         super.viewDidLoad()
         title = String.localized("pref_profile_info_headline")
         navigationItem.rightBarButtonItem = doneButtonItem
+        tableView.rowHeight = UITableView.automaticDimension
     }
 
     // MARK: - tableviewDelegate
@@ -69,15 +69,6 @@ class ProfileInfoViewController: UITableViewController {
         return cells[indexPath.row]
     }
 
-    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-
-        let cell = cells[indexPath.row]
-        if cell is AvatarSelectionCell {
-            return AvatarSelectionCell.cellHeight
-        }
-        return Constants.defaultCellHeight
-    }
-
     override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
         let email = dcContext.addr ?? ""
         let footerTitle = String.localizedStringWithFormat(

+ 5 - 1
deltachat-ios/Controller/QrCodeReaderController.swift

@@ -21,6 +21,9 @@ class QrCodeReaderController: UIViewController {
         label.numberOfLines = 0
         label.textAlignment = .center
         label.textColor = .white
+        label.adjustsFontForContentSizeCategory = true
+        label.font = .preferredFont(forTextStyle: .subheadline)
+
         return label
     }()
 
@@ -85,8 +88,9 @@ class QrCodeReaderController: UIViewController {
         view.addSubview(infoLabel)
         infoLabel.translatesAutoresizingMaskIntoConstraints = false
 
-        infoLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
         infoLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
+        infoLabel.constraintAlignLeadingTo(view, paddingLeading: 5).isActive = true
+        infoLabel.constraintAlignTrailingTo(view, paddingTrailing: 5).isActive = true
         view.bringSubviewToFront(infoLabel)
     }
 

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

@@ -1,120 +0,0 @@
-import Foundation
-import UIKit
-import DcCore
-
-class QrInviteViewController: UITableViewController {
-    private let rowQRCode = 0
-    private let rowDescription = 1
-
-    let dcContext: DcContext
-    let chatId: Int
-
-    var onDismissed: (() -> Void)?
-
-    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 viewDidDisappear(_ animated: Bool) {
-        onDismissed?()
-    }
-
-    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 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 = dcContext.getChat(chatId: 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
-    }
-}

+ 17 - 3
deltachat-ios/Controller/QrPageController.swift

@@ -9,6 +9,18 @@ class QrPageController: UIPageViewController, ProgressAlertHandler {
 
     private var selectedIndex: Int = 0
 
+    private lazy var qrCodeHint: String = {
+        var qrCodeHint = ""
+        if dcContext.isConfigured() {
+            let contact = DcContact(id: Int(DC_CONTACT_ID_SELF))
+            qrCodeHint = String.localizedStringWithFormat(
+                String.localized("qrshow_join_contact_hint"),
+                contact.email
+            )
+        }
+        return qrCodeHint
+    }()
+
     private lazy var qrSegmentControl: UISegmentedControl = {
         let control = UISegmentedControl(
             items: [String.localized("qrshow_title"), String.localized("qrscan_title")]
@@ -35,7 +47,7 @@ class QrPageController: UIPageViewController, ProgressAlertHandler {
         delegate = self
         navigationItem.titleView = qrSegmentControl
 
-        let qrController = QrViewController(dcContext: dcContext)
+        let qrController = QrViewController(dcContext: dcContext, qrCodeHint: qrCodeHint)
         setViewControllers(
             [qrController],
             direction: .forward,
@@ -60,10 +72,12 @@ class QrPageController: UIPageViewController, ProgressAlertHandler {
         self.progressObserver = nil
     }
 
+
+
     // MARK: - actions
     @objc private func qrSegmentControlChanged(_ sender: UISegmentedControl) {
         if sender.selectedSegmentIndex == 0 {
-            let qrController = QrViewController(dcContext: dcContext)
+            let qrController = QrViewController(dcContext: dcContext, qrCodeHint: qrCodeHint)
             setViewControllers([qrController], direction: .reverse, animated: true, completion: nil)
         } else {
             let qrCodeReaderController = makeQRReader()
@@ -99,7 +113,7 @@ extension QrPageController: UIPageViewControllerDataSource, UIPageViewController
         if viewController is QrViewController {
             return nil
         }
-        return QrViewController(dcContext: dcContext)
+        return QrViewController(dcContext: dcContext, qrCodeHint: qrCodeHint)
     }
 
     func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

+ 18 - 26
deltachat-ios/Controller/QrViewController.swift

@@ -6,13 +6,7 @@ class QrViewController: UIViewController {
 
     private let dcContext: DcContext
 
-    private var contact: DcContact? {
-        // This is nil if we do not have an account setup yet
-        if !dcContext.isConfigured() {
-            return nil
-        }
-        return DcContact(id: Int(DC_CONTACT_ID_SELF))
-    }
+    var onDismissed: (() -> Void)?
 
     private lazy var scrollView: UIScrollView = {
         let scrollView = UIScrollView()
@@ -21,14 +15,19 @@ class QrViewController: UIViewController {
     }()
 
     private lazy var qrContentView: QrViewContentView = {
-        let qrCode = dcContext.getSecurejoinQr(chatId: 0)
-        let view = QrViewContentView(contact: contact, qrCode: qrCode)
+        let qrCode = dcContext.getSecurejoinQr(chatId: chatId)
+        let view = QrViewContentView(qrCode: qrCode, hint: qrCodeHint)
         view.translatesAutoresizingMaskIntoConstraints = false
         return view
     }()
 
-    init(dcContext: DcContext) {
+    private let qrCodeHint: String
+    private let chatId: Int
+
+    init(dcContext: DcContext, chatId: Int? = 0, qrCodeHint: String?) {
         self.dcContext = dcContext
+        self.chatId = chatId ?? 0
+        self.qrCodeHint = qrCodeHint ?? ""
         super.init(nibName: nil, bundle: nil)
     }
 
@@ -41,6 +40,7 @@ class QrViewController: UIViewController {
         super.viewDidLoad()
         title = String.localized("qr_code")
         setupSubviews()
+        view.backgroundColor = DcColors.defaultBackgroundColor
     }
 
     override func viewDidLayoutSubviews() {
@@ -54,6 +54,10 @@ class QrViewController: UIViewController {
         scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
     }
 
+    override func viewDidDisappear(_ animated: Bool) {
+        onDismissed?()
+    }
+
     // MARK: - setup
     private func setupSubviews() {
         view.addSubview(scrollView)
@@ -77,14 +81,6 @@ class QrViewController: UIViewController {
         frameGuide.widthAnchor.constraint(equalTo: contentGuide.widthAnchor).isActive = true
     }
 
-    // MARK: - actions
-    private func displayNewChat(contactId: Int) {
-        let chatId = dcContext.createChatByContactId(contactId: contactId)
-        let chatVC = ChatViewController(dcContext: dcContext, chatId: Int(chatId))
-
-        chatVC.hidesBottomBarWhenPushed = true
-        navigationController?.pushViewController(chatVC, animated: true)
-    }
 }
 
 // MARK: - QrViewContentView
@@ -100,7 +96,8 @@ class QrViewContentView: UIView {
         label.lineBreakMode = .byWordWrapping
         label.numberOfLines = 0
         label.textAlignment = .center
-        label.font = UIFont.systemFont(ofSize: 14)
+        label.font = .preferredFont(forTextStyle: .subheadline)
+        label.adjustsFontForContentSizeCategory = true
         return label
     }()
 
@@ -116,14 +113,9 @@ class QrViewContentView: UIView {
         return container.heightAnchor.constraint(greaterThanOrEqualToConstant: 0)
     }()
 
-    init(contact: DcContact?, qrCode: String?) {
+    init(qrCode: String?, hint: String) {
         super.init(frame: .zero)
-        if let contact = contact {
-            hintLabel.text = String.localizedStringWithFormat(
-                String.localized("qrshow_join_contact_hint"),
-                contact.email
-            )
-        }
+        hintLabel.text = hint
         if let qrCode = qrCode {
             qrCodeView.generateCode(
                 qrCode,

+ 16 - 13
deltachat-ios/Controller/SettingsController.swift

@@ -36,14 +36,12 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
 
     // MARK: - cells
 
-    private let profileHeader = ContactDetailHeader()
-
-    private lazy var profileCell: ProfileCell = {
-        let displayName = dcContext.displayname ?? String.localized("pref_your_name")
-        let email = dcContext.addr ?? ""
-        let selfContact = DcContact(id: Int(DC_CONTACT_ID_SELF))
-        let cell = ProfileCell(contact: selfContact, displayName: displayName, address: email)
+    private lazy var profileCell: ContactCell = {
+        let cell = ContactCell(style: .default, reuseIdentifier: "profile_cell")
+        let cellViewModel = ProfileViewModell(context: dcContext)
+        cell.updateCell(cellViewModel: cellViewModel)
         cell.tag = CellTags.profile.rawValue
+        cell.accessoryType = .disclosureIndicator
         return cell
     }()
 
@@ -228,6 +226,7 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
         let backButton = UIBarButtonItem(title: String.localized("menu_settings"), style: .plain, target: nil, action: nil)
         navigationItem.backBarButtonItem = backButton
         documentInteractionController.delegate = self as? UIDocumentInteractionControllerDelegate
+        tableView.rowHeight = UITableView.automaticDimension
     }
 
     override func viewWillAppear(_ animated: Bool) {
@@ -253,6 +252,15 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
 
     // MARK: - UITableViewDelegate + UITableViewDatasource
 
+
+    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        if indexPath.section == 0 && indexPath.row == 0 {
+            return ContactCell.cellHeight
+        } else {
+            return UITableView.automaticDimension
+        }
+    }
+
     override func numberOfSections(in tableView: UITableView) -> Int {
         return sections.count
     }
@@ -428,14 +436,9 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
 
     // MARK: - updates
     private func updateCells() {
-        let displayName = dcContext.displayname ?? String.localized("pref_your_name")
-        let email = dcContext.addr ?? ""
-        let selfContact = DcContact(id: Int(DC_CONTACT_ID_SELF))
-        profileCell.update(contact: selfContact, displayName: displayName, address: email)
-
+        profileCell.updateCell(cellViewModel: ProfileViewModell(context: dcContext))
         showEmailsCell.detailTextLabel?.text = SettingsClassicViewController.getValString(val: dcContext.showEmails)
         mediaQualityCell.detailTextLabel?.text = MediaQualityController.getValString(val: dcContext.getConfigInt("media_quality"))
-
         autodelCell.detailTextLabel?.text = autodelSummary()
     }
 

+ 10 - 0
deltachat-ios/Extensions/Extensions.swift

@@ -84,3 +84,13 @@ extension UITableView {
         }
     }
 }
+
+extension UIFont {
+    static func preferredFont(for style: TextStyle, weight: Weight) -> UIFont {
+        let traits = UITraitCollection(preferredContentSizeCategory: .large)
+        let desc = UIFontDescriptor.preferredFontDescriptor(withTextStyle: style, compatibleWith: traits)
+        let font = UIFont.systemFont(ofSize: desc.pointSize, weight: weight)
+        let metrics = UIFontMetrics(forTextStyle: style)
+        return metrics.scaledFont(for: font)
+    }
+}

+ 6 - 0
deltachat-ios/Extensions/String+Extension.swift

@@ -74,6 +74,12 @@ extension String {
         return attributedText
     }
 
+    func bold(fontSize: CGFloat) -> NSAttributedString {
+        let attributedText = NSMutableAttributedString(string: self)
+        attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: fontSize), range: NSRange(location: 0, length: count - 1))
+        return attributedText
+    }
+
     static func timeStringForInterval(_ interval: TimeInterval) -> String {
         let time = NSInteger(interval)
         let seconds = time % 60

+ 84 - 28
deltachat-ios/Extensions/UIView+Extensions.swift

@@ -33,20 +33,36 @@ internal extension UIView {
         self.layer.borderWidth = 2
     }
 
-    func alignLeadingToAnchor(_ anchor: NSLayoutXAxisAnchor, paddingLeading: CGFloat = 0.0) {
-        self.leadingAnchor.constraint(equalTo: anchor, constant: paddingLeading).isActive = true
+    func alignLeadingToAnchor(_ anchor: NSLayoutXAxisAnchor, paddingLeading: CGFloat = 0.0, priority: UILayoutPriority? = .none) {
+        let constraint = self.leadingAnchor.constraint(equalTo: anchor, constant: paddingLeading)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        constraint.isActive = true
     }
 
-    func alignTrailingToAnchor(_ anchor: NSLayoutXAxisAnchor, paddingTrailing: CGFloat = 0.0) {
-        self.trailingAnchor.constraint(equalTo: anchor, constant: -paddingTrailing).isActive = true
+    func alignTrailingToAnchor(_ anchor: NSLayoutXAxisAnchor, paddingTrailing: CGFloat = 0.0, priority: UILayoutPriority? = .none) {
+        let constraint = self.trailingAnchor.constraint(equalTo: anchor, constant: -paddingTrailing)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        constraint.isActive = true
     }
 
-    func alignTopToAnchor(_ anchor: NSLayoutYAxisAnchor, paddingTop: CGFloat = 0.0) {
-        self.topAnchor.constraint(equalTo: anchor, constant: paddingTop).isActive = true
+    func alignTopToAnchor(_ anchor: NSLayoutYAxisAnchor, paddingTop: CGFloat = 0.0, priority: UILayoutPriority? = .none) {
+        let constraint = self.topAnchor.constraint(equalTo: anchor, constant: paddingTop)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        constraint.isActive = true
     }
 
-    func alignBottomToAnchor(_ anchor: NSLayoutYAxisAnchor, paddingBottom: CGFloat = 0.0) {
-        self.bottomAnchor.constraint(equalTo: anchor, constant: -paddingBottom).isActive = true
+    func alignBottomToAnchor(_ anchor: NSLayoutYAxisAnchor, paddingBottom: CGFloat = 0.0, priority: UILayoutPriority? = .none) {
+        let constraint = self.bottomAnchor.constraint(equalTo: anchor, constant: -paddingBottom)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        constraint.isActive = true
     }
 
     func fill(view: UIView, paddingLeading: CGFloat? = 0.0, paddingTrailing: CGFloat? = 0.0, paddingTop: CGFloat? = 0.0, paddingBottom: CGFloat? = 0.0) {
@@ -60,8 +76,8 @@ internal extension UIView {
         return constraintAlignTopTo(view, paddingTop: 0.0)
     }
 
-    func constraintAlignTopTo(_ view: UIView, paddingTop: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(
+    func constraintAlignTopTo(_ view: UIView, paddingTop: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
             item: self,
             attribute: .top,
             relatedBy: .equal,
@@ -69,10 +85,14 @@ internal extension UIView {
             attribute: .top,
             multiplier: 1.0,
             constant: paddingTop)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintAlignBottomTo(_ view: UIView, paddingBottom: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(
+    func constraintAlignBottomTo(_ view: UIView, paddingBottom: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
             item: self,
             attribute: .bottom,
             relatedBy: .equal,
@@ -80,10 +100,14 @@ internal extension UIView {
             attribute: .bottom,
             multiplier: 1.0,
             constant: -paddingBottom)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintAlignLeadingTo(_ view: UIView, paddingLeading: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(
+    func constraintAlignLeadingTo(_ view: UIView, paddingLeading: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
             item: self,
             attribute: .leading,
             relatedBy: .equal,
@@ -91,10 +115,14 @@ internal extension UIView {
             attribute: .leading,
             multiplier: 1.0,
             constant: paddingLeading)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintAlignTrailingTo(_ view: UIView, paddingTrailing: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(
+    func constraintAlignTrailingTo(_ view: UIView, paddingTrailing: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
             item: self,
             attribute: .trailing,
             relatedBy: .equal,
@@ -102,10 +130,14 @@ internal extension UIView {
             attribute: .trailing,
             multiplier: 1.0,
             constant: -paddingTrailing)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintToBottomOf(_ view: UIView, paddingTop: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(
+    func constraintToBottomOf(_ view: UIView, paddingTop: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
             item: self,
             attribute: .top,
             relatedBy: .equal,
@@ -113,10 +145,14 @@ internal extension UIView {
             attribute: .bottom,
             multiplier: 1.0,
             constant: paddingTop)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintToTrailingOf(_ view: UIView, paddingLeading: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(
+    func constraintToTrailingOf(_ view: UIView, paddingLeading: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
             item: self,
             attribute: .leading,
             relatedBy: .equal,
@@ -124,35 +160,55 @@ internal extension UIView {
             attribute: .trailing,
             multiplier: 1.0,
             constant: paddingLeading)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
 
-    func constraintCenterXTo(_ view: UIView, paddingX: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(item: self,
+    func constraintCenterXTo(_ view: UIView, paddingX: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(item: self,
                                   attribute: .centerX,
                                   relatedBy: .equal,
                                   toItem: view,
                                   attribute: .centerX,
                                   multiplier: 1.0,
                                   constant: paddingX)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintCenterYTo(_ view: UIView, paddingY: CGFloat = 0.0) -> NSLayoutConstraint {
-        return NSLayoutConstraint(item: self,
+    func constraintCenterYTo(_ view: UIView, paddingY: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(item: self,
                                   attribute: .centerY,
                                   relatedBy: .equal,
                                   toItem: view,
                                   attribute: .centerY,
                                   multiplier: 1.0,
                                   constant: paddingY)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintHeightTo(_ height: CGFloat) -> NSLayoutConstraint {
-        return heightAnchor.constraint(equalToConstant: height)
+    func constraintHeightTo(_ height: CGFloat, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = heightAnchor.constraint(equalToConstant: height)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
-    func constraintWidthTo(_ width: CGFloat) -> NSLayoutConstraint {
-       return  widthAnchor.constraint(equalToConstant: width)
+    func constraintWidthTo(_ width: CGFloat, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = widthAnchor.constraint(equalToConstant: width)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
     }
 
     func fillSuperview() {

+ 0 - 6
deltachat-ios/Helper/Constants.swift

@@ -11,14 +11,8 @@ struct Constants {
         static let deltachatImapPasswordKey = "__DELTACHAT_IMAP_PASSWORD_KEY__"
     }
 
-    static let defaultShadow = UIImage(color: UIColor(hexString: "ff2b82"), size: CGSize(width: 1, height: 1))
-    static let onlineShadow = UIImage(color: UIColor(hexString: "3ed67e"), size: CGSize(width: 1, height: 1))
-
     static let notificationIdentifier = "deltachat-ios-local-notifications"
 
-    static let defaultCellHeight: CGFloat = 48
-    static let defaultHeaderHeight: CGFloat = 20
-
 }
 
 struct Time {

+ 2 - 1
deltachat-ios/MessageKit/Views/AudioPlayerView.swift

@@ -19,7 +19,8 @@ open class AudioPlayerView: UIView {
     private lazy var durationLabel: UILabel = {
         let durationLabel = UILabel(frame: CGRect.zero)
         durationLabel.textAlignment = .right
-        durationLabel.font = UIFont.systemFont(ofSize: 14)
+        durationLabel.font = UIFont.preferredFont(forTextStyle: .body)
+        durationLabel.adjustsFontForContentSizeCategory = true
         durationLabel.text = "0:00"
         durationLabel.translatesAutoresizingMaskIntoConstraints = false
         return durationLabel

+ 11 - 2
deltachat-ios/View/ActionCell.swift

@@ -22,6 +22,10 @@ class ActionCell: UITableViewCell {
         let label = UILabel()
         label.text = actionTitle
         label.textColor = UIColor.systemBlue
+        label.font = .preferredFont(forTextStyle: .body)
+        label.adjustsFontForContentSizeCategory = true
+        label.textAlignment = .center
+        label.numberOfLines = 0
         return label
     }()
 
@@ -43,7 +47,12 @@ class ActionCell: UITableViewCell {
     private func setupSubviews() {
         contentView.addSubview(actionLabel)
         actionLabel.translatesAutoresizingMaskIntoConstraints = false
-        actionLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor, constant: 0).isActive = true
-        actionLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0).isActive = true
+        contentView.addConstraints([
+            actionLabel.constraintAlignLeadingTo(contentView, paddingLeading: 12),
+            actionLabel.constraintAlignTrailingTo(contentView, paddingTrailing: 12),
+            actionLabel.constraintAlignTopTo(contentView, paddingTop: 12),
+            actionLabel.constraintAlignBottomTo(contentView, paddingBottom: 12)
+
+        ])
     }
 }

+ 4 - 2
deltachat-ios/View/AvatarSelectionCell.swift

@@ -3,7 +3,6 @@ import DcCore
 
 class AvatarSelectionCell: UITableViewCell {
     let badgeSize: CGFloat = 72
-    static let cellHeight: CGFloat = 98
 
     var onAvatarTapped: (() -> Void)?
 
@@ -25,6 +24,8 @@ class AvatarSelectionCell: UITableViewCell {
         label.translatesAutoresizingMaskIntoConstraints = false
         label.textColor = DcColors.defaultTextColor
         label.text = String.localized("pref_profile_photo")
+        label.font = .preferredFont(forTextStyle: .body)
+        label.adjustsFontForContentSizeCategory = true
         return label
     }()
 
@@ -54,12 +55,13 @@ class AvatarSelectionCell: UITableViewCell {
         contentView.addSubview(badge)
         badge.alignTrailingToAnchor(contentView.layoutMarginsGuide.trailingAnchor)
         badge.alignTopToAnchor(contentView.layoutMarginsGuide.topAnchor)
+        badge.alignBottomToAnchor(contentView.layoutMarginsGuide.bottomAnchor)
 
         contentView.addSubview(hintLabel)
         hintLabel.alignLeadingToAnchor(contentView.layoutMarginsGuide.leadingAnchor)
         hintLabel.alignTopToAnchor(contentView.layoutMarginsGuide.topAnchor)
         hintLabel.alignTrailingToAnchor(badge.leadingAnchor)
-        hintLabel.alignBottomToAnchor(contentView.layoutMarginsGuide.bottomAnchor)
+        hintLabel.alignBottomToAnchor(contentView.layoutMarginsGuide.bottomAnchor, priority: .defaultLow)
 
         let touchListener = UILongPressGestureRecognizer(target: self, action: #selector(onBadgeTouched))
         touchListener.minimumPressDuration = 0

+ 0 - 41
deltachat-ios/View/Cell/ProfileCell.swift

@@ -1,41 +0,0 @@
-import UIKit
-import DcCore
-
-class ProfileCell: UITableViewCell {
-
-    private let detailView = ContactDetailHeader()
-
-    init(contact: DcContact, displayName: String?, address: String?) {
-        super.init(style: .default, reuseIdentifier: nil)
-        accessoryType = .disclosureIndicator
-        setupSubviews()
-        update(contact: contact, displayName: displayName, address: address)
-        detailView.backgroundColor = .clear
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    private func setupSubviews() {
-        contentView.addSubview(detailView)
-        detailView.translatesAutoresizingMaskIntoConstraints = false
-        detailView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0).isActive = true
-        detailView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true
-        detailView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0).isActive = true
-        detailView.trailingAnchor.constraint(equalTo: accessoryView?.trailingAnchor ?? contentView.trailingAnchor, constant: 0).isActive = true
-        let heightConstraint = detailView.heightAnchor.constraint(equalToConstant: ContactDetailHeader.headerHeight)
-        heightConstraint.priority = .defaultLow
-        heightConstraint.isActive = true
-    }
-
-    func update(contact: DcContact, displayName: String?, address: String?) {
-        let email = address ?? contact.email
-        detailView.updateDetails(title: displayName ?? contact.displayName, subtitle: email)
-        if let image = contact.profileImage {
-            detailView.setImage(image)
-        } else {
-            detailView.setBackupImage(name: displayName ?? email, color: contact.color)
-        }
-    }
-}

+ 80 - 14
deltachat-ios/View/ContactCell.swift

@@ -8,7 +8,17 @@ protocol ContactCellDelegate: class {
 class ContactCell: UITableViewCell {
 
     static let reuseIdentifier = "contact_cell_reuse_identifier"
-    static let cellHeight: CGFloat = 74.5
+    static var cellHeight: CGFloat {
+        let textHeight = UIFont.preferredFont(forTextStyle: .headline).pointSize + UIFont.preferredFont(forTextStyle: .subheadline).pointSize + 24
+        if textHeight > 74.5 {
+            return textHeight
+        }
+        return 74.5
+    }
+
+    var isLargeText: Bool {
+        return UIFont.preferredFont(forTextStyle: .body).pointSize > 36
+    }
 
     weak var delegate: ContactCellDelegate?
     private let badgeSize: CGFloat = 54
@@ -26,6 +36,7 @@ class ContactCell: UITableViewCell {
         let stackView = UIStackView(arrangedSubviews: [subtitleLabel, deliveryStatusIndicator, archivedIndicator, unreadMessageCounter])
         stackView.axis = .horizontal
         stackView.spacing = 10
+        stackView.alignment = .center
         return stackView
     }()
 
@@ -38,62 +49,63 @@ class ContactCell: UITableViewCell {
 
     let titleLabel: UILabel = {
         let label = UILabel()
-        label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
         label.lineBreakMode = .byTruncatingTail
         label.textColor = DcColors.defaultTextColor
         label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1), for: NSLayoutConstraint.Axis.horizontal)
+        label.font = UIFont.preferredFont(for: .body, weight: .medium)
+        label.adjustsFontForContentSizeCategory = true
         return label
     }()
 
     private let pinnedIndicator: UIImageView = {
         let view = UIImageView()
         view.translatesAutoresizingMaskIntoConstraints = false
-        view.heightAnchor.constraint(equalToConstant: 16).isActive = true
         view.widthAnchor.constraint(equalToConstant: 16).isActive = true
         view.tintColor = DcColors.middleGray
         view.image = #imageLiteral(resourceName: "pinned_chatlist").withRenderingMode(.alwaysTemplate)
         view.isHidden = true
+        view.contentMode = .scaleAspectFit
         return view
     }()
 
     private let mutedIndicator: UIImageView = {
         let view = UIImageView()
         view.translatesAutoresizingMaskIntoConstraints = false
-        view.heightAnchor.constraint(equalToConstant: 16).isActive = true
         view.widthAnchor.constraint(equalToConstant: 16).isActive = true
         view.tintColor = DcColors.middleGray
         view.image = #imageLiteral(resourceName: "volume_off").withRenderingMode(.alwaysTemplate)
         view.isHidden = true
+        view.contentMode = .scaleAspectFit
         return view
     }()
 
     private let timeLabel: UILabel = {
         let label = UILabel()
-        label.font = UIFont.systemFont(ofSize: 14)
+        label.font = UIFont.preferredFont(forTextStyle: .subheadline)
+        label.adjustsFontForContentSizeCategory = true
         label.textColor = DcColors.middleGray
         label.textAlignment = .right
         label.setContentHuggingPriority(.defaultHigh, for: NSLayoutConstraint.Axis.horizontal)
-        label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 10), for: NSLayoutConstraint.Axis.horizontal)
         return label
     }()
 
     private let locationStreamingIndicator: UIImageView = {
         let view = UIImageView()
         view.translatesAutoresizingMaskIntoConstraints = false
-        view.heightAnchor.constraint(equalToConstant: 16).isActive = true
         view.widthAnchor.constraint(equalToConstant: 16).isActive = true
         view.tintColor = DcColors.checkmarkGreen
         view.image = #imageLiteral(resourceName: "ic_location").withRenderingMode(.alwaysTemplate)
         view.isHidden = true
+        view.contentMode = .scaleAspectFit
         return view
     }()
 
     let subtitleLabel: UILabel = {
         let label = UILabel()
-        label.font = UIFont.systemFont(ofSize: 14)
         label.textColor = DcColors.middleGray
         label.lineBreakMode = .byTruncatingTail
-        label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1), for: NSLayoutConstraint.Axis.horizontal)
+        label.font = .preferredFont(forTextStyle: .subheadline)
+        label.adjustsFontForContentSizeCategory = true
         return label
     }()
 
@@ -136,6 +148,25 @@ class ContactCell: UITableViewCell {
         super.init(style: style, reuseIdentifier: reuseIdentifier)
         setupSubviews()
         selectionStyle = .default
+        configureCompressionPriority()
+    }
+
+    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+        if previousTraitCollection?.preferredContentSizeCategory !=
+            traitCollection.preferredContentSizeCategory {
+            configureCompressionPriority()
+        }
+    }
+
+
+    private func configureCompressionPriority() {
+        if isLargeText {
+            timeLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1), for: .horizontal)
+            subtitleLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 10), for: .horizontal)
+        } else {
+            timeLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 10), for: .horizontal)
+            subtitleLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1), for: .horizontal)
+        }
     }
 
     required init?(coder: NSCoder) {
@@ -152,7 +183,9 @@ class ContactCell: UITableViewCell {
             avatar.constraintWidthTo(badgeSize),
             avatar.constraintHeightTo(badgeSize),
             avatar.constraintAlignLeadingTo(contentView, paddingLeading: badgeSize / 4),
-            avatar.constraintCenterYTo(contentView),
+            avatar.constraintAlignTopTo(contentView, paddingTop: badgeSize / 4, priority: .defaultLow),
+            avatar.constraintAlignBottomTo(contentView, paddingBottom: badgeSize / 4, priority: .defaultLow),
+            avatar.constraintCenterYTo(contentView, priority: .required),
         ])
 
         deliveryStatusIndicator.translatesAutoresizingMaskIntoConstraints = false
@@ -164,12 +197,18 @@ class ContactCell: UITableViewCell {
         verticalStackView.clipsToBounds = true
 
         contentView.addSubview(verticalStackView)
+        verticalStackView.addArrangedSubview(toplineStackView)
+        verticalStackView.addArrangedSubview(bottomlineStackView)
         verticalStackView.leadingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: margin).isActive = true
-        verticalStackView.centerYAnchor.constraint(equalTo: avatar.centerYAnchor).isActive = true
+        verticalStackView.constraintCenterYTo(avatar, priority: .required).isActive = true
         verticalStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -margin).isActive = true
         verticalStackView.axis = .vertical
-        verticalStackView.addArrangedSubview(toplineStackView)
-        verticalStackView.addArrangedSubview(bottomlineStackView)
+
+        toplineStackView.addConstraints([
+            pinnedIndicator.constraintHeightTo(titleLabel.font.pointSize * 1.2),
+            mutedIndicator.constraintHeightTo(titleLabel.font.pointSize * 1.2),
+            locationStreamingIndicator.constraintHeightTo(titleLabel.font.pointSize * 1.2)
+        ])
     }
 
     func setVerified(isVerified: Bool) {
@@ -191,6 +230,16 @@ class ContactCell: UITableViewCell {
     }
 
     func setStatusIndicators(unreadCount: Int, status: Int, visibility: Int32, isLocationStreaming: Bool, isMuted: Bool) {
+        if isLargeText {
+            unreadMessageCounter.setCount(unreadCount)
+            unreadMessageCounter.isHidden = unreadCount == 0
+            unreadMessageCounter.backgroundColor = isMuted ? .gray : .red
+            pinnedIndicator.isHidden = true
+            deliveryStatusIndicator.isHidden = true
+            archivedIndicator.isHidden = true
+            return
+        }
+
         if visibility==DC_CHAT_VISIBILITY_ARCHIVED {
             pinnedIndicator.isHidden = true
             unreadMessageCounter.isHidden = true
@@ -267,7 +316,7 @@ class ContactCell: UITableViewCell {
 
             // text bold if chat contains unread messages - otherwise hightlight search results if needed
             if chatData.unreadMessages > 0 {
-                titleLabel.attributedText = NSAttributedString(string: cellViewModel.title, attributes: [ .font: UIFont.systemFont(ofSize: 16, weight: .bold) ])
+                titleLabel.attributedText = cellViewModel.title.bold(fontSize: titleLabel.font.pointSize)
             } else {
                 titleLabel.attributedText = cellViewModel.title.boldAt(indexes: cellViewModel.titleHighlightIndexes, fontSize: titleLabel.font.pointSize)
             }
@@ -305,6 +354,23 @@ class ContactCell: UITableViewCell {
                                 visibility: 0,
                                 isLocationStreaming: false,
                                 isMuted: false)
+        case .profile:
+            let contact = DcContact(id: Int(DC_CONTACT_ID_SELF))
+            titleLabel.text = cellViewModel.title
+            subtitleLabel.text = cellViewModel.subtitle
+            if let profileImage = contact.profileImage {
+                avatar.setImage(profileImage)
+            } else {
+                avatar.setName(cellViewModel.title)
+                avatar.setColor(contact.color)
+            }
+            setVerified(isVerified: false)
+            setStatusIndicators(unreadCount: 0,
+            status: 0,
+            visibility: 0,
+            isLocationStreaming: false,
+            isMuted: false)
         }
+
     }
 }

+ 4 - 2
deltachat-ios/View/ContactDetailHeader.swift

@@ -16,18 +16,20 @@ class ContactDetailHeader: UIView {
 
     private var titleLabel: UILabel = {
         let label = UILabel()
-        label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
         label.lineBreakMode = .byTruncatingTail
         label.textColor = DcColors.defaultTextColor
         label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1), for: NSLayoutConstraint.Axis.horizontal)
+        label.adjustsFontForContentSizeCategory = true
+        label.font = .preferredFont(forTextStyle: UIFont.TextStyle.headline)
         return label
     }()
 
     private var subtitleLabel: UILabel = {
         let label = UILabel()
-        label.font = UIFont.systemFont(ofSize: 14)
+        label.font = .preferredFont(forTextStyle: .subheadline)
         label.textColor = UIColor(hexString: "848ba7")
         label.lineBreakMode = .byTruncatingTail
+        label.adjustsFontForContentSizeCategory = true
         return label
     }()
 

+ 23 - 4
deltachat-ios/View/MultilineTextFieldCell.swift

@@ -2,7 +2,14 @@ import Foundation
 import UIKit
 
 class MultilineTextFieldCell: UITableViewCell, UITextViewDelegate {
-    static let cellHeight: CGFloat = 125
+
+    private lazy var textFieldHeightConstraint: NSLayoutConstraint = {
+        return textField.constraintHeightTo(fourLinesHeight)
+    }()
+
+    private var fourLinesHeight: CGFloat {
+        return UIFont.preferredFont(forTextStyle: .body).pointSize * 4
+    }
 
     var onTextFieldChange:((_:UITextView) -> Void)?    // set this from outside to get notified about textfield changes
 
@@ -10,6 +17,8 @@ class MultilineTextFieldCell: UITableViewCell, UITextViewDelegate {
         let textField = UITextField()
         textField.translatesAutoresizingMaskIntoConstraints = false
         textField.isEnabled = false
+        textField.adjustsFontForContentSizeCategory = true
+        textField.font = .preferredFont(forTextStyle: .body)
         return textField
     }()
 
@@ -17,16 +26,18 @@ class MultilineTextFieldCell: UITableViewCell, UITextViewDelegate {
         let textField = UITextView()
         textField.delegate = self
         textField.translatesAutoresizingMaskIntoConstraints = false
-        textField.font = UIFont.systemFont(ofSize: 16)
+        textField.adjustsFontForContentSizeCategory = true
+        textField.font = .preferredFont(forTextStyle: .body)
         textField.backgroundColor = .none
         return textField
     }()
 
     lazy var placeholder: UILabel = {
         let placeholderLabel = UILabel()
-        placeholderLabel.font = self.textField.font
         placeholderLabel.textColor = UIColor.lightGray
         placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
+        placeholderLabel.adjustsFontForContentSizeCategory = true
+        placeholderLabel.font = .preferredFont(forTextStyle: .body)
         return placeholderLabel
     }()
 
@@ -56,8 +67,9 @@ class MultilineTextFieldCell: UITableViewCell, UITextViewDelegate {
 
         textField.alignLeadingToAnchor(margins.leadingAnchor, paddingLeading: -5)
         textField.alignTrailingToAnchor(margins.trailingAnchor)
-        contentView.addConstraint(textField.constraintHeightTo(95))
+        contentView.addConstraint(textFieldHeightConstraint)
         textField.alignTopToAnchor(descriptionField.bottomAnchor)
+        textField.alignBottomToAnchor(margins.bottomAnchor)
 
         placeholder.alignLeadingToAnchor(margins.leadingAnchor)
         placeholder.alignTrailingToAnchor(textField.layoutMarginsGuide.trailingAnchor)
@@ -88,4 +100,11 @@ class MultilineTextFieldCell: UITableViewCell, UITextViewDelegate {
         placeholder.isHidden = !(text.isEmpty && range.length == textView.text.count)
         return true
     }
+
+    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+        if previousTraitCollection?.preferredContentSizeCategory !=
+            traitCollection.preferredContentSizeCategory {
+            textFieldHeightConstraint.constant = fourLinesHeight
+        }
+    }
 }

+ 165 - 20
deltachat-ios/View/TextFieldCell.swift

@@ -1,37 +1,87 @@
 import UIKit
+import DcCore
 
 class TextFieldCell: UITableViewCell {
 
+    private let maxFontSizeHorizontalLayout: CGFloat = 30
+
+    private var placeholderVal: String
     var placeholder: String? {
         set {
-            textField.placeholder = newValue
+            placeholderVal = newValue ?? ""
+            configureTextFieldPlaceholder()
+        }
+        get {
+            return placeholderVal
+        }
+    }
+
+    private var fontSize: CGFloat {
+        return UIFont.preferredFont(forTextStyle: .body).pointSize
+    }
+
+    private var preferValue: Bool {
+        set {
+            textField.setContentCompressionResistancePriority( newValue ? .defaultHigh : .defaultLow, for: .horizontal)
+            title.setContentCompressionResistancePriority( newValue ? .defaultLow : .defaultHigh, for: .horizontal)
         }
         get {
-            return textField.placeholder
+            textField.contentCompressionResistancePriority(for: .horizontal) == .defaultHigh
         }
     }
 
+    private var customConstraints: [NSLayoutConstraint] = []
+
     var onTextFieldChange:((_:UITextField) -> Void)?	// set this from outside to get notified about textfield changes
 
+
+    public lazy var title: UILabel = {
+        let label = UILabel()
+        label.font = .preferredFont(forTextStyle: .body)
+        label.adjustsFontForContentSizeCategory = true
+        label.textColor = DcColors.defaultTextColor
+        label.lineBreakMode = .byTruncatingTail
+        label.translatesAutoresizingMaskIntoConstraints = false
+        return label
+    }()
+
+    // use textFieldDelegate instead of textfield.delegate if you want to set a delegate from outside
+    public weak var textFieldDelegate: UITextFieldDelegate?
     lazy var textField: UITextField = {
         let textField = UITextField()
         textField.textAlignment = .right
-        // textField.enablesReturnKeyAutomatically = true
         textField.addTarget(self, action: #selector(textFieldChanged), for: .editingChanged)
+        textField.adjustsFontForContentSizeCategory = true
+        textField.font = .preferredFont(forTextStyle: .body)
+        textField.translatesAutoresizingMaskIntoConstraints = false
+        textField.delegate = self
         return textField
     }()
 
+    public lazy var stackView: UIStackView = {
+        let view = UIStackView()
+        view.translatesAutoresizingMaskIntoConstraints = false
+        view.clipsToBounds = true
+        view.addArrangedSubview(title)
+        view.addArrangedSubview(textField)
+        view.axis = .horizontal
+        view.spacing = 10
+        return view
+    }()
+    
     init(description: String, placeholder: String, delegate: UITextFieldDelegate? = nil) {
-        super.init(style: .value1, reuseIdentifier: nil)
-        textLabel?.text = "\(description):"
+        placeholderVal = placeholder
+        super.init(style: .default, reuseIdentifier: nil)
+        title.text = "\(description):"
 
         // see: https://stackoverflow.com/a/35903650
         // this makes the textField respect the trailing margin of
         // the table view cell
         selectionStyle = .none
         setupViews()
-        textField.delegate = delegate
+        textFieldDelegate = delegate
         textField.placeholder = placeholder
+        preferValue = false
     }
 
     convenience init(descriptionID: String, placeholder: String, delegate: UITextFieldDelegate? = nil) {
@@ -43,18 +93,13 @@ class TextFieldCell: UITableViewCell {
     }
 
     private func setupViews() {
-        contentView.addSubview(textField)
-        textField.translatesAutoresizingMaskIntoConstraints = false
         let margins = contentView.layoutMarginsGuide
-        let trailing = margins.trailingAnchor
-        textField.trailingAnchor.constraint(equalTo: trailing).isActive = true
-        textField.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
-        if let label = self.textLabel {
-            textField.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 20).isActive = true
-            // this will prevent the textfield from growing over the textLabel while typing
-        } else {
-            textField.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
-        }
+        contentView.addSubview(stackView)
+        stackView.alignTopToAnchor(margins.topAnchor)
+        stackView.alignBottomToAnchor(margins.bottomAnchor)
+        stackView.alignLeadingToAnchor(margins.leadingAnchor)
+        stackView.alignTrailingToAnchor(margins.trailingAnchor)
+        updateViews()
     }
 
     override func setSelected(_ selected: Bool, animated _: Bool) {
@@ -64,9 +109,18 @@ class TextFieldCell: UITableViewCell {
     }
 
     @objc func textFieldChanged() {
+        configureTextFieldPlaceholder()
         onTextFieldChange?(self.textField)
     }
 
+    func configureTextFieldPlaceholder() {
+        if let textFieldText = textField.text, !textFieldText.isEmpty {
+            textField.placeholder = nil
+        } else {
+            textField.placeholder = placeholderVal
+        }
+    }
+
     func getText() -> String? {
         if let text = textField.text {
             if text.isEmpty {
@@ -83,13 +137,39 @@ class TextFieldCell: UITableViewCell {
         textField.text = text
     }
 
+    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+        if previousTraitCollection?.preferredContentSizeCategory !=
+            traitCollection.preferredContentSizeCategory {
+            updateViews()
+        }
+    }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+        title.text = nil
+        title.attributedText = nil
+        textField.text = nil
+    }
+
+    private func updateViews() {
+        if fontSize <= maxFontSizeHorizontalLayout {
+            stackView.axis = .horizontal
+            title.numberOfLines = 1
+            textField.textAlignment = .right
+        } else {
+            stackView.axis = .vertical
+            title.numberOfLines = 1
+            textField.textAlignment = .left
+        }
+    }
+
     static func makeEmailCell(delegate: UITextFieldDelegate? = nil) -> TextFieldCell {
         let cell = TextFieldCell(description: String.localized("email_address"), placeholder: "you@example.org")
         cell.textField.keyboardType = .emailAddress
         // switch off quicktype
         cell.textField.autocorrectionType = .no
         cell.textField.autocapitalizationType = .none
-        cell.textField.delegate = delegate
+        cell.textFieldDelegate = delegate
         return cell
     }
 
@@ -108,7 +188,7 @@ class TextFieldCell: UITableViewCell {
         // see: https://stackoverflow.com/a/36365399
         // therefore we use .default to capitalize the first character of the name
         cell.textField.keyboardType = .default
-        cell.textField.delegate = delegate
+        cell.textFieldDelegate = delegate
 
         return cell
     }
@@ -121,7 +201,72 @@ class TextFieldCell: UITableViewCell {
         // see: https://stackoverflow.com/a/36365399
         // therefore we use .default to capitalize the first character of the name
         cell.textField.keyboardType = .default
-        cell.textField.delegate = delegate
+        cell.textFieldDelegate = delegate
         return cell
     }
 }
+
+extension TextFieldCell: UITextFieldDelegate {
+
+    func textFieldDidBeginEditing(_ textField: UITextField) {
+        if let delegate = textFieldDelegate {
+            delegate.textFieldDidBeginEditing?(textField)
+        }
+    }
+
+    func textFieldDidEndEditing(_ textField: UITextField) {
+        if let delegate = textFieldDelegate {
+            delegate.textFieldDidEndEditing?(textField)
+        }
+    }
+
+    func textFieldDidChangeSelection(_ textField: UITextField) {
+        if #available(iOS 13.0, *), let delegate = textFieldDelegate {
+            delegate.textFieldDidChangeSelection?(textField)
+        }
+    }
+
+    func textFieldShouldClear(_ textField: UITextField) -> Bool {
+        if let delegate = textFieldDelegate, let result = delegate.textFieldShouldClear?(textField) {
+            return result
+        }
+        return true
+    }
+
+    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+        if let delegate = textFieldDelegate, let result = delegate.textFieldShouldReturn?(textField) {
+            return result
+        }
+        return true
+    }
+
+    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
+        preferValue = true
+        if let delegate = textFieldDelegate, let result = delegate.textFieldShouldBeginEditing?(textField) {
+            return result
+        }
+        return true
+    }
+
+    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
+        preferValue = false
+        if let delegate = textFieldDelegate, let result = delegate.textFieldShouldEndEditing?(textField) {
+            return result
+        }
+        return true
+    }
+
+    func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
+        if let delegate = textFieldDelegate {
+            delegate.textFieldDidEndEditing?(textField)
+        }
+    }
+
+    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+        if let delegate = textFieldDelegate, let result = delegate.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) {
+            return result
+        }
+        return true
+    }
+
+}

+ 0 - 37
deltachat-ios/View/TextFieldTableViewCell.swift

@@ -1,37 +0,0 @@
-import UIKit
-
-internal class TextFieldTableViewCell: UITableViewCell {
-    static let identifier = "TextFieldTableViewCellIdentifier"
-
-    var mainLabel = UILabel()
-    var textField = UITextField()
-
-    // MARK: - View lifecycle
-
-    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
-        super.init(style: style, reuseIdentifier: reuseIdentifier)
-
-        mainLabel.translatesAutoresizingMaskIntoConstraints = false
-        textField.translatesAutoresizingMaskIntoConstraints = false
-
-        contentView.addSubview(mainLabel)
-        contentView.addSubview(textField)
-
-        NSLayoutConstraint.activate([
-            mainLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
-            mainLabel.widthAnchor.constraint(equalToConstant: 200),
-            mainLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
-
-            textField.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
-
-            textField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
-            textField.widthAnchor.constraint(equalToConstant: 50),
-        ])
-
-        textField.textAlignment = .right
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}

+ 2 - 0
deltachat-ios/ViewModel/ChatListViewModel.swift

@@ -144,6 +144,8 @@ class ChatListViewModel: NSObject, ChatListViewModelProtocol {
             return data.chatId
         case .contact:
             return nil
+        case .profile:
+            return nil
         }
     }
 

+ 27 - 0
deltachat-ios/ViewModel/ContactCellViewModel.swift

@@ -13,6 +13,7 @@ enum CellModel {
     case contact(ContactCellData)
     case chat(ChatCellData)
     case deaddrop(DeaddropCellData)
+    case profile
 }
 
 struct ContactCellData {
@@ -59,6 +60,32 @@ class ContactCellViewModel: AvatarCellViewModel {
     }
 }
 
+class ProfileViewModell: AvatarCellViewModel {
+    var type: CellModel {
+        return CellModel.profile
+    }
+
+    var title: String
+
+    private let contact: DcContact
+
+    var titleHighlightIndexes: [Int] {
+        return []
+    }
+
+    var subtitle: String
+
+    var subtitleHighlightIndexes: [Int] {
+        return []
+    }
+
+    init(context: DcContext) {
+        contact = DcContact(id: Int(DC_CONTACT_ID_SELF))
+        title = context.displayname ?? String.localized("pref_your_name")
+        subtitle = context.addr ?? ""
+    }
+}
+
 class ChatCellViewModel: AvatarCellViewModel {
 
     private let chat: DcChat