Selaa lähdekoodia

prepare new screens and better info messages

dignifiedquire 6 vuotta sitten
vanhempi
commit
51dd684b96

+ 14 - 6
deltachat-ios.xcodeproj/project.pbxproj

@@ -64,6 +64,8 @@
 		78E45E4421D3F14A00D4B15E /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */; };
 		78E45E4C21D404AE00D4B15E /* CustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E4B21D404AE00D4B15E /* CustomCell.swift */; };
 		78ED838321D5379000243125 /* TextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78ED838221D5379000243125 /* TextFieldCell.swift */; };
+		78ED838D21D577D000243125 /* events.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78ED838C21D577D000243125 /* events.swift */; };
+		78ED838F21D5927A00243125 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78ED838E21D5927A00243125 /* CameraViewController.swift */; };
 		7A0052A11FBC50C40048C3BF /* CredentialsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0052A01FBC50C40048C3BF /* CredentialsController.swift */; };
 		7A0052C81FBE6CB40048C3BF /* NewContactController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0052C71FBE6CB40048C3BF /* NewContactController.swift */; };
 		7A451D941FB1B1DB00177250 /* wrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = 7A451D921FB1B1DB00177250 /* wrapper.c */; };
@@ -191,6 +193,8 @@
 		78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
 		78E45E4B21D404AE00D4B15E /* CustomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCell.swift; sourceTree = "<group>"; };
 		78ED838221D5379000243125 /* TextFieldCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldCell.swift; sourceTree = "<group>"; };
+		78ED838C21D577D000243125 /* events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = events.swift; sourceTree = "<group>"; };
+		78ED838E21D5927A00243125 /* CameraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = "<group>"; };
 		7A0052A01FBC50C40048C3BF /* CredentialsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialsController.swift; sourceTree = "<group>"; };
 		7A0052C71FBE6CB40048C3BF /* NewContactController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewContactController.swift; sourceTree = "<group>"; };
 		7A451D921FB1B1DB00177250 /* wrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wrapper.c; sourceTree = "<group>"; };
@@ -275,14 +279,15 @@
 			path = Extensions;
 			sourceTree = "<group>";
 		};
-		78ED838B21D56BAA00243125 /* TopViews */ = {
+		78ED839021D5929800243125 /* TopViews */ = {
 			isa = PBXGroup;
 			children = (
+				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
 				78E45E3F21D3D70700D4B15E /* ContactListController.swift */,
-				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
+				78ED838E21D5927A00243125 /* CameraViewController.swift */,
 				78E45E3921D3CFBC00D4B15E /* SettingsController.swift */,
 			);
-			name = TopViews;
+			path = TopViews;
 			sourceTree = "<group>";
 		};
 		7A451D9B1FB1F4BF00177250 /* Products */ = {
@@ -413,10 +418,11 @@
 				7A451D931FB1B1DB00177250 /* wrapper.h */,
 				7A451DBD1FB4AD0700177250 /* Wrapper.swift */,
 				70B8882D2091B8550074812E /* ContactCell.swift */,
+				78ED838C21D577D000243125 /* events.swift */,
 				7032FF8E2149C1DB00B7EC83 /* BaseController.swift */,
-				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
-				78ED838B21D56BAA00243125 /* TopViews */,
+				78ED839021D5929800243125 /* TopViews */,
 				78E45E3221D3CBC000D4B15E /* AppTabBarController.swift */,
+				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
 				78E45E3D21D3D28C00D4B15E /* NavigationController.swift */,
 				7A0052A01FBC50C40048C3BF /* CredentialsController.swift */,
 				7092474020B3869500AF8799 /* ContactProfileViewController.swift */,
@@ -561,7 +567,7 @@
 								enabled = 1;
 							};
 							com.apple.Push = {
-								enabled = 0;
+								enabled = 1;
 							};
 						};
 					};
@@ -716,6 +722,7 @@
 				7070FB6A20FF345F000DC258 /* dc_saxparser.c in Sources */,
 				7070FB8A20FF4118000DC258 /* dc_log.c in Sources */,
 				7070FB9020FF4118000DC258 /* dc_stock.c in Sources */,
+				78ED838D21D577D000243125 /* events.swift in Sources */,
 				7070FB8F20FF4118000DC258 /* dc_loginparam.c in Sources */,
 				7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */,
 				78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */,
@@ -731,6 +738,7 @@
 				7070FB4020FF3421000DC258 /* dc_chat.c in Sources */,
 				7070FB7320FF345F000DC258 /* dc_aheader.c in Sources */,
 				7070FB6120FF345F000DC258 /* dc_securejoin.c in Sources */,
+				78ED838F21D5927A00243125 /* CameraViewController.swift in Sources */,
 				78E45E4221D3DB4000D4B15E /* UIViewController+Extension.swift in Sources */,
 				7A7923741FB0A2C800BC2DE5 /* symmetric.c in Sources */,
 				7A9FB1441FB061E2001FEA36 /* AppDelegate.swift in Sources */,

+ 0 - 138
deltachat-ios/AppDelegate.swift

@@ -13,144 +13,6 @@ import Reachability
 
 var mailboxPointer:UnsafeMutablePointer<dc_context_t>!
 
-let dc_notificationChanged = Notification.Name(rawValue:"MrEventMsgsChanged")
-let dc_notificationStateChanged = Notification.Name(rawValue:"MrEventStateChanged")
-let dc_notificationIncoming = Notification.Name(rawValue:"MrEventIncomingMsg")
-let dc_notificationBackupProgress = Notification.Name(rawValue:"MrEventBackupProgress")
-
-
-@_silgen_name("callbackSwift")
-
-public func callbackSwift(event: CInt, data1: CUnsignedLong, data2: CUnsignedLong, data1String: UnsafePointer<Int8>, data2String: UnsafePointer<Int8>) -> UnsafePointer<Int8>? {
-
-    switch event {
-    case DC_EVENT_HTTP_GET:
-        let urlString = String(cString: data1String)
-        guard let url = URL(string: urlString) else {
-            return nil
-        }
-        guard let configText = try? String(contentsOf: url) else {
-            return nil
-        }
-        // see the strdup tip here: https://oleb.net/blog/2016/10/swift-array-of-c-strings/#alternative-strdup-and-free
-        let p = UnsafePointer(strdup(configText))
-        return p
-    case DC_EVENT_INFO:
-        let s = String(cString: data2String)
-        print("Info: \(s)")
-    case DC_EVENT_WARNING:
-        let s = String(cString: data2String)
-        print("Warning: \(s)")
-    case DC_EVENT_ERROR:
-        let s = String(cString: data2String)
-        AppDelegate.lastErrorDuringConfig = s
-        print("Error: \(s)")
-    // TODO
-    // check online state, return
-    // - 0 when online
-    // - 1 when offline
-    case DC_EVENT_CONFIGURE_PROGRESS:
-        DispatchQueue.main.async {
-            // progress in promille, 0 - error, 1000 - completed
-            let progressInPromille = Float(data1)
-            AppDelegate.progress = progressInPromille / 1000
-            print("progress: \(AppDelegate.progress)")
-            if data1 == 1000 {
-                UserDefaults.standard.set(true, forKey: Constants.Keys.deltachatUserProvidedCredentialsKey)
-                UserDefaults.standard.synchronize()
-                AppDelegate.appCoordinator.setupInnerViewControllers()
-            }
-            if data1 == 0 {
-                if let lastErrorMessage = AppDelegate.lastErrorDuringConfig {
-                    AppDelegate.appCoordinator.displayCredentialsController(message: lastErrorMessage, isCancellable: AppDelegate.cancellableCredentialsController)
-                } else {
-                    AppDelegate.appCoordinator.displayCredentialsController(message: "Configuration failed. Make sure to enter correct credentials. If using GMail, enable access for 'less secure apps' first.", isCancellable: AppDelegate.cancellableCredentialsController)
-                }
-            }
-            let nc = NotificationCenter.default
-
-            DispatchQueue.main.async {
-                nc.post(name:Notification.Name(rawValue:"ProgressUpdated"),
-                        object: nil,
-                        userInfo: ["message":"Progress updated", "date": Date()])
-            }
-        }
-        return nil
-    case DC_EVENT_ERROR_NETWORK:
-        print("network error")
-        let nc = NotificationCenter.default
-        DispatchQueue.main.async {
-            nc.post(name: dc_notificationStateChanged,
-                    object: nil,
-                    userInfo: ["state": "offline"])
-        }
-    case DC_EVENT_IMAP_CONNECTED, DC_EVENT_SMTP_CONNECTED:
-        print("connected")
-        let nc = NotificationCenter.default
-        DispatchQueue.main.async {
-            nc.post(name: dc_notificationStateChanged,
-                    object: nil,
-                    userInfo: ["state": "online"])
-        }
-    case DC_EVENT_MSGS_CHANGED, DC_EVENT_MSG_READ, DC_EVENT_MSG_DELIVERED:
-        // TODO: reload all views
-        // e.g. when message appears that is not new, i.e. no need
-        // to set badge / notification
-        print("change", event)
-        let nc = NotificationCenter.default
-
-        DispatchQueue.main.async {
-            nc.post(name:dc_notificationChanged,
-                    object: nil,
-                    userInfo: [
-                        "message_id": Int(data2),
-                        "chat_id": Int(data1),
-                        "date": Date()
-                    ])
-        }
-    case DC_EVENT_INCOMING_MSG:
-        // TODO: reload all views + set notification / badge
-        // mrmailbox_get_fresh_msgs
-        let nc = NotificationCenter.default
-
-        // let msg = MRMessage.init(id: Int(data2))
-        // TODO: default summary
-        // if let summary = msg.summary(chars: 32) {
-        // TODO: dispatch user notification
-        DispatchQueue.main.async {
-             nc.post(name:dc_notificationIncoming,
-                     object: nil,
-                     userInfo: [
-                        "message_id": Int(data2),
-                        "chat_id": Int(data1),
-                        "date": Date()
-                    ])
-        }
-    case DC_EVENT_SMTP_MESSAGE_SENT:
-        print("smtp message sent", data2String)
-    case DC_EVENT_MSG_DELIVERED:
-        print("message delivered", data1, data2)
-    case DC_EVENT_IMEX_PROGRESS:
-        let nc = NotificationCenter.default
-        DispatchQueue.main.async {
-            nc.post(
-                name: dc_notificationBackupProgress,
-                object: nil,
-                userInfo: [
-                    "progress": Int(data1),
-                    "error": Int(data1) == 0,
-                    "done": Int(data1) == 1000
-            ])
-        }
-    case DC_EVENT_IMEX_FILE_WRITTEN:
-        print("backup file written", String(cString: data1String))
-    default:
-        print("unknown event", event)
-    }
-
-    return nil
-}
-
 enum ApplicationState {
     case stopped
     case running

+ 27 - 10
deltachat-ios/AppTabBarController.swift

@@ -12,30 +12,47 @@ class AppTabBarController: UITabBarController {
 
     override func viewDidLoad() {
         super.viewDidLoad()
-        
+
         let contactListController = ContactListController()
         let contactNavigationController = NavigationController(rootViewController: contactListController)
         let contactImage = UIImage(named: "contacts")
         contactNavigationController.tabBarItem = UITabBarItem.init(title: "Contacts", image: contactImage, tag: 0)
 
+        let mailboxController = ChatViewController(chatId: Int(DC_CHAT_ID_DEADDROP))
+        mailboxController.disableWriting = true
+        let mailboxNavigationController = NavigationController(rootViewController: mailboxController)
+        let mailboxImage = UIImage(named: "message")
+        mailboxNavigationController.tabBarItem = UITabBarItem.init(title: "Mailbox", image: mailboxImage, tag: 1)
+
+        let cameraController = CameraViewController()
+        let cameraNavigationController = NavigationController(rootViewController: cameraController)
+        let cameraImage = UIImage(named: "camera")
+        cameraNavigationController.tabBarItem = UITabBarItem.init(title: "Camera", image: cameraImage, tag: 2)
+
         let chatListController = ChatListController()
         let chatNavigationController = NavigationController(rootViewController: chatListController)
         let chatImage = UIImage(named: "chat")
-        chatNavigationController.tabBarItem = UITabBarItem.init(title: "Chats", image: chatImage, tag: 1)
-        
+        chatNavigationController.tabBarItem = UITabBarItem.init(title: "Chats", image: chatImage, tag: 3)
+
         let settingsController = SettingsViewController()
         let settingsNavigationController = NavigationController(rootViewController: settingsController)
         let settingsImage = UIImage(named: "settings")
-        settingsNavigationController.tabBarItem = UITabBarItem.init(title: "Settings", image: settingsImage, tag: 2)
-        
-        let tabBarList = [contactNavigationController, chatNavigationController, settingsNavigationController]
-        
+        settingsNavigationController.tabBarItem = UITabBarItem.init(title: "Settings", image: settingsImage, tag: 4)
+
+        let tabBarList = [
+          contactNavigationController,
+          mailboxNavigationController,
+          cameraNavigationController,
+          chatNavigationController,
+          settingsNavigationController
+        ]
+
         viewControllers = tabBarList
-        self.selectedIndex = 1
-        
+        self.selectedIndex = 3
+
         tabBar.tintColor = Constants.primaryColor
     }
-    
+
 
     /*
     // MARK: - Navigation

+ 23 - 0
deltachat-ios/Assets.xcassets/message.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "message.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "message@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "message@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
deltachat-ios/Assets.xcassets/message.imageset/message.png


BIN
deltachat-ios/Assets.xcassets/message.imageset/message@2x.png


BIN
deltachat-ios/Assets.xcassets/message.imageset/message@3x.png


+ 44 - 16
deltachat-ios/ChatViewController.swift

@@ -22,9 +22,7 @@ class ChatViewController: MessagesViewController {
     var msgChangedObserver: Any?
     var incomingMsgObserver: Any?
     
-    override var preferredStatusBarStyle: UIStatusBarStyle {
-        return .lightContent
-    }
+    var disableWriting = false
     
     init(chatId: Int) {
         self.chatId = chatId
@@ -68,12 +66,17 @@ class ChatViewController: MessagesViewController {
     private func idToMessage(messageId: Int) -> Message {
         let message = MRMessage(id: messageId)
         let contact = MRContact(id: message.fromContactId)
-        
+        let messageId = "\(messageId)"
+        let date = Date(timeIntervalSince1970: Double(message.timestamp))
         let sender = Sender(id: "\(contact.id)", displayName: contact.name)
-        if let image = message.image {
-            return Message(image: image, sender: sender, messageId: "\(messageId)", date: Date(timeIntervalSince1970: Double(message.timestamp)))
+        
+        if message.isInfo {
+            let text = NSAttributedString(string: message.text ?? "", attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12), NSAttributedString.Key.foregroundColor: UIColor.darkGray])
+            return Message(attributedText: text, sender: sender, messageId: messageId, date: date)
+        } else if let image = message.image {
+            return Message(image: image, sender: sender, messageId: messageId, date: date)
         } else {
-            return Message(text: message.text ?? "- empty -", sender: sender, messageId: "\(messageId)", date: Date(timeIntervalSince1970: Double(message.timestamp)))
+            return Message(text: message.text ?? "- empty -", sender: sender, messageId: messageId, date: date)
         }
     }
     
@@ -158,17 +161,26 @@ class ChatViewController: MessagesViewController {
         }
     }
     
+    override var inputAccessoryView: UIView? {
+        if disableWriting {
+            return nil
+        }
+        
+        return messageInputBar
+    }
+    
     override func viewDidLoad() {
         super.viewDidLoad()
 
         let chat = MRChat(id: self.chatId)
-        
-        configureMessageCollectionView()
-        configureMessageInputBar()
         updateTitleView(title: chat.name, subtitle: nil)
         
-        messageInputBar.inputTextView.text = textDraft
-        messageInputBar.inputTextView.becomeFirstResponder()
+        configureMessageCollectionView()
+        if !disableWriting {
+            configureMessageInputBar()
+            messageInputBar.inputTextView.text = textDraft
+            messageInputBar.inputTextView.becomeFirstResponder()
+        }
         
         loadFirstMessages()
     }
@@ -176,7 +188,6 @@ class ChatViewController: MessagesViewController {
     func configureMessageCollectionView() {
         messagesCollectionView.messagesDataSource = self
         messagesCollectionView.messageCellDelegate = self
-       
         
         scrollsToBottomOnKeyboardBeginsEditing = true // default false
         maintainPositionOnKeyboardFrameChanged = true // default false
@@ -354,6 +365,15 @@ extension ChatViewController: MessagesDataSource {
         return messageList[indexPath.section].sender == messageList[indexPath.section - 1].sender
     }
     
+    func isInfoMessage(at indexPath: IndexPath) -> Bool {
+        if let id = Int(messageList[indexPath.section].messageId) {
+            return MRMessage(id: id).isInfo
+        }
+        
+        return false
+    }
+        
+    
     func isNextMessageSameSender(at indexPath: IndexPath) -> Bool {
         guard indexPath.section + 1 < messageList.count else { return false }
         return messageList[indexPath.section].sender == messageList[indexPath.section + 1].sender
@@ -433,6 +453,15 @@ extension ChatViewController: MessagesDisplayDelegate {
     }
     
     func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle {
+
+        if isInfoMessage(at: indexPath) {
+            return .custom { view in
+                view.style = .none
+                view.backgroundColor = UIColor(alpha: 0, red: 0, green: 0, blue: 0)
+                view.center.x = self.view.center.x
+
+            }
+        }
         
         var corners: UIRectCorner = []
         
@@ -472,7 +501,7 @@ extension ChatViewController: MessagesDisplayDelegate {
             let contact = message.fromContact
             let avatar = Avatar(image: contact.profileImage, initials: Utils.getInitials(inputName: contact.name))
             avatarView.set(avatar: avatar)
-            avatarView.isHidden = isNextMessageSameSender(at: indexPath)
+            avatarView.isHidden = isNextMessageSameSender(at: indexPath) || message.isInfo
         }
     }
     
@@ -501,7 +530,7 @@ extension ChatViewController: MessagesLayoutDelegate {
     }
     
     func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return (!isNextMessageSameSender(at: indexPath) && isFromCurrentSender(message: message)) ? 16 : 0
+        return (!isNextMessageSameSender(at: indexPath) && isFromCurrentSender(message: message)) && !isInfoMessage(at: indexPath) ? 16 : 0
     }
 
     func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
@@ -637,7 +666,6 @@ extension ChatViewController: MessageLabelDelegate {
     func didSelectURL(_ url: URL) {
         UIApplication.shared.open(url)
     }
-    
 }
 
 // MARK: - LocationMessageDisplayDelegate

+ 1 - 1
deltachat-ios/Constants.swift

@@ -22,7 +22,7 @@ struct Constants {
     }
     
     static let primaryColor = UIColor(red: 81/255, green: 73/255, blue: 255/255, alpha: 1)
-    static let messagePrimaryColor = UIColor(red: 234/255, green: 233/255, blue: 246/255, alpha: 1)
+    static let messagePrimaryColor = Constants.primaryColor.withAlphaComponent(0.5)
     static let messageSecondaryColor = UIColor(red: 245/255, green: 245/255, blue: 245/255, alpha: 1)
     
     static let defaultShadow = UIImage(color: UIColor(hexString: "ff2b82"), size: CGSize(width: 1, height: 1))

+ 38 - 21
deltachat-ios/ContactProfileViewController.swift

@@ -49,42 +49,31 @@ class ContactProfileViewController: UITableViewController {
     }
 
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        return 5
+        if section == 0 {
+            return 3
+        }
+        
+        return 0
     }
 
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let row = indexPath.row
-        if row == 0 {
-            let contactCell = ContactCell()
-            contactCell.nameLabel.text = contact.name
-            contactCell.emailLabel.text = contact.email
-            contactCell.darkMode = true
-            contactCell.selectionStyle = .none
-            if let img = contact.profileImage {
-                contactCell.setImage(img)
-            } else {
-                contactCell.setBackupImage(name: contact.name, color: contact.color)
-            }
-            
-            return contactCell
-        }
+        
         let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
 
         let settingsImage = #imageLiteral(resourceName: "baseline_settings_black_18pt").withRenderingMode(.alwaysTemplate)
         cell.imageView?.image = settingsImage
         cell.imageView?.tintColor = UIColor.clear
 
-        if row == 1 {
+        if row == 0 {
             cell.textLabel?.text = "Settings"
             cell.imageView?.tintColor = UIColor.gray
         }
-        if row == 2 {
+        if row == 1 {
             cell.textLabel?.text = "Edit name"
         }
-        /*if row == 3 {
-            cell.textLabel?.text = "Encryption"
-        }*/
-        if row == 3 {
+
+        if row == 2 {
             cell.textLabel?.text = "New chat"
         }
         return cell
@@ -107,4 +96,32 @@ class ContactProfileViewController: UITableViewController {
             displayNewChat(contactId: contactId)
         }
     }
+    
+    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+        return 80
+    }
+    
+    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+        let bg = UIColor(red: 248/255, green: 248/255, blue: 255/255, alpha: 1.0)
+        if section == 0 {
+            let contactCell = ContactCell()
+            contactCell.backgroundColor = bg
+            contactCell.nameLabel.text = contact.name
+            contactCell.emailLabel.text = contact.email
+            contactCell.darkMode = false
+            contactCell.selectionStyle = .none
+            if let img = contact.profileImage {
+                contactCell.setImage(img)
+            } else {
+                contactCell.setBackupImage(name: contact.name, color: contact.color)
+            }
+            
+            return contactCell
+        }
+        
+        let vw = UIView()
+        vw.backgroundColor = bg
+        
+        return vw
+    }
 }

+ 2 - 2
deltachat-ios/Extensions/UIViewController+Extension.swift

@@ -11,12 +11,12 @@ import UIKit
 
 extension UIViewController {
     
-    func updateTitleView(title: String, subtitle: String?, baseColor: UIColor = .white) {
+    func updateTitleView(title: String, subtitle: String?, baseColor: UIColor = .darkText) {
         
         let titleLabel = UILabel(frame: CGRect(x: 0, y: -2, width: 0, height: 0))
         titleLabel.backgroundColor = UIColor.clear
         titleLabel.textColor = baseColor
-        titleLabel.font = UIFont.systemFont(ofSize: 15)
+        titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
         titleLabel.text = title
         titleLabel.textAlignment = .center
         titleLabel.adjustsFontSizeToFitWidth = true

+ 0 - 4
deltachat-ios/NavigationController.swift

@@ -11,10 +11,6 @@ import UIKit
 final class NavigationController: UINavigationController {
     var stateChangedObserver: Any?
     
-    override var preferredStatusBarStyle: UIStatusBarStyle {
-        return viewControllers.last?.preferredStatusBarStyle ?? .lightContent
-    }
-    
     override func viewDidLoad() {
         super.viewDidLoad()
        

+ 90 - 0
deltachat-ios/TopViews/CameraViewController.swift

@@ -0,0 +1,90 @@
+//
+//  CameraViewController.swift
+//  deltachat-ios
+//
+//  Created by Friedel Ziegelmayer on 28.12.18.
+//  Copyright © 2018 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class CameraViewController: UITableViewController {
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        // Uncomment the following line to preserve selection between presentations
+        // self.clearsSelectionOnViewWillAppear = false
+
+        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
+        // self.navigationItem.rightBarButtonItem = self.editButtonItem
+    }
+
+    // MARK: - Table view data source
+
+    override func numberOfSections(in tableView: UITableView) -> Int {
+        // #warning Incomplete implementation, return the number of sections
+        return 0
+    }
+
+    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        // #warning Incomplete implementation, return the number of rows
+        return 0
+    }
+
+    /*
+    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
+
+        // Configure the cell...
+
+        return cell
+    }
+    */
+
+    /*
+    // Override to support conditional editing of the table view.
+    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
+        // Return false if you do not want the specified item to be editable.
+        return true
+    }
+    */
+
+    /*
+    // Override to support editing the table view.
+    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
+        if editingStyle == .delete {
+            // Delete the row from the data source
+            tableView.deleteRows(at: [indexPath], with: .fade)
+        } else if editingStyle == .insert {
+            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
+        }    
+    }
+    */
+
+    /*
+    // Override to support rearranging the table view.
+    override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
+
+    }
+    */
+
+    /*
+    // Override to support conditional rearranging of the table view.
+    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
+        // Return false if you do not want the item to be re-orderable.
+        return true
+    }
+    */
+
+    /*
+    // MARK: - Navigation
+
+    // In a storyboard-based application, you will often want to do a little preparation before navigation
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        // Get the new view controller using segue.destination.
+        // Pass the selected object to the new view controller.
+    }
+    */
+
+}

+ 1 - 1
deltachat-ios/ChatListController.swift → deltachat-ios/TopViews/ChatListController.swift

@@ -23,7 +23,7 @@ class ChatListController: UIViewController {
     var newButton: UIBarButtonItem!
     
     func getChatList() {
-        guard let chatlistPointer = dc_get_chatlist(mailboxPointer, 0, nil, 0) else {
+        guard let chatlistPointer = dc_get_chatlist(mailboxPointer, DC_GCL_NO_SPECIALS, nil, 0) else {
             fatalError("chatlistPointer was nil")
         }
         // ownership of chatlistPointer transferred here to ChatList object

+ 0 - 0
deltachat-ios/ContactListController.swift → deltachat-ios/TopViews/ContactListController.swift


+ 1 - 6
deltachat-ios/SettingsController.swift → deltachat-ios/TopViews/SettingsController.swift

@@ -17,12 +17,7 @@ final internal class SettingsViewController: QuickTableViewController {
     var backupProgressObserver: Any?
     var backupHud: JGProgressHUD?
 
-    // MARK: - Properties
-
-    override var preferredStatusBarStyle: UIStatusBarStyle {
-        return .lightContent
-    }
-
+  
     // MARK: - View lifecycle
 
     override func viewDidLoad() {

+ 4 - 0
deltachat-ios/Wrapper.swift

@@ -159,6 +159,10 @@ class MRMessage {
     var timestamp: Int64 {
         return Int64(messagePointer.pointee.timestamp)
     }
+    
+    var isInfo: Bool {
+        return dc_msg_is_info(messagePointer) == 1
+    }
 
     init(id: Int) {
         messagePointer = dc_get_msg(mailboxPointer, UInt32(id))

+ 2 - 0
deltachat-ios/deltachat-ios.entitlements

@@ -2,6 +2,8 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+	<key>aps-environment</key>
+	<string>development</string>
 	<key>com.apple.security.application-groups</key>
 	<array>
 		<string>group.delta.chat.ios</string>

+ 143 - 0
deltachat-ios/events.swift

@@ -0,0 +1,143 @@
+//
+//  events.swift
+//  deltachat-ios
+//
+//  Created by Friedel Ziegelmayer on 27.12.18.
+//  Copyright © 2018 Jonas Reinsch. All rights reserved.
+//
+
+import UserNotifications
+
+let dc_notificationChanged = Notification.Name(rawValue:"MrEventMsgsChanged")
+let dc_notificationStateChanged = Notification.Name(rawValue:"MrEventStateChanged")
+let dc_notificationIncoming = Notification.Name(rawValue:"MrEventIncomingMsg")
+let dc_notificationBackupProgress = Notification.Name(rawValue:"MrEventBackupProgress")
+
+@_silgen_name("callbackSwift")
+
+public func callbackSwift(event: CInt, data1: CUnsignedLong, data2: CUnsignedLong, data1String: UnsafePointer<Int8>, data2String: UnsafePointer<Int8>) -> UnsafePointer<Int8>? {
+    
+    switch event {
+    case DC_EVENT_HTTP_GET:
+        let urlString = String(cString: data1String)
+        guard let url = URL(string: urlString) else {
+            return nil
+        }
+        guard let configText = try? String(contentsOf: url) else {
+            return nil
+        }
+        // see the strdup tip here: https://oleb.net/blog/2016/10/swift-array-of-c-strings/#alternative-strdup-and-free
+        let p = UnsafePointer(strdup(configText))
+        return p
+    case DC_EVENT_INFO:
+        let s = String(cString: data2String)
+        print("Info: \(s)")
+    case DC_EVENT_WARNING:
+        let s = String(cString: data2String)
+        print("Warning: \(s)")
+    case DC_EVENT_ERROR:
+        let s = String(cString: data2String)
+        AppDelegate.lastErrorDuringConfig = s
+        print("Error: \(s)")
+        // TODO
+        // check online state, return
+        // - 0 when online
+    // - 1 when offline
+    case DC_EVENT_CONFIGURE_PROGRESS:
+        DispatchQueue.main.async {
+            // progress in promille, 0 - error, 1000 - completed
+            let progressInPromille = Float(data1)
+            AppDelegate.progress = progressInPromille / 1000
+            print("progress: \(AppDelegate.progress)")
+            if data1 == 1000 {
+                UserDefaults.standard.set(true, forKey: Constants.Keys.deltachatUserProvidedCredentialsKey)
+                UserDefaults.standard.synchronize()
+                AppDelegate.appCoordinator.setupInnerViewControllers()
+            }
+            if data1 == 0 {
+                if let lastErrorMessage = AppDelegate.lastErrorDuringConfig {
+                    AppDelegate.appCoordinator.displayCredentialsController(message: lastErrorMessage, isCancellable: AppDelegate.cancellableCredentialsController)
+                } else {
+                    AppDelegate.appCoordinator.displayCredentialsController(message: "Configuration failed. Make sure to enter correct credentials. If using GMail, enable access for 'less secure apps' first.", isCancellable: AppDelegate.cancellableCredentialsController)
+                }
+            }
+            let nc = NotificationCenter.default
+            
+            DispatchQueue.main.async {
+                nc.post(name:Notification.Name(rawValue:"ProgressUpdated"),
+                        object: nil,
+                        userInfo: ["message":"Progress updated", "date": Date()])
+            }
+        }
+        return nil
+    case DC_EVENT_ERROR_NETWORK:
+        print("network error")
+        let nc = NotificationCenter.default
+        DispatchQueue.main.async {
+            nc.post(name: dc_notificationStateChanged,
+                    object: nil,
+                    userInfo: ["state": "offline"])
+        }
+    case DC_EVENT_IMAP_CONNECTED, DC_EVENT_SMTP_CONNECTED:
+        print("connected")
+        let nc = NotificationCenter.default
+        DispatchQueue.main.async {
+            nc.post(name: dc_notificationStateChanged,
+                    object: nil,
+                    userInfo: ["state": "online"])
+        }
+    case DC_EVENT_MSGS_CHANGED, DC_EVENT_MSG_READ, DC_EVENT_MSG_DELIVERED:
+        // TODO: reload all views
+        // e.g. when message appears that is not new, i.e. no need
+        // to set badge / notification
+        print("change", event)
+        let nc = NotificationCenter.default
+        
+        DispatchQueue.main.async {
+            nc.post(name:dc_notificationChanged,
+                    object: nil,
+                    userInfo: [
+                        "message_id": Int(data2),
+                        "chat_id": Int(data1),
+                        "date": Date()
+                ])
+        }
+    case DC_EVENT_INCOMING_MSG:
+        let nc = NotificationCenter.default
+
+        DispatchQueue.main.async {
+            nc.post(name:dc_notificationIncoming,
+                    object: nil,
+                    userInfo: [
+                        "message_id": Int(data2),
+                        "chat_id": Int(data1),
+                        "date": Date()
+                ])
+        }
+    case DC_EVENT_SMTP_MESSAGE_SENT:
+        print("message sent", data2String)
+    case DC_EVENT_MSG_DELIVERED:
+        print("message delivered", data1, data2)
+    case DC_EVENT_IMEX_PROGRESS:
+        let nc = NotificationCenter.default
+        DispatchQueue.main.async {
+            nc.post(
+                name: dc_notificationBackupProgress,
+                object: nil,
+                userInfo: [
+                    "progress": Int(data1),
+                    "error": Int(data1) == 0,
+                    "done": Int(data1) == 1000
+                ])
+        }
+    case DC_EVENT_IMEX_FILE_WRITTEN:
+        print("backup file written", String(cString: data1String))
+    case DC_EVENT_GET_STRING:
+        // nothing to do for now
+        break
+    default:
+        print("unknown event", event)
+    }
+    
+    return nil
+}