Quellcode durchsuchen

Merge pull request #66 from deltachat/ArchitecturRefactoring

Architecture refactoring
nayooti vor 6 Jahren
Ursprung
Commit
9e05641536
48 geänderte Dateien mit 1012 neuen und 674 gelöschten Zeilen
  1. 118 62
      deltachat-ios.xcodeproj/project.pbxproj
  2. 0 36
      deltachat-ios/AppCoordinator.swift
  3. 17 13
      deltachat-ios/AppDelegate.swift
  4. 0 54
      deltachat-ios/AppTabBarController.swift
  5. 0 80
      deltachat-ios/BaseController.swift
  6. 4 4
      deltachat-ios/Controller/AccountSetupController.swift
  7. 40 0
      deltachat-ios/Controller/ChatDetailViewController.swift
  8. 10 53
      deltachat-ios/Controller/ChatListController.swift
  9. 107 93
      deltachat-ios/Controller/ChatViewController.swift
  10. 2 0
      deltachat-ios/Controller/ContactListController.swift
  11. 0 0
      deltachat-ios/Controller/ContactProfileViewController.swift
  12. 109 0
      deltachat-ios/Controller/GroupNameController.swift
  13. 0 0
      deltachat-ios/Controller/MessageInfoViewController.swift
  14. 0 0
      deltachat-ios/Controller/NavigationController.swift
  15. 16 48
      deltachat-ios/Controller/NewChatViewController.swift
  16. 0 0
      deltachat-ios/Controller/NewContactController.swift
  17. 7 5
      deltachat-ios/Controller/NewGroupViewController.swift
  18. 2 0
      deltachat-ios/Controller/ProfileViewController.swift
  19. 0 4
      deltachat-ios/Controller/QrCodeReaderController.swift
  20. 3 3
      deltachat-ios/Controller/SettingsController.swift
  21. 282 0
      deltachat-ios/Coordinator/AppCoordinator.swift
  22. 0 0
      deltachat-ios/DC/Wrapper.swift
  23. 3 1
      deltachat-ios/DC/events.swift
  24. 0 0
      deltachat-ios/DC/wrapper.c
  25. 0 0
      deltachat-ios/DC/wrapper.h
  26. 0 91
      deltachat-ios/GroupNameController.swift
  27. 0 0
      deltachat-ios/Handler/DeviceContactsHandler.swift
  28. 0 0
      deltachat-ios/Handler/HudHandler.swift
  29. 0 0
      deltachat-ios/Helper/Colors.swift
  30. 1 5
      deltachat-ios/Helper/Constants.swift
  31. 0 0
      deltachat-ios/Helper/Extensions.swift
  32. 29 0
      deltachat-ios/Helper/Protocols.swift
  33. 0 0
      deltachat-ios/Helper/UIImage+Extension.swift
  34. 0 0
      deltachat-ios/Helper/UIViewController+Extension.swift
  35. 0 0
      deltachat-ios/Helper/Utils.swift
  36. 22 0
      deltachat-ios/Model/Location.swift
  37. 32 0
      deltachat-ios/Model/Media.swift
  38. 0 32
      deltachat-ios/Model/Message.swift
  39. 69 66
      deltachat-ios/NewGroupMemberChoiceController.swift
  40. 0 0
      deltachat-ios/View/ActionCell.swift
  41. 36 24
      deltachat-ios/View/ContactCell.swift
  42. 0 0
      deltachat-ios/View/CustomCell.swift
  43. 64 0
      deltachat-ios/View/GroupNameCell.swift
  44. 39 0
      deltachat-ios/View/InitialsLabel.swift
  45. 0 0
      deltachat-ios/View/ProgressHud.swift
  46. 0 0
      deltachat-ios/View/QrCodeView.swift
  47. 0 0
      deltachat-ios/View/TextFieldCell.swift
  48. 0 0
      deltachat-ios/View/TextFieldTableViewCell.swift

+ 118 - 62
deltachat-ios.xcodeproj/project.pbxproj

@@ -8,7 +8,6 @@
 
 /* Begin PBXBuildFile section */
 		6795F63A82E94FF7CD2CEC0F /* Pods_deltachat_iosTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F7009234DB9408201A6CDCB /* Pods_deltachat_iosTests.framework */; };
-		7032FF8F2149C1DB00B7EC83 /* BaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7032FF8E2149C1DB00B7EC83 /* BaseController.swift */; };
 		7070FB3D20FDD9FE000DC258 /* NewGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB3C20FDD9FE000DC258 /* NewGroupViewController.swift */; };
 		7070FB4020FF3421000DC258 /* dc_chat.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB3E20FF3420000DC258 /* dc_chat.c */; };
 		7070FB4120FF3421000DC258 /* dc_smtp.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB3F20FF3421000DC258 /* dc_smtp.c */; };
@@ -66,7 +65,6 @@
 		78E45E2B21D176FB00D4B15E /* dc_jobthread.c in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2A21D176FB00D4B15E /* dc_jobthread.c */; };
 		78E45E2F21D1774200D4B15E /* dc_context.h in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2D21D1774200D4B15E /* dc_context.h */; };
 		78E45E3021D1774200D4B15E /* dc_move.c in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E2E21D1774200D4B15E /* dc_move.c */; };
-		78E45E3321D3CBC000D4B15E /* AppTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3221D3CBC000D4B15E /* AppTabBarController.swift */; };
 		78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3921D3CFBC00D4B15E /* SettingsController.swift */; };
 		78E45E3C21D3D03700D4B15E /* TextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3B21D3D03700D4B15E /* TextFieldTableViewCell.swift */; };
 		78E45E3E21D3D28C00D4B15E /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3D21D3D28C00D4B15E /* NavigationController.swift */; };
@@ -90,10 +88,16 @@
 		7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE0A5481FC42F65005ECB4B /* NewChatViewController.swift */; };
 		8B6D425BC604F7C43B65D436 /* Pods_deltachat_ios.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6241BE1534A653E79AD5D01D /* Pods_deltachat_ios.framework */; };
 		AE0D26FD1FB1FE88002FAFCE /* ChatListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */; };
+		AE25F09022807AD800CDEA66 /* GroupNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE25F08F22807AD800CDEA66 /* GroupNameCell.swift */; };
 		AE38B31822672DFC00EC37A1 /* ActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE38B31722672DFC00EC37A1 /* ActionCell.swift */; };
 		AE38B31A2267328200EC37A1 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE38B3192267328200EC37A1 /* Colors.swift */; };
 		AE8519EA2272FDCA00ED86F0 /* DeviceContactsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE8519E92272FDCA00ED86F0 /* DeviceContactsHandler.swift */; };
 		AE851A04227AECDE00ED86F0 /* deltachat_iosTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851A03227AECDE00ED86F0 /* deltachat_iosTests.swift */; };
+		AE851AC5227C755A00ED86F0 /* Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC4227C755A00ED86F0 /* Protocols.swift */; };
+		AE851AC7227C776400ED86F0 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC6227C776400ED86F0 /* Location.swift */; };
+		AE851AC9227C77CF00ED86F0 /* Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC8227C77CF00ED86F0 /* Media.swift */; };
+		AE851ACE227CA54400ED86F0 /* InitialsLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */; };
+		AE851AD0227DF50900ED86F0 /* ChatDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACF227DF50900ED86F0 /* ChatDetailViewController.swift */; };
 		AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */; };
 		AEACE2DF1FB3246400DCDD78 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2DE1FB3246400DCDD78 /* Message.swift */; };
 		AEACE2E31FB32B5C00DCDD78 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2E21FB32B5C00DCDD78 /* Constants.swift */; };
@@ -138,7 +142,6 @@
 		21EE28844E7A690D73BF5285 /* Pods-deltachat-iosTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-deltachat-iosTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-deltachat-iosTests/Pods-deltachat-iosTests.debug.xcconfig"; sourceTree = "<group>"; };
 		2F7009234DB9408201A6CDCB /* Pods_deltachat_iosTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_deltachat_iosTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		6241BE1534A653E79AD5D01D /* Pods_deltachat_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_deltachat_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-		7032FF8E2149C1DB00B7EC83 /* BaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseController.swift; sourceTree = "<group>"; };
 		7070FB3C20FDD9FE000DC258 /* NewGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGroupViewController.swift; sourceTree = "<group>"; };
 		7070FB3E20FF3420000DC258 /* dc_chat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_chat.c; sourceTree = "<group>"; };
 		7070FB3F20FF3421000DC258 /* dc_smtp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_smtp.c; sourceTree = "<group>"; };
@@ -211,7 +214,6 @@
 		78E45E2C21D1774200D4B15E /* dc_context.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dc_context.c; path = "deltachat-ios/libraries/deltachat-core/src/dc_context.c"; sourceTree = "<group>"; };
 		78E45E2D21D1774200D4B15E /* dc_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dc_context.h; path = "deltachat-ios/libraries/deltachat-core/src/dc_context.h"; sourceTree = "<group>"; };
 		78E45E2E21D1774200D4B15E /* dc_move.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dc_move.c; path = "deltachat-ios/libraries/deltachat-core/src/dc_move.c"; sourceTree = "<group>"; };
-		78E45E3221D3CBC000D4B15E /* AppTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTabBarController.swift; 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>"; };
 		78E45E3D21D3D28C00D4B15E /* NavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = "<group>"; };
@@ -277,12 +279,18 @@
 		8DE110C607A0E4485C43B5FA /* Pods-deltachat-ios.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-deltachat-ios.debug.xcconfig"; path = "Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.debug.xcconfig"; sourceTree = "<group>"; };
 		A8615D4600859851E53CAA9C /* Pods-deltachat-ios.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-deltachat-ios.release.xcconfig"; path = "Pods/Target Support Files/Pods-deltachat-ios/Pods-deltachat-ios.release.xcconfig"; sourceTree = "<group>"; };
 		AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListController.swift; sourceTree = "<group>"; };
+		AE25F08F22807AD800CDEA66 /* GroupNameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupNameCell.swift; sourceTree = "<group>"; };
 		AE38B31722672DFC00EC37A1 /* ActionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCell.swift; sourceTree = "<group>"; };
 		AE38B3192267328200EC37A1 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
 		AE8519E92272FDCA00ED86F0 /* DeviceContactsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceContactsHandler.swift; sourceTree = "<group>"; };
 		AE851A01227AECDE00ED86F0 /* deltachat-iosTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "deltachat-iosTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
 		AE851A03227AECDE00ED86F0 /* deltachat_iosTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = deltachat_iosTests.swift; sourceTree = "<group>"; };
 		AE851A05227AECDF00ED86F0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		AE851AC4227C755A00ED86F0 /* Protocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Protocols.swift; sourceTree = "<group>"; };
+		AE851AC6227C776400ED86F0 /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = "<group>"; };
+		AE851AC8227C77CF00ED86F0 /* Media.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Media.swift; sourceTree = "<group>"; };
+		AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialsLabel.swift; sourceTree = "<group>"; };
+		AE851ACF227DF50900ED86F0 /* ChatDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatDetailViewController.swift; sourceTree = "<group>"; };
 		AEA9CC2F22522DA20061D113 /* librpgp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = librpgp.h; sourceTree = "<group>"; };
 		AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = "<group>"; };
 		AEACE2DE1FB3246400DCDD78 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
@@ -319,27 +327,6 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		78ED838A21D5570700243125 /* Extensions */ = {
-			isa = PBXGroup;
-			children = (
-				78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */,
-				78E45E4121D3DB4000D4B15E /* UIViewController+Extension.swift */,
-				AEE56D7F225504DB007DC082 /* Extensions.swift */,
-			);
-			path = Extensions;
-			sourceTree = "<group>";
-		};
-		78ED839021D5929800243125 /* TopViews */ = {
-			isa = PBXGroup;
-			children = (
-				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
-				78E45E3F21D3D70700D4B15E /* ContactListController.swift */,
-				78ED838E21D5927A00243125 /* ProfileViewController.swift */,
-				78E45E3921D3CFBC00D4B15E /* SettingsController.swift */,
-			);
-			path = TopViews;
-			sourceTree = "<group>";
-		};
 		7A451D9B1FB1F4BF00177250 /* Products */ = {
 			isa = PBXGroup;
 			children = (
@@ -462,46 +449,21 @@
 		7A9FB1421FB061E2001FEA36 /* deltachat-ios */ = {
 			isa = PBXGroup;
 			children = (
-				78C7036A21D46752005D4525 /* deltachat-ios.entitlements */,
-				AEACE2DE1FB3246400DCDD78 /* Message.swift */,
-				7A9FB15B1FB07364001FEA36 /* libraries */,
 				7A9FB1431FB061E2001FEA36 /* AppDelegate.swift */,
-				7A451DAF1FB1F84900177250 /* AppCoordinator.swift */,
-				78E45E4B21D404AE00D4B15E /* CustomCell.swift */,
+				AE851ACA227C79CF00ED86F0 /* DC */,
+				AE851AC3227C695900ED86F0 /* View */,
+				AE851AC2227C695000ED86F0 /* Helper */,
+				AE851AC1227C694300ED86F0 /* Coordinator */,
+				AE851AC0227C693B00ED86F0 /* Controller */,
+				AE851ABA227C692600ED86F0 /* Model */,
+				AE851ACB227C7A5000ED86F0 /* Handler */,
+				7A9FB15B1FB07364001FEA36 /* libraries */,
+				7A9FB1561FB06540001FEA36 /* deltachat-ios-Bridging-Header.h */,
+				78C7036A21D46752005D4525 /* deltachat-ios.entitlements */,
 				7A9FB14A1FB061E2001FEA36 /* Assets.xcassets */,
 				7A9FB14C1FB061E2001FEA36 /* LaunchScreen.storyboard */,
 				7A9FB14F1FB061E2001FEA36 /* Info.plist */,
-				7A9FB1561FB06540001FEA36 /* deltachat-ios-Bridging-Header.h */,
-				7A451D921FB1B1DB00177250 /* wrapper.c */,
-				7A451D931FB1B1DB00177250 /* wrapper.h */,
-				7A451DBD1FB4AD0700177250 /* Wrapper.swift */,
-				789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */,
-				785BE16721E247F1003BE98C /* MessageInfoViewController.swift */,
-				70B8882D2091B8550074812E /* ContactCell.swift */,
-				78ED838C21D577D000243125 /* events.swift */,
-				789E879C21D6DF86003ED1C5 /* ProgressHud.swift */,
-				7032FF8E2149C1DB00B7EC83 /* BaseController.swift */,
-				78ED839021D5929800243125 /* TopViews */,
-				78E45E3221D3CBC000D4B15E /* AppTabBarController.swift */,
-				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
-				78E45E3D21D3D28C00D4B15E /* NavigationController.swift */,
-				7092474020B3869500AF8799 /* ContactProfileViewController.swift */,
-				7A0052C71FBE6CB40048C3BF /* NewContactController.swift */,
-				78ED838A21D5570700243125 /* Extensions */,
-				7AE0A5481FC42F65005ECB4B /* NewChatViewController.swift */,
-				7070FB3C20FDD9FE000DC258 /* NewGroupViewController.swift */,
 				70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */,
-				7070FB9A2101ECBB000DC258 /* GroupNameController.swift */,
-				AEACE2E21FB32B5C00DCDD78 /* Constants.swift */,
-				78ED839321D5AF8A00243125 /* QrCodeView.swift */,
-				AEACE2E41FB32E1900DCDD78 /* Utils.swift */,
-				78E45E3B21D3D03700D4B15E /* TextFieldTableViewCell.swift */,
-				78ED838221D5379000243125 /* TextFieldCell.swift */,
-				AEE56D752253431E007DC082 /* AccountSetupController.swift */,
-				AEE56D7C2253ADB4007DC082 /* HudHandler.swift */,
-				AE38B31722672DFC00EC37A1 /* ActionCell.swift */,
-				AE38B3192267328200EC37A1 /* Colors.swift */,
-				AE8519E92272FDCA00ED86F0 /* DeviceContactsHandler.swift */,
 			);
 			path = "deltachat-ios";
 			sourceTree = "<group>";
@@ -608,6 +570,96 @@
 			path = "deltachat-iosTests";
 			sourceTree = "<group>";
 		};
+		AE851ABA227C692600ED86F0 /* Model */ = {
+			isa = PBXGroup;
+			children = (
+				AEACE2DE1FB3246400DCDD78 /* Message.swift */,
+				AE851AC6227C776400ED86F0 /* Location.swift */,
+				AE851AC8227C77CF00ED86F0 /* Media.swift */,
+			);
+			path = Model;
+			sourceTree = "<group>";
+		};
+		AE851AC0227C693B00ED86F0 /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+				78E45E3D21D3D28C00D4B15E /* NavigationController.swift */,
+				785BE16721E247F1003BE98C /* MessageInfoViewController.swift */,
+				7A0052C71FBE6CB40048C3BF /* NewContactController.swift */,
+				AEE56D752253431E007DC082 /* AccountSetupController.swift */,
+				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
+				789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */,
+				7092474020B3869500AF8799 /* ContactProfileViewController.swift */,
+				7AE0A5481FC42F65005ECB4B /* NewChatViewController.swift */,
+				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
+				78E45E3F21D3D70700D4B15E /* ContactListController.swift */,
+				78ED838E21D5927A00243125 /* ProfileViewController.swift */,
+				78E45E3921D3CFBC00D4B15E /* SettingsController.swift */,
+				7070FB3C20FDD9FE000DC258 /* NewGroupViewController.swift */,
+				7070FB9A2101ECBB000DC258 /* GroupNameController.swift */,
+				AE851ACF227DF50900ED86F0 /* ChatDetailViewController.swift */,
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		AE851AC1227C694300ED86F0 /* Coordinator */ = {
+			isa = PBXGroup;
+			children = (
+				7A451DAF1FB1F84900177250 /* AppCoordinator.swift */,
+			);
+			path = Coordinator;
+			sourceTree = "<group>";
+		};
+		AE851AC2227C695000ED86F0 /* Helper */ = {
+			isa = PBXGroup;
+			children = (
+				AEACE2E21FB32B5C00DCDD78 /* Constants.swift */,
+				78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */,
+				78E45E4121D3DB4000D4B15E /* UIViewController+Extension.swift */,
+				AEACE2E41FB32E1900DCDD78 /* Utils.swift */,
+				AEE56D7F225504DB007DC082 /* Extensions.swift */,
+				AE38B3192267328200EC37A1 /* Colors.swift */,
+				AE851AC4227C755A00ED86F0 /* Protocols.swift */,
+			);
+			path = Helper;
+			sourceTree = "<group>";
+		};
+		AE851AC3227C695900ED86F0 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				78E45E4B21D404AE00D4B15E /* CustomCell.swift */,
+				70B8882D2091B8550074812E /* ContactCell.swift */,
+				78ED839321D5AF8A00243125 /* QrCodeView.swift */,
+				78ED838221D5379000243125 /* TextFieldCell.swift */,
+				78E45E3B21D3D03700D4B15E /* TextFieldTableViewCell.swift */,
+				789E879C21D6DF86003ED1C5 /* ProgressHud.swift */,
+				AE38B31722672DFC00EC37A1 /* ActionCell.swift */,
+				AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */,
+				AE25F08F22807AD800CDEA66 /* GroupNameCell.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
+		AE851ACA227C79CF00ED86F0 /* DC */ = {
+			isa = PBXGroup;
+			children = (
+				7A451D931FB1B1DB00177250 /* wrapper.h */,
+				7A451DBD1FB4AD0700177250 /* Wrapper.swift */,
+				78ED838C21D577D000243125 /* events.swift */,
+				7A451D921FB1B1DB00177250 /* wrapper.c */,
+			);
+			path = DC;
+			sourceTree = "<group>";
+		};
+		AE851ACB227C7A5000ED86F0 /* Handler */ = {
+			isa = PBXGroup;
+			children = (
+				AEE56D7C2253ADB4007DC082 /* HudHandler.swift */,
+				AE8519E92272FDCA00ED86F0 /* DeviceContactsHandler.swift */,
+			);
+			path = Handler;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -883,8 +935,8 @@
 				7070FB7520FF345F000DC258 /* dc_strbuilder.c in Sources */,
 				7070FB6220FF345F000DC258 /* dc_configure.c in Sources */,
 				7070FB4120FF3421000DC258 /* dc_smtp.c in Sources */,
-				78E45E3321D3CBC000D4B15E /* AppTabBarController.swift in Sources */,
 				7070FB6E20FF345F000DC258 /* dc_openssl.c in Sources */,
+				AE851AC9227C77CF00ED86F0 /* Media.swift in Sources */,
 				7070FB6720FF345F000DC258 /* dc_simplify.c in Sources */,
 				7070FB7120FF345F000DC258 /* dc_receive_imf.c in Sources */,
 				7070FB8B20FF4118000DC258 /* dc_keyhistory.c in Sources */,
@@ -905,7 +957,9 @@
 				7070FB9020FF4118000DC258 /* dc_stock.c in Sources */,
 				78ED838D21D577D000243125 /* events.swift in Sources */,
 				7070FB8F20FF4118000DC258 /* dc_loginparam.c in Sources */,
+				AE851AC7227C776400ED86F0 /* Location.swift in Sources */,
 				7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */,
+				AE25F09022807AD800CDEA66 /* GroupNameCell.swift in Sources */,
 				78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */,
 				AE8519EA2272FDCA00ED86F0 /* DeviceContactsHandler.swift in Sources */,
 				78ED838321D5379000243125 /* TextFieldCell.swift in Sources */,
@@ -926,7 +980,6 @@
 				78E45E4221D3DB4000D4B15E /* UIViewController+Extension.swift in Sources */,
 				7A9FB1441FB061E2001FEA36 /* AppDelegate.swift in Sources */,
 				AEE56D7D2253ADB4007DC082 /* HudHandler.swift in Sources */,
-				7032FF8F2149C1DB00B7EC83 /* BaseController.swift in Sources */,
 				7070FB9320FF4118000DC258 /* dc_msg.c in Sources */,
 				7070FB6820FF345F000DC258 /* dc_array.c in Sources */,
 				7070FB9120FF4118000DC258 /* dc_strencode.c in Sources */,
@@ -942,16 +995,19 @@
 				7070FB5F20FF345F000DC258 /* dc_tools.c in Sources */,
 				7070FB8E20FF4118000DC258 /* dc_apeerstate.c in Sources */,
 				7A451DBE1FB4AD0700177250 /* Wrapper.swift in Sources */,
+				AE851ACE227CA54400ED86F0 /* InitialsLabel.swift in Sources */,
 				7070FB6420FF345F000DC258 /* dc_dehtml.c in Sources */,
 				70B8882E2091B8550074812E /* ContactCell.swift in Sources */,
 				7070FB8D20FF4118000DC258 /* dc_sqlite3.c in Sources */,
 				7A451D941FB1B1DB00177250 /* wrapper.c in Sources */,
 				7092474120B3869500AF8799 /* ContactProfileViewController.swift in Sources */,
 				7070FB5E20FF345F000DC258 /* dc_token.c in Sources */,
+				AE851AD0227DF50900ED86F0 /* ChatDetailViewController.swift in Sources */,
 				7070FB6C20FF345F000DC258 /* dc_keyring.c in Sources */,
 				7A451DB01FB1F84900177250 /* AppCoordinator.swift in Sources */,
 				AE38B31822672DFC00EC37A1 /* ActionCell.swift in Sources */,
 				785BE16821E247F1003BE98C /* MessageInfoViewController.swift in Sources */,
+				AE851AC5227C755A00ED86F0 /* Protocols.swift in Sources */,
 				AEACE2E31FB32B5C00DCDD78 /* Constants.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 0 - 36
deltachat-ios/AppCoordinator.swift

@@ -1,36 +0,0 @@
-//
-//  AppCoordinator.swift
-//  deltachat-ios
-//
-//  Created by Jonas Reinsch on 07.11.17.
-//  Copyright © 2017 Jonas Reinsch. All rights reserved.
-//
-
-import UIKit
-
-protocol Coordinator {
-  func setupViewControllers(window: UIWindow)
-}
-
-class AppCoordinator: Coordinator {
-  let baseController = BaseController()
-
-  private var appTabBarController: AppTabBarController = AppTabBarController()
-
-  func setupViewControllers(window: UIWindow) {
-    window.rootViewController = appTabBarController
-    window.makeKeyAndVisible()
-  }
-
-  func presentAccountSetup(animated: Bool) {
-    let accountSetupController = AccountSetupController()
-    let accountSetupNavigationController = UINavigationController(rootViewController: accountSetupController)
-    appTabBarController.present(accountSetupNavigationController, animated: animated, completion: nil)
-  }
-
-  func setupInnerViewControllers() {
-    let chatListController = ChatListController()
-    let chatNavigationController = UINavigationController(rootViewController: chatListController)
-    baseController.present(chatNavigationController, animated: false, completion: nil)
-  }
-}

+ 17 - 13
deltachat-ios/AppDelegate.swift

@@ -25,10 +25,11 @@ enum ApplicationState {
 
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
-  static let appCoordinator = AppCoordinator()
-  static var progress: Float = 0
+  var appCoordinator: AppCoordinator!
+  // static let appCoordinatorDeprecated = AppCoordinatorDeprecated()
+  static var progress: Float = 0 // TODO: delete
   static var lastErrorDuringConfig: String?
-  var backgroundTask: UIBackgroundTaskIdentifier = .invalid
+  private var backgroundTask: UIBackgroundTaskIdentifier = .invalid
 
   var reachability = Reachability()!
   var window: UIWindow?
@@ -74,12 +75,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     //       - second param remains nil (user data for more than one mailbox)
     open()
     let isConfigured = dc_is_configured(mailboxPointer) != 0
-    AppDelegate.appCoordinator.setupViewControllers(window: window)
+    // AppDelegate.appCoordinatorDeprecated.setupViewControllers(window: window)
+    appCoordinator = AppCoordinator(window: window)
+    appCoordinator.start()
     UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
     start()
     registerForPushNotifications()
     if !isConfigured {
-      AppDelegate.appCoordinator.presentAccountSetup(animated: false)
+      appCoordinator.presentLoginController()
+      // AppDelegate.appCoordinatorDeprecated.presentAccountSetup(animated: false)
     }
     return true
   }
@@ -107,7 +111,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     maybeStop()
   }
 
-  func maybeStop() {
+  private func maybeStop() {
     DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
       let app = UIApplication.shared
       logger.info("state: \(app.applicationState) time remaining \(app.backgroundTimeRemaining)")
@@ -232,7 +236,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     DBDebugToolkit.add(info)
   }
 
-  @objc func reachabilityChanged(note: Notification) {
+  @objc private func reachabilityChanged(note: Notification) {
     let reachability = note.object as! Reachability
 
     switch reachability.connection {
@@ -259,7 +263,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
   // MARK: - BackgroundTask
 
-  func registerBackgroundTask() {
+  private func registerBackgroundTask() {
     logger.info("background task registered")
     backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
       self?.endBackgroundTask()
@@ -267,7 +271,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     assert(backgroundTask != .invalid)
   }
 
-  func endBackgroundTask() {
+  private func endBackgroundTask() {
     logger.info("background task ended")
     UIApplication.shared.endBackgroundTask(backgroundTask)
     backgroundTask = .invalid
@@ -275,7 +279,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
   // MARK: - PushNotifications
 
-  func registerForPushNotifications() {
+  private func registerForPushNotifications() {
     UNUserNotificationCenter.current().delegate = self
 
     UNUserNotificationCenter.current()
@@ -287,18 +291,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
       }
   }
 
-  func getNotificationSettings() {
+  private func getNotificationSettings() {
     UNUserNotificationCenter.current().getNotificationSettings { settings in
       logger.info("Notification settings: \(settings)")
     }
   }
 
-  func userNotificationCenter(_: UNUserNotificationCenter, willPresent _: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+  private func userNotificationCenter(_: UNUserNotificationCenter, willPresent _: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
     logger.info("forground notification")
     completionHandler([.alert, .sound])
   }
 
-  func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
+  private func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
     if response.notification.request.identifier == Constants.notificationIdentifier {
       logger.info("handling notifications")
       let userInfo = response.notification.request.content.userInfo

+ 0 - 54
deltachat-ios/AppTabBarController.swift

@@ -1,54 +0,0 @@
-//
-//  AppTabBarController.swift
-//  deltachat-ios
-//
-//  Created by Friedel Ziegelmayer on 26.12.18.
-//  Copyright © 2018 Jonas Reinsch. All rights reserved.
-//
-
-import UIKit
-
-class AppTabBarController: UITabBarController {
-  override func viewDidLoad() {
-    super.viewDidLoad()
-
-    let contactListController = ContactListController()
-    let contactNavigationController = NavigationController(rootViewController: contactListController)
-    let contactImage = UIImage(named: "contacts")
-    contactNavigationController.tabBarItem = UITabBarItem(title: "Contacts", image: contactImage, tag: 0)
-
-    let mailboxController = ChatViewController(chatId: Int(DC_CHAT_ID_DEADDROP), title: "Mailbox")
-    mailboxController.disableWriting = true
-    let mailboxNavigationController = NavigationController(rootViewController: mailboxController)
-    let mailboxImage = UIImage(named: "message")
-    mailboxNavigationController.tabBarItem = UITabBarItem(title: "Mailbox", image: mailboxImage, tag: 1)
-
-    let profileController = ProfileViewController()
-    let profileNavigationController = NavigationController(rootViewController: profileController)
-    let profileImage = UIImage(named: "report_card")
-    profileNavigationController.tabBarItem = UITabBarItem(title: "My Profile", image: profileImage, tag: 2)
-
-    let chatListController = ChatListController()
-    let chatNavigationController = NavigationController(rootViewController: chatListController)
-    let chatImage = UIImage(named: "chat")
-    chatNavigationController.tabBarItem = UITabBarItem(title: "Chats", image: chatImage, tag: 3)
-
-    let settingsController = SettingsViewController()
-    let settingsNavigationController = NavigationController(rootViewController: settingsController)
-    let settingsImage = UIImage(named: "settings")
-    settingsNavigationController.tabBarItem = UITabBarItem(title: "Settings", image: settingsImage, tag: 4)
-
-    let tabBarList = [
-      contactNavigationController,
-      mailboxNavigationController,
-      profileNavigationController,
-      chatNavigationController,
-      settingsNavigationController,
-    ]
-
-    viewControllers = tabBarList
-    selectedIndex = 3
-
-    tabBar.tintColor = DCColors.primary
-  }
-}

+ 0 - 80
deltachat-ios/BaseController.swift

@@ -1,80 +0,0 @@
-//
-//  BaseController.swift
-//  deltachat-ios
-//
-//  Created by Alla Reinsch on 12.09.18.
-//  Copyright © 2018 Jonas Reinsch. All rights reserved.
-//
-
-import UIKit
-
-class ProgressViewContainer: UIView {
-  let progressView = UIProgressView(progressViewStyle: .default)
-
-  init() {
-    super.init(frame: .zero)
-    backgroundColor = .lightGray
-
-    let label = UILabel()
-    label.translatesAutoresizingMaskIntoConstraints = false
-    addSubview(label)
-    label.textAlignment = .center
-    label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
-    label.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -50).isActive = true
-    label.textColor = .darkGray
-    label.text = "Configuring…"
-
-    let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
-    activityIndicator.translatesAutoresizingMaskIntoConstraints = false
-    addSubview(activityIndicator)
-
-    activityIndicator.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
-    activityIndicator.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 50).isActive = true
-    activityIndicator.startAnimating()
-
-    progressView.progressTintColor = .darkGray
-    progressView.trackTintColor = .white
-    progressView.progress = 0.0
-
-    addSubview(progressView)
-
-    progressView.translatesAutoresizingMaskIntoConstraints = false
-    progressView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
-    progressView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
-    progressView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
-  }
-
-  required init?(coder _: NSCoder) {
-    fatalError("init(coder:) has not been implemented")
-  }
-}
-
-class BaseController: UIViewController {
-  let progressViewContainer = ProgressViewContainer()
-  var progressChangedObserver: Any?
-
-  override func loadView() {
-    view = progressViewContainer
-  }
-
-  override func viewDidLoad() {}
-
-  override func viewWillAppear(_ animated: Bool) {
-    super.viewWillAppear(animated)
-    let nc = NotificationCenter.default
-    progressChangedObserver = nc.addObserver(forName: Notification.Name(rawValue: "ProgressUpdated"),
-                                             object: nil, queue: nil) {
-      _ in
-      logger.info("----------- ProgressUpdated notification received --------")
-      self.progressViewContainer.progressView.progress = AppDelegate.progress
-    }
-  }
-
-  override func viewDidDisappear(_ animated: Bool) {
-    super.viewDidDisappear(animated)
-    let nc = NotificationCenter.default
-    if let progressChangedObserver = self.progressChangedObserver {
-      nc.removeObserver(progressChangedObserver)
-    }
-  }
-}

+ 4 - 4
deltachat-ios/AccountSetupController.swift → deltachat-ios/Controller/AccountSetupController.swift

@@ -574,10 +574,10 @@ class AdvancedSectionHeader: UIView {
 
  // TODO: to add Eye-icon -> uncomment -> add to inputField.rightView
  /*
-     lazy var makeVisibleIcon: UIImageView = {
-     let view = UIImageView(image: )
-     return view
-     }()
+      lazy var makeVisibleIcon: UIImageView = {
+      let view = UIImageView(image: )
+      return view
+      }()
   */
  init() {
  super.init(style: .default, reuseIdentifier: nil)

+ 40 - 0
deltachat-ios/Controller/ChatDetailViewController.swift

@@ -0,0 +1,40 @@
+//
+//  ChatDetailViewController.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 04.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+// TODO: checkout if it makes sense to  run group chats and single chats within this chatDetailViewController or maybe seperate these
+
+class ChatDetailViewController: UIViewController {
+  weak var coordinator: ChatDetailCoordinator?
+
+  init(chatId _: Int) {
+    super.init(nibName: nil, bundle: nil)
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    view.backgroundColor = UIColor.white
+
+    // Do any additional setup after loading the view.
+  }
+
+  /*
+   // 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.
+   }
+   */
+}

+ 10 - 53
deltachat-ios/TopViews/ChatListController.swift → deltachat-ios/Controller/ChatListController.swift

@@ -9,20 +9,17 @@
 import UIKit
 
 class ChatListController: UIViewController {
+  weak var coordinator: ChatListCoordinator?
   var chatList: MRChatList?
 
   lazy var chatTable: UITableView = {
     let chatTable = UITableView()
-    chatTable.dataSource = chatTableDataSource
-    chatTableDelegate.chatPresenter = self
-    chatTable.delegate = chatTableDelegate
+    chatTable.dataSource = self
+    chatTable.delegate = self
     chatTable.rowHeight = 80
     return chatTable
   }()
 
-  let chatTableDataSource = ChatTableDataSource()
-  let chatTableDelegate = ChatTableDelegate()
-
   var msgChangedObserver: Any?
   var incomingMsgObserver: Any?
   var viewChatObserver: Any?
@@ -33,6 +30,7 @@ class ChatListController: UIViewController {
     super.viewWillAppear(animated)
 
     if #available(iOS 11.0, *) {
+      // TODO: check if this is really nessesary - dc navigationController has large titles
       navigationController?.navigationBar.prefersLargeTitles = true
     }
 
@@ -64,7 +62,7 @@ class ChatListController: UIViewController {
     viewChatObserver = nc.addObserver(forName: dcNotificationViewChat, object: nil, queue: nil) {
       notification in
       if let chatId = notification.userInfo?["chat_id"] as? Int {
-        self.displayChatForId(chatId: chatId)
+        self.coordinator?.showChat(chatId: chatId)
       }
     }
   }
@@ -106,10 +104,7 @@ class ChatListController: UIViewController {
   }
 
   @objc func didPressNewChat() {
-    let ncv = NewChatViewController()
-    ncv.chatDisplayer = self
-    let nav = UINavigationController(rootViewController: ncv)
-    present(nav, animated: true, completion: nil)
+    coordinator?.showNewChatController()
   }
 
   func getChatList() {
@@ -118,43 +113,11 @@ class ChatListController: UIViewController {
     }
     // ownership of chatlistPointer transferred here to ChatList object
     chatList = MRChatList(chatListPointer: chatlistPointer)
-
-    chatTableDataSource.chatList = chatList
     chatTable.reloadData()
   }
 }
 
-extension ChatListController: ChatPresenter {
-  func displayChat(index: Int) {
-    guard let chatList = self.chatList else {
-      fatalError("chatList was nil in ChatPresenter extension")
-    }
-
-    let chatId = chatList.getChatId(index: index)
-    let chatVC = ChatViewController(chatId: chatId)
-
-    chatVC.hidesBottomBarWhenPushed = true
-    navigationController?.pushViewController(chatVC, animated: true)
-  }
-}
-
-extension ChatListController: ChatDisplayer {
-  func displayNewChat(contactId: Int) {
-    let chatId = dc_create_chat_by_contact_id(mailboxPointer, UInt32(contactId))
-    displayChatForId(chatId: Int(chatId))
-  }
-
-  func displayChatForId(chatId: Int) {
-    let chatVC = ChatViewController(chatId: chatId)
-
-    chatVC.hidesBottomBarWhenPushed = true
-    navigationController?.pushViewController(chatVC, animated: true)
-  }
-}
-
-class ChatTableDataSource: NSObject, UITableViewDataSource {
-  weak var chatList: MRChatList?
-
+extension ChatListController: UITableViewDataSource, UITableViewDelegate {
   func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
     guard let chatList = self.chatList else {
       fatalError("chatList was nil in data source")
@@ -200,17 +163,11 @@ class ChatTableDataSource: NSObject, UITableViewDataSource {
     cell.emailLabel.text = result
     return cell
   }
-}
-
-protocol ChatPresenter: class {
-  func displayChat(index: Int)
-}
-
-class ChatTableDelegate: NSObject, UITableViewDelegate {
-  weak var chatPresenter: ChatPresenter?
 
   func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
     let row = indexPath.row
-    chatPresenter?.displayChat(index: row)
+    if let chatId = chatList?.getChatId(index: row) {
+      coordinator?.showChat(chatId: chatId)
+    }
   }
 }

+ 107 - 93
deltachat-ios/ChatViewController.swift → deltachat-ios/Controller/ChatViewController.swift

@@ -14,6 +14,8 @@ import QuickLook
 import UIKit
 
 class ChatViewController: MessagesViewController {
+  weak var coordinator: ChatViewCoordinator?
+
   let outgoingAvatarOverlap: CGFloat = 17.5
   let loadCount = 30
 
@@ -37,74 +39,40 @@ class ChatViewController: MessagesViewController {
     }
   }
 
-  @objc
-  func loadMoreMessages() {
-    DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) {
-      DispatchQueue.main.async {
-        self.messageList = self.getMessageIds(self.loadCount, from: self.messageList.count) + self.messageList
-        self.messagesCollectionView.reloadDataAndKeepOffset()
-        self.refreshControl.endRefreshing()
-      }
-    }
-  }
-
-  @objc
-  func refreshMessages() {
-    DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) {
-      DispatchQueue.main.async {
-        self.messageList = self.getMessageIds(self.messageList.count)
-        self.messagesCollectionView.reloadDataAndKeepOffset()
-        self.refreshControl.endRefreshing()
-        if self.isLastSectionVisible() {
-          self.messagesCollectionView.scrollToBottom(animated: true)
-        }
-      }
-    }
-  }
-
-  func loadFirstMessages() {
-    DispatchQueue.global(qos: .userInitiated).async {
-      DispatchQueue.main.async {
-        self.messageList = self.getMessageIds(self.loadCount)
-        self.messagesCollectionView.reloadData()
-        self.refreshControl.endRefreshing()
-        self.messagesCollectionView.scrollToBottom(animated: false)
-      }
-    }
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
   }
 
-  var textDraft: String? {
-    // FIXME: need to free pointer
-    if let draft = dc_get_draft(mailboxPointer, UInt32(chatId)) {
-      if let text = dc_msg_get_text(draft) {
-        let s = String(validatingUTF8: text)!
-        return s
-      }
-      return nil
+  override func viewDidLoad() {
+    messagesCollectionView.register(CustomCell.self)
+    super.viewDidLoad()
+    view.backgroundColor = DCColors.chatBackgroundColor
+    let navBarTap = UITapGestureRecognizer(target: self, action: #selector(chatProfilePressed))
+    navigationController?.navigationBar.addGestureRecognizer(navBarTap)
+    if !MRConfig.configured {
+      // TODO: display message about nothing being configured
+      return
     }
-    return nil
-  }
 
-  func getMessageIds(_ count: Int, from: Int? = nil) -> [MRMessage] {
-    let cMessageIds = dc_get_chat_msgs(mailboxPointer, UInt32(chatId), 0, 0)
+    let chat = MRChat(id: chatId)
+    updateTitleView(title: chat.name, subtitle: chat.subtitle)
 
-    let ids: [Int]
-    if let from = from {
-      ids = Utils.copyAndFreeArrayWithOffset(inputArray: cMessageIds, len: count, skipEnd: from)
+    if let image = chat.profileImage {
+      navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .done, target: self, action: #selector(chatProfilePressed))
     } else {
-      ids = Utils.copyAndFreeArrayWithLen(inputArray: cMessageIds, len: count)
+      let initialsLabel = InitialsLabel(name: chat.name, color: chat.color, size: 28)
+      navigationItem.rightBarButtonItem = UIBarButtonItem(customView: initialsLabel)
     }
 
-    let markIds: [UInt32] = ids.map { UInt32($0) }
-    dc_markseen_msgs(mailboxPointer, UnsafePointer(markIds), Int32(ids.count))
+    configureMessageCollectionView()
 
-    return ids.map {
-      MRMessage(id: $0)
+    if !disableWriting {
+      configureMessageInputBar()
+      messageInputBar.inputTextView.text = textDraft
+      messageInputBar.inputTextView.becomeFirstResponder()
     }
-  }
 
-  required init?(coder _: NSCoder) {
-    fatalError("init(coder:) has not been implemented")
+    loadFirstMessages()
   }
 
   override func viewWillAppear(_ animated: Bool) {
@@ -150,17 +118,6 @@ class ChatViewController: MessagesViewController {
     }
   }
 
-  func setTextDraft() {
-    if let text = self.messageInputBar.inputTextView.text {
-      let draft = dc_msg_new(mailboxPointer, DC_MSG_TEXT)
-      dc_msg_set_text(draft, text.cString(using: .utf8))
-      dc_set_draft(mailboxPointer, UInt32(chatId), draft)
-
-      // cleanup
-      dc_msg_unref(draft)
-    }
-  }
-
   override func viewWillDisappear(_ animated: Bool) {
     super.viewWillDisappear(animated)
 
@@ -188,39 +145,92 @@ class ChatViewController: MessagesViewController {
     }
   }
 
-  override var inputAccessoryView: UIView? {
-    if disableWriting {
-      return nil
+  @objc
+  private func loadMoreMessages() {
+    DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) {
+      DispatchQueue.main.async {
+        self.messageList = self.getMessageIds(self.loadCount, from: self.messageList.count) + self.messageList
+        self.messagesCollectionView.reloadDataAndKeepOffset()
+        self.refreshControl.endRefreshing()
+      }
     }
+  }
 
-    return messageInputBar
+  @objc
+  private func refreshMessages() {
+    DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) {
+      DispatchQueue.main.async {
+        self.messageList = self.getMessageIds(self.messageList.count)
+        self.messagesCollectionView.reloadDataAndKeepOffset()
+        self.refreshControl.endRefreshing()
+        if self.isLastSectionVisible() {
+          self.messagesCollectionView.scrollToBottom(animated: true)
+        }
+      }
+    }
   }
 
-  override func viewDidLoad() {
-    messagesCollectionView.register(CustomCell.self)
-    super.viewDidLoad()
-    view.backgroundColor = DCColors.chatBackgroundColor
+  private func loadFirstMessages() {
+    DispatchQueue.global(qos: .userInitiated).async {
+      DispatchQueue.main.async {
+        self.messageList = self.getMessageIds(self.loadCount)
+        self.messagesCollectionView.reloadData()
+        self.refreshControl.endRefreshing()
+        self.messagesCollectionView.scrollToBottom(animated: false)
+      }
+    }
+  }
 
-    if !MRConfig.configured {
-      // TODO: display message about nothing being configured
-      return
+  private var textDraft: String? {
+    // FIXME: need to free pointer
+    if let draft = dc_get_draft(mailboxPointer, UInt32(chatId)) {
+      if let text = dc_msg_get_text(draft) {
+        let s = String(validatingUTF8: text)!
+        return s
+      }
+      return nil
     }
+    return nil
+  }
 
-    let chat = MRChat(id: chatId)
-    updateTitleView(title: chat.name, subtitle: chat.subtitle)
+  private func getMessageIds(_ count: Int, from: Int? = nil) -> [MRMessage] {
+    let cMessageIds = dc_get_chat_msgs(mailboxPointer, UInt32(chatId), 0, 0)
 
-    configureMessageCollectionView()
+    let ids: [Int]
+    if let from = from {
+      ids = Utils.copyAndFreeArrayWithOffset(inputArray: cMessageIds, len: count, skipEnd: from)
+    } else {
+      ids = Utils.copyAndFreeArrayWithLen(inputArray: cMessageIds, len: count)
+    }
 
-    if !disableWriting {
-      configureMessageInputBar()
-      messageInputBar.inputTextView.text = textDraft
-      messageInputBar.inputTextView.becomeFirstResponder()
+    let markIds: [UInt32] = ids.map { UInt32($0) }
+    dc_markseen_msgs(mailboxPointer, UnsafePointer(markIds), Int32(ids.count))
+
+    return ids.map {
+      MRMessage(id: $0)
     }
+  }
 
-    loadFirstMessages()
+  private func setTextDraft() {
+    if let text = self.messageInputBar.inputTextView.text {
+      let draft = dc_msg_new(mailboxPointer, DC_MSG_TEXT)
+      dc_msg_set_text(draft, text.cString(using: .utf8))
+      dc_set_draft(mailboxPointer, UInt32(chatId), draft)
+
+      // cleanup
+      dc_msg_unref(draft)
+    }
   }
 
-  func configureMessageMenu() {
+  override var inputAccessoryView: UIView? {
+    if disableWriting {
+      return nil
+    }
+
+    return messageInputBar
+  }
+
+  private func configureMessageMenu() {
     var menuItems: [UIMenuItem]
 
     if disableWriting {
@@ -239,7 +249,7 @@ class ChatViewController: MessagesViewController {
     UIMenuController.shared.menuItems = menuItems
   }
 
-  func configureMessageCollectionView() {
+  private func configureMessageCollectionView() {
     messagesCollectionView.messagesDataSource = self
     messagesCollectionView.messageCellDelegate = self
 
@@ -272,7 +282,7 @@ class ChatViewController: MessagesViewController {
     messagesCollectionView.messagesDisplayDelegate = self
   }
 
-  func configureMessageInputBar() {
+  private func configureMessageInputBar() {
     messageInputBar.delegate = self
     messageInputBar.inputTextView.tintColor = DCColors.primary
     messageInputBar.sendButton.tintColor = DCColors.primary
@@ -298,17 +308,17 @@ class ChatViewController: MessagesViewController {
 
   private func configureInputBarItems() {
     messageInputBar.setLeftStackViewWidthConstant(to: 44, animated: false)
-    messageInputBar.setRightStackViewWidthConstant(to: 36, animated: false)
+    messageInputBar.setRightStackViewWidthConstant(to: 30, animated: false)
 
     let sendButtonImage = UIImage(named: "paper_plane")?.withRenderingMode(.alwaysTemplate)
     messageInputBar.sendButton.image = sendButtonImage
     messageInputBar.sendButton.tintColor = UIColor(white: 1, alpha: 1)
     messageInputBar.sendButton.backgroundColor = UIColor(white: 0.9, alpha: 1)
     messageInputBar.sendButton.contentEdgeInsets = UIEdgeInsets(top: 6, left: 0, bottom: 6, right: 0)
-    messageInputBar.sendButton.setSize(CGSize(width: 34, height: 34), animated: false)
+    messageInputBar.sendButton.setSize(CGSize(width: 30, height: 30), animated: false)
 
     messageInputBar.sendButton.title = nil
-    messageInputBar.sendButton.layer.cornerRadius = 18
+    messageInputBar.sendButton.layer.cornerRadius = 15
 
     messageInputBar.textViewPadding.right = -40
 
@@ -342,6 +352,10 @@ class ChatViewController: MessagesViewController {
       }
   }
 
+  @objc private func chatProfilePressed() {
+    coordinator?.showChatDetail(chatId: chatId)
+  }
+
   // MARK: - UICollectionViewDataSource
 
   public override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

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

@@ -9,6 +9,8 @@
 import UIKit
 
 class ContactListController: UITableViewController {
+  weak var coordinator: ContactListCoordinator?
+
   let contactCellReuseIdentifier = "xyz"
   var contactIds: [Int] = Utils.getContactIds()
   var contactIdsForGroup: Set<Int> = []

+ 0 - 0
deltachat-ios/ContactProfileViewController.swift → deltachat-ios/Controller/ContactProfileViewController.swift


+ 109 - 0
deltachat-ios/Controller/GroupNameController.swift

@@ -0,0 +1,109 @@
+//
+//  GroupNameController.swift
+//  deltachat-ios
+//
+//  Created by Alla Reinsch on 20.07.18.
+//  Copyright © 2018 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class GroupNameController: UITableViewController {
+  weak var coordinator: GroupNameCoordinator?
+
+  var groupName: String = ""
+
+  var doneButton: UIBarButtonItem!
+  let contactIdsForGroup: Set<Int> // TODO: check if array is sufficient
+  let groupContactIds: [Int]
+
+  init(contactIdsForGroup: Set<Int>) {
+    self.contactIdsForGroup = contactIdsForGroup
+    groupContactIds = Array(contactIdsForGroup)
+    super.init(style: .grouped)
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    title = "New Group"
+    doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonPressed))
+    navigationItem.rightBarButtonItem = doneButton
+    tableView.bounces = false
+    doneButton.isEnabled = false
+    tableView.register(GroupLabelCell.self, forCellReuseIdentifier: "groupLabelCell")
+    tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")
+    // setupSubviews()
+  }
+
+  @objc func doneButtonPressed() {
+    let groupChatId = dc_create_group_chat(mailboxPointer, 0, groupName)
+    for contactId in contactIdsForGroup {
+      let success = dc_add_contact_to_chat(mailboxPointer, groupChatId, UInt32(contactId))
+      if success == 1 {
+        logger.info("successfully added \(contactId) to group \(groupName)")
+      } else {
+        // FIXME:
+        fatalError("failed to add \(contactId) to group \(groupName)")
+      }
+    }
+
+    coordinator?.showGroupChat(chatId: Int(groupChatId))
+  }
+
+  override func didReceiveMemoryWarning() {
+    super.didReceiveMemoryWarning()
+    // Dispose of any resources that can be recreated.
+  }
+
+  override func numberOfSections(in _: UITableView) -> Int {
+    return 2
+  }
+
+  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+    let section = indexPath.section
+    let row = indexPath.row
+
+    if section == 0 {
+      let cell = tableView.dequeueReusableCell(withIdentifier: "groupLabelCell", for: indexPath) as! GroupLabelCell
+      cell.groupNameUpdated = updateGroupName
+
+      return cell
+
+    } else {
+      let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactCell
+
+      let contact = MRContact(id: groupContactIds[row])
+      cell.nameLabel.text = contact.name
+      cell.emailLabel.text = contact.email
+      cell.initialsLabel.text = Utils.getInitials(inputName: contact.name)
+      cell.setColor(contact.color)
+
+      return cell
+    }
+  }
+
+  override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
+    if section == 0 {
+      return 1
+    } else {
+      return contactIdsForGroup.count
+    }
+  }
+
+  override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
+    if section == 1 {
+      return "Group Members"
+    } else {
+      return nil
+    }
+  }
+
+  private func updateGroupName(name: String) {
+    groupName = name
+    doneButton.isEnabled = name.containsCharacters()
+  }
+}

+ 0 - 0
deltachat-ios/MessageInfoViewController.swift → deltachat-ios/Controller/MessageInfoViewController.swift


+ 0 - 0
deltachat-ios/NavigationController.swift → deltachat-ios/Controller/NavigationController.swift


+ 16 - 48
deltachat-ios/NewChatViewController.swift → deltachat-ios/Controller/NewChatViewController.swift

@@ -10,12 +10,9 @@ import ALCameraViewController
 import Contacts
 import UIKit
 
-protocol ChatDisplayer: class {
-  func displayNewChat(contactId: Int)
-  func displayChatForId(chatId: Int)
-}
-
 class NewChatViewController: UITableViewController {
+  weak var coordinator: NewChatCoordinator?
+
   private lazy var searchController: UISearchController = {
     let searchController = UISearchController(searchResultsController: nil)
     searchController.searchResultsUpdater = self
@@ -43,7 +40,7 @@ class NewChatViewController: UITableViewController {
     return searchController.isActive && !searchBarIsEmpty()
   }
 
-  weak var chatDisplayer: ChatDisplayer?
+  // weak var chatDisplayer: ChatDisplayer?
 
   var syncObserver: Any?
   var hud: ProgressHud?
@@ -72,10 +69,6 @@ class NewChatViewController: UITableViewController {
     super.viewDidLoad()
 
     title = "New Chat"
-    navigationController?.navigationBar.prefersLargeTitles = true
-
-    let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(NewChatViewController.cancelButtonPressed))
-    navigationItem.rightBarButtonItem = cancelButton
 
     deviceContactHandler.importDeviceContacts()
     navigationItem.searchController = searchController
@@ -118,6 +111,11 @@ class NewChatViewController: UITableViewController {
     }
   }
 
+  override func viewWillDisappear(_: Bool) {
+    hidesBottomBarWhenPushed = false
+    title = "Chats" /* hack: when navigating to chatView (removing this viewController), there was a delayed backButton update (showing 'New Chat' for a moment) */
+  }
+
   override func viewDidDisappear(_ animated: Bool) {
     super.viewDidDisappear(animated)
 
@@ -245,15 +243,11 @@ class NewChatViewController: UITableViewController {
 
     if section == 0 {
       if row == 0 {
-        let newGroupController = NewGroupViewController()
-        navigationController?.pushViewController(newGroupController, animated: true)
+        coordinator?.showNewGroupController()
       }
       if row == 1 {
         if UIImagePickerController.isSourceTypeAvailable(.camera) {
-          let controller = QrCodeReaderController()
-          controller.delegate = self
-          present(controller, animated: true, completion: nil)
-
+          coordinator?.showQRCodeController()
         } else {
           let alert = UIAlertController(title: "Camera is not available", message: nil, preferredStyle: .alert)
           alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: { _ in
@@ -263,8 +257,7 @@ class NewChatViewController: UITableViewController {
         }
       }
       if row == 2 {
-        let newContactController = NewContactController()
-        navigationController?.pushViewController(newContactController, animated: true)
+        coordinator?.showNewContactController()
       }
     } else if section == 1 {
       if deviceContactAccessGranted {
@@ -272,15 +265,11 @@ class NewChatViewController: UITableViewController {
           // edge case: when searchController is active but searchBar is empty -> filteredContacts is empty, so we fallback to contactIds
           let contactId = isFiltering() ? filteredContacts[row].contact.id : contactIds[row]
           searchController.dismiss(animated: false, completion: {
-            self.dismiss(animated: false, completion: {
-              self.chatDisplayer?.displayNewChat(contactId: contactId)
-            })
+            self.coordinator?.showNewChat(contactId: contactId)
           })
         } else {
           let contactId = contactIds[row]
-          dismiss(animated: false) {
-            self.chatDisplayer?.displayNewChat(contactId: contactId)
-          }
+          coordinator?.showNewChat(contactId: contactId)
         }
       } else {
         showSettingsAlert()
@@ -288,21 +277,7 @@ class NewChatViewController: UITableViewController {
     } else {
       let contactIndex = row
       let contactId = contactIds[contactIndex]
-      dismiss(animated: false) {
-        self.chatDisplayer?.displayNewChat(contactId: contactId)
-      }
-    }
-  }
-
-  override func tableView(_: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
-    let row = indexPath.row
-    if row > 2 {
-      let contactIndex = row - 3
-      let contactId = contactIds[contactIndex]
-      // let newContactController = NewContactController(contactIdForUpdate: contactId)
-      // navigationController?.pushViewController(newContactController, animated: true)
-      let contactProfileController = ContactProfileViewController(contactId: contactId)
-      navigationController?.pushViewController(contactProfileController, animated: true)
+      coordinator?.showNewChat(contactId: contactId)
     }
   }
 
@@ -323,7 +298,6 @@ class NewChatViewController: UITableViewController {
     }
     cell.initialsLabel.text = Utils.getInitials(inputName: contact.name)
     cell.setColor(contact.color)
-    cell.accessoryType = .detailDisclosureButton
   }
 
   private func searchBarIsEmpty() -> Bool {
@@ -355,7 +329,8 @@ extension NewChatViewController: QrCodeReaderDelegate {
 
         DispatchQueue.main.async {
           self.dismiss(animated: true) {
-            self.chatDisplayer?.displayChatForId(chatId: Int(id))
+            self.coordinator?.showChat(chatId: Int(id))
+            // self.chatDisplayer?.displayChatForId(chatId: Int(id))
           }
         }
       }
@@ -407,13 +382,6 @@ extension NewChatViewController: UISearchResultsUpdating {
   }
 }
 
-protocol ContactListDelegate: class {
-  func accessGranted()
-  func accessDenied()
-  func deviceContactsImported()
-}
-
-// TODO: find better name
 struct ContactHighlights {
   let contactDetail: ContactDetail
   let indexes: [Int]

+ 0 - 0
deltachat-ios/NewContactController.swift → deltachat-ios/Controller/NewContactController.swift


+ 7 - 5
deltachat-ios/NewGroupViewController.swift → deltachat-ios/Controller/NewGroupViewController.swift

@@ -9,6 +9,8 @@
 import UIKit
 
 class NewGroupViewController: UITableViewController {
+  weak var coordinator: NewGroupCoordinator?
+
   let contactCellReuseIdentifier = "xyz"
   var contactIds: [Int] = Utils.getContactIds()
   var contactIdsForGroup: Set<Int> = [] {
@@ -18,17 +20,13 @@ class NewGroupViewController: UITableViewController {
     }
   }
 
-  @objc func didPressGroupCreationNextButton() {
-    navigationController?.pushViewController(GroupNameController(contactIdsForGroup: contactIdsForGroup), animated: true)
-  }
-
   override func viewDidLoad() {
     super.viewDidLoad()
     title = "New Group"
     navigationItem.prompt = "0 members and me"
     tableView.register(ContactCell.self, forCellReuseIdentifier: contactCellReuseIdentifier)
     navigationController?.navigationBar.prefersLargeTitles = false
-    let groupCreationNextButton = UIBarButtonItem(title: "Next", style: .done, target: self, action: #selector(didPressGroupCreationNextButton))
+    let groupCreationNextButton = UIBarButtonItem(title: "Next", style: .done, target: self, action: #selector(nextButtonPressed))
     navigationItem.rightBarButtonItem = groupCreationNextButton
   }
 
@@ -75,4 +73,8 @@ class NewGroupViewController: UITableViewController {
       }
     }
   }
+
+  @objc func nextButtonPressed() {
+    coordinator?.showGroupNameController(contactIdsForGroup: contactIdsForGroup)
+  }
 }

+ 2 - 0
deltachat-ios/TopViews/ProfileViewController.swift → deltachat-ios/Controller/ProfileViewController.swift

@@ -9,6 +9,8 @@
 import UIKit
 
 class ProfileViewController: UITableViewController {
+  weak var coordinator: ProfileCoordinator?
+
   var contact: MRContact? {
     // This is nil if we do not have an account setup yet
     if !MRConfig.configured {

+ 0 - 4
deltachat-ios/QrCodeReaderController.swift → deltachat-ios/Controller/QrCodeReaderController.swift

@@ -9,10 +9,6 @@
 import AVFoundation
 import UIKit
 
-protocol QrCodeReaderDelegate: class {
-  func handleQrCode(_ code: String)
-}
-
 class QrCodeReaderController: UIViewController {
   var captureSession = AVCaptureSession()
 

+ 3 - 3
deltachat-ios/TopViews/SettingsController.swift → deltachat-ios/Controller/SettingsController.swift

@@ -13,6 +13,8 @@ import QuickTableViewController
 import UIKit
 
 internal final class SettingsViewController: QuickTableViewController {
+  weak var coordinator: SettingsCoordinator?
+
   let documentInteractionController = UIDocumentInteractionController()
   var backupProgressObserver: Any?
   var configureProgressObserver: Any?
@@ -273,8 +275,6 @@ internal final class SettingsViewController: QuickTableViewController {
   }
 
   private func presentAccountSetup(_: Row) {
-    if let nav = self.navigationController {
-      nav.pushViewController(AccountSetupController(), animated: true)
-    }
+    coordinator?.showAccountSetupController()
   }
 }

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

@@ -0,0 +1,282 @@
+//
+//  AppCoordinator.swift
+//  deltachat-ios
+//
+//  Created by Jonas Reinsch on 07.11.17.
+//  Copyright © 2017 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class AppCoordinator: NSObject, Coordinator, UITabBarControllerDelegate {
+  private let window: UIWindow
+
+  var rootViewController: UIViewController {
+    return tabBarController
+  }
+
+  private var childCoordinators: [Coordinator] = []
+
+  private lazy var tabBarController: UITabBarController = {
+    let tabBarController = UITabBarController()
+    tabBarController.viewControllers = [contactListController, mailboxController, profileController, chatListController, settingsController]
+    // put viewControllers here
+    tabBarController.delegate = self
+    tabBarController.tabBar.tintColor = DCColors.primary
+    // tabBarController.tabBar.isTranslucent = false
+    return tabBarController
+  }()
+
+  // MARK: viewControllers
+
+  private lazy var contactListController: UIViewController = {
+    let controller = ContactListController()
+    let nav = NavigationController(rootViewController: controller)
+    let settingsImage = UIImage(named: "contacts")
+    nav.tabBarItem = UITabBarItem(title: "Contacts", image: settingsImage, tag: 4)
+    let coordinator = ContactListCoordinator(navigationController: nav)
+    self.childCoordinators.append(coordinator)
+    controller.coordinator = coordinator
+    return nav
+  }()
+
+  private lazy var mailboxController: UIViewController = {
+    let controller = ChatViewController(chatId: Int(DC_CHAT_ID_DEADDROP), title: "Mailbox")
+    controller.disableWriting = true
+    let nav = NavigationController(rootViewController: controller)
+    let settingsImage = UIImage(named: "message")
+    nav.tabBarItem = UITabBarItem(title: "Mailbox", image: settingsImage, tag: 4)
+    let coordinator = MailboxCoordinator(navigationController: nav)
+    self.childCoordinators.append(coordinator)
+    controller.coordinator = coordinator
+    return nav
+  }()
+
+  private lazy var profileController: UIViewController = {
+    let controller = ProfileViewController()
+    let nav = NavigationController(rootViewController: controller)
+    let settingsImage = UIImage(named: "report_card")
+    nav.tabBarItem = UITabBarItem(title: "My Profile", image: settingsImage, tag: 4)
+    let coordinator = ProfileCoordinator(rootViewController: nav)
+    self.childCoordinators.append(coordinator)
+    controller.coordinator = coordinator
+    return nav
+  }()
+
+  private lazy var chatListController: UIViewController = {
+    let controller = ChatListController()
+    let nav = NavigationController(rootViewController: controller)
+    let settingsImage = UIImage(named: "chat")
+    nav.tabBarItem = UITabBarItem(title: "Chats", image: settingsImage, tag: 4)
+    let coordinator = ChatListCoordinator(navigationController: nav)
+    self.childCoordinators.append(coordinator)
+    controller.coordinator = coordinator
+    return nav
+  }()
+
+  private lazy var settingsController: UIViewController = {
+    let controller = SettingsViewController()
+    let nav = NavigationController(rootViewController: controller)
+    let settingsImage = UIImage(named: "settings")
+    nav.tabBarItem = UITabBarItem(title: "Settings", image: settingsImage, tag: 4)
+    let coordinator = SettingsCoordinator(navigationController: nav)
+    self.childCoordinators.append(coordinator)
+    controller.coordinator = coordinator
+    return nav
+  }()
+
+  init(window: UIWindow) {
+    self.window = window
+    super.init()
+    window.rootViewController = rootViewController
+    window.makeKeyAndVisible()
+  }
+
+  public func start() {
+    showTab(index: 3)
+  }
+
+  public func showTab(index: Int) {
+    tabBarController.selectedIndex = index
+  }
+
+  public func presentLoginController() {
+    let accountSetupController = AccountSetupController()
+    let accountSetupNavigationController = UINavigationController(rootViewController: accountSetupController)
+    rootViewController.present(accountSetupNavigationController, animated: false, completion: nil)
+  }
+}
+
+class ContactListCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+}
+
+// since mailbox and chatView -tab both use ChatViewController we want to be able to assign different functionality via coordinators -> therefore we override unneeded functions such as showChatDetail -> maybe find better solution in longterm
+class MailboxCoordinator: ChatViewCoordinator {
+  override func showChatDetail(chatId _: Int) {
+    // ignore for now
+  }
+}
+
+class ProfileCoordinator: Coordinator {
+  var rootViewController: UIViewController
+
+  init(rootViewController: UIViewController) {
+    self.rootViewController = rootViewController
+  }
+}
+
+class ChatListCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showNewChatController() {
+    let newChatVC = NewChatViewController()
+    let coordinator = NewChatCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    newChatVC.coordinator = coordinator
+    newChatVC.hidesBottomBarWhenPushed = true
+    navigationController.pushViewController(newChatVC, animated: true)
+  }
+
+  func showChat(chatId: Int) {
+    let chatVC = ChatViewController(chatId: chatId)
+    let coordinator = ChatViewCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    chatVC.coordinator = coordinator
+    chatVC.hidesBottomBarWhenPushed = true
+    navigationController.pushViewController(chatVC, animated: true)
+  }
+}
+
+class SettingsCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showAccountSetupController() {
+    let accountSetupVC = AccountSetupController()
+    accountSetupVC.hidesBottomBarWhenPushed = true
+
+    navigationController.pushViewController(accountSetupVC, animated: true)
+  }
+}
+
+class NewChatCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  private var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showNewGroupController() {
+    let newGroupController = NewGroupViewController()
+    let coordinator = NewGroupCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    newGroupController.coordinator = coordinator
+    navigationController.pushViewController(newGroupController, animated: true)
+  }
+
+  func showQRCodeController() {
+    let controller = QrCodeReaderController()
+    // controller.delegate = self
+    // present(controller, animated: true, completion: nil)
+  }
+
+  func showNewContactController() {
+    let newContactController = NewContactController()
+    navigationController.pushViewController(newContactController, animated: true)
+  }
+
+  func showNewChat(contactId: Int) {
+    let chatId = dc_create_chat_by_contact_id(mailboxPointer, UInt32(contactId))
+    showChat(chatId: Int(chatId))
+  }
+
+  func showChat(chatId: Int) {
+    let chatViewController = ChatViewController(chatId: chatId)
+    let coordinator = ChatViewCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    chatViewController.coordinator = coordinator
+    navigationController.pushViewController(chatViewController, animated: true)
+    navigationController.viewControllers.remove(at: 1)
+  }
+}
+
+class ChatDetailCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  private var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+}
+
+class ChatViewCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showChatDetail(chatId: Int) {
+    let chatDetailViewController = ChatDetailViewController(chatId: chatId)
+    let coordinator = ChatDetailCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    chatDetailViewController.coordinator = coordinator
+    navigationController.pushViewController(chatDetailViewController, animated: true)
+  }
+}
+
+class NewGroupCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  private var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showGroupNameController(contactIdsForGroup: Set<Int>) {
+    let groupNameController = GroupNameController(contactIdsForGroup: contactIdsForGroup)
+    let coordinator = GroupNameCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    groupNameController.coordinator = coordinator
+    navigationController.pushViewController(groupNameController, animated: true)
+  }
+}
+
+class GroupNameCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  private var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showGroupChat(chatId: Int) {
+    let chatViewController = ChatViewController(chatId: chatId)
+    let coordinator = ChatViewCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    chatViewController.coordinator = coordinator
+    navigationController.popToRootViewController(animated: false)
+    navigationController.pushViewController(chatViewController, animated: true)
+  }
+}

+ 0 - 0
deltachat-ios/Wrapper.swift → deltachat-ios/DC/Wrapper.swift


+ 3 - 1
deltachat-ios/events.swift → deltachat-ios/DC/events.swift

@@ -6,6 +6,7 @@
 //  Copyright © 2018 Jonas Reinsch. All rights reserved.
 //
 
+import UIKit
 import UserNotifications
 
 let dcNotificationChanged = Notification.Name(rawValue: "MrEventMsgsChanged")
@@ -91,7 +92,8 @@ public func callbackSwift(event: CInt, data1: CUnsignedLong, data2: CUnsignedLon
       if done {
         UserDefaults.standard.set(true, forKey: Constants.Keys.deltachatUserProvidedCredentialsKey)
         UserDefaults.standard.synchronize()
-        AppDelegate.appCoordinator.setupInnerViewControllers()
+        let appDelegate = UIApplication.shared.delegate as! AppDelegate
+        appDelegate.appCoordinator?.showTab(index: 3)
         AppDelegate.lastErrorDuringConfig = nil
       }
     }

+ 0 - 0
deltachat-ios/wrapper.c → deltachat-ios/DC/wrapper.c


+ 0 - 0
deltachat-ios/wrapper.h → deltachat-ios/DC/wrapper.h


+ 0 - 91
deltachat-ios/GroupNameController.swift

@@ -1,91 +0,0 @@
-//
-//  GroupNameController.swift
-//  deltachat-ios
-//
-//  Created by Alla Reinsch on 20.07.18.
-//  Copyright © 2018 Jonas Reinsch. All rights reserved.
-//
-
-import UIKit
-
-class GroupNameController: UIViewController {
-  var doneButton: UIBarButtonItem!
-  let groupNameTextField = UITextField()
-  let contactIdsForGroup: Set<Int>
-  var groupName = "" {
-    didSet {
-      if groupName.isEmpty {
-        logger.info("empty")
-        doneButton.isEnabled = false
-      } else {
-        logger.info("something")
-        doneButton.isEnabled = true
-      }
-    }
-  }
-
-  init(contactIdsForGroup: Set<Int>) {
-    self.contactIdsForGroup = contactIdsForGroup
-    super.init(nibName: nil, bundle: nil)
-  }
-
-  required init?(coder _: NSCoder) {
-    fatalError("init(coder:) has not been implemented")
-  }
-
-  func layoutTextField() {
-    groupNameTextField.translatesAutoresizingMaskIntoConstraints = false
-    view.addSubview(groupNameTextField)
-    groupNameTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
-    groupNameTextField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
-    groupNameTextField.placeholder = "Group Name"
-    groupNameTextField.becomeFirstResponder()
-  }
-
-  override func viewDidLoad() {
-    super.viewDidLoad()
-    title = "Group Name"
-    groupNameTextField.delegate = self
-    layoutTextField()
-
-    doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(didPressDoneButton))
-    navigationItem.rightBarButtonItem = doneButton
-    doneButton.isEnabled = false
-  }
-
-  @objc func didPressDoneButton() {
-    logger.info("Done Button pressed")
-    let groupChatId = dc_create_group_chat(mailboxPointer, 0, groupName)
-    for contactId in contactIdsForGroup {
-      let success = dc_add_contact_to_chat(mailboxPointer, groupChatId, UInt32(contactId))
-      if success == 1 {
-        logger.info("successfully added \(contactId) to group \(groupName)")
-      } else {
-        // FIXME:
-        fatalError("failed to add \(contactId) to group \(groupName)")
-      }
-    }
-    groupNameTextField.resignFirstResponder()
-    let root = navigationController?.presentingViewController
-    navigationController?.dismiss(animated: true) {
-      let chatVC = ChatViewController(chatId: Int(groupChatId))
-      if let navigationRoot = root as? UINavigationController {
-        navigationRoot.pushViewController(chatVC, animated: true)
-      }
-    }
-  }
-
-  override func didReceiveMemoryWarning() {
-    super.didReceiveMemoryWarning()
-    // Dispose of any resources that can be recreated.
-  }
-}
-
-extension GroupNameController: UITextFieldDelegate {
-  func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
-    let text = (textField.text! as NSString).replacingCharacters(in: range, with: string)
-    groupName = text
-
-    return true
-  }
-}

+ 0 - 0
deltachat-ios/DeviceContactsHandler.swift → deltachat-ios/Handler/DeviceContactsHandler.swift


+ 0 - 0
deltachat-ios/HudHandler.swift → deltachat-ios/Handler/HudHandler.swift


+ 0 - 0
deltachat-ios/Colors.swift → deltachat-ios/Helper/Colors.swift


+ 1 - 5
deltachat-ios/Constants.swift → deltachat-ios/Helper/Constants.swift

@@ -20,11 +20,7 @@ struct Constants {
     static let deltachatImapEmailKey = "__DELTACHAT_IMAP_EMAIL_KEY__"
     static let deltachatImapPasswordKey = "__DELTACHAT_IMAP_PASSWORD_KEY__"
   }
-
-  // static let primaryColor = UIColor(red: 81 / 255, green: 73 / 255, blue: 255 / 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))
   static let onlineShadow = UIImage(color: UIColor(hexString: "3ed67e"), size: CGSize(width: 1, height: 1))
 

+ 0 - 0
deltachat-ios/Extensions/Extensions.swift → deltachat-ios/Helper/Extensions.swift


+ 29 - 0
deltachat-ios/Helper/Protocols.swift

@@ -0,0 +1,29 @@
+//
+//  Protocols.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 03.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+protocol Coordinator: class {
+  // var rootViewController: UIViewController { get }
+  // func start()
+}
+
+protocol QrCodeReaderDelegate: class {
+  func handleQrCode(_ code: String)
+}
+
+protocol ContactListDelegate: class {
+  func accessGranted()
+  func accessDenied()
+  func deviceContactsImported()
+}
+
+protocol ChatDisplayer: class {
+  func displayNewChat(contactId: Int)
+  func displayChatForId(chatId: Int)
+}

+ 0 - 0
deltachat-ios/Extensions/UIImage+Extension.swift → deltachat-ios/Helper/UIImage+Extension.swift


+ 0 - 0
deltachat-ios/Extensions/UIViewController+Extension.swift → deltachat-ios/Helper/UIViewController+Extension.swift


+ 0 - 0
deltachat-ios/Utils.swift → deltachat-ios/Helper/Utils.swift


+ 22 - 0
deltachat-ios/Model/Location.swift

@@ -0,0 +1,22 @@
+//
+//  Location.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 03.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import CoreLocation
+import Foundation
+import MessageKit
+
+struct Location: LocationItem {
+  var location: CLLocation
+
+  var size: CGSize
+
+  init(location: CLLocation, size: CGSize) {
+    self.location = location
+    self.size = size
+  }
+}

+ 32 - 0
deltachat-ios/Model/Media.swift

@@ -0,0 +1,32 @@
+//
+//  Media.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 03.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import CoreLocation
+import Foundation
+import MessageKit
+
+struct Media: MediaItem {
+  var url: URL?
+
+  var image: UIImage?
+
+  var placeholderImage: UIImage = UIImage(named: "ic_attach_file_36pt")!
+
+  var size: CGSize {
+    if let image = image {
+      return image.size
+    } else {
+      return placeholderImage.size
+    }
+  }
+
+  init(url: URL? = nil, image: UIImage? = nil) {
+    self.url = url
+    self.image = image
+  }
+}

+ 0 - 32
deltachat-ios/Message.swift → deltachat-ios/Model/Message.swift

@@ -10,38 +10,6 @@ import CoreLocation
 import Foundation
 import MessageKit
 
-struct Location: LocationItem {
-  var location: CLLocation
-
-  var size: CGSize
-
-  init(location: CLLocation, size: CGSize) {
-    self.location = location
-    self.size = size
-  }
-}
-
-struct Media: MediaItem {
-  var url: URL?
-
-  var image: UIImage?
-
-  var placeholderImage: UIImage = UIImage(named: "ic_attach_file_36pt")!
-
-  var size: CGSize {
-    if let image = image {
-      return image.size
-    } else {
-      return placeholderImage.size
-    }
-  }
-
-  init(url: URL? = nil, image: UIImage? = nil) {
-    self.url = url
-    self.image = image
-  }
-}
-
 struct Message: MessageType {
   var messageId: String
   var sender: Sender

+ 69 - 66
deltachat-ios/NewGroupMemberChoiceController.swift

@@ -8,80 +8,83 @@
 
 import UIKit
 
-class ViewController: UIViewController {
-  override func viewDidLoad() {
-    super.viewDidLoad()
+/*
+ class ViewController: UIViewController {
+ override func viewDidLoad() {
+   super.viewDidLoad()
 
-    let n: CGFloat = 150
-    let l: CGFloat = 40
-    let generalView = UIView()
-    let square = UIView()
-    square.layer.cornerRadius = n / 2
-    let nameLabel = UILabel()
-    nameLabel.text = "Alic Doe"
-    square.translatesAutoresizingMaskIntoConstraints = false
-    nameLabel.translatesAutoresizingMaskIntoConstraints = false
-    generalView.translatesAutoresizingMaskIntoConstraints = false
+   let n: CGFloat = 150
+   let l: CGFloat = 40
+   let generalView = UIView()
+   let square = UIView()
+   square.layer.cornerRadius = n / 2
+   let nameLabel = UILabel()
+   nameLabel.text = "Alic Doe"
+   square.translatesAutoresizingMaskIntoConstraints = false
+   nameLabel.translatesAutoresizingMaskIntoConstraints = false
+   generalView.translatesAutoresizingMaskIntoConstraints = false
 
-    view.addSubview(generalView)
-    view.addSubview(square)
-    view.addSubview(nameLabel)
-    generalView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
-    generalView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
-    square.centerXAnchor.constraint(equalTo: generalView.centerXAnchor).isActive = true
-    square.centerYAnchor.constraint(equalTo: generalView.centerYAnchor).isActive = true
-    nameLabel.topAnchor.constraint(equalTo: square.bottomAnchor).isActive = true
-    nameLabel.leadingAnchor.constraint(equalTo: square.leadingAnchor).isActive = true
+   view.addSubview(generalView)
+   view.addSubview(square)
+   view.addSubview(nameLabel)
+   generalView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
+   generalView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
+   square.centerXAnchor.constraint(equalTo: generalView.centerXAnchor).isActive = true
+   square.centerYAnchor.constraint(equalTo: generalView.centerYAnchor).isActive = true
+   nameLabel.topAnchor.constraint(equalTo: square.bottomAnchor).isActive = true
+   nameLabel.leadingAnchor.constraint(equalTo: square.leadingAnchor).isActive = true
 
-    square.widthAnchor.constraint(equalToConstant: n).isActive = true
-    square.heightAnchor.constraint(equalToConstant: n).isActive = true
-    nameLabel.widthAnchor.constraint(equalToConstant: n).isActive = true
-    nameLabel.heightAnchor.constraint(equalToConstant: l).isActive = true
-    generalView.widthAnchor.constraint(equalToConstant: n).isActive = true
-    generalView.heightAnchor.constraint(equalToConstant: n + l).isActive = true
-    square.backgroundColor = UIColor.blue
-    nameLabel.backgroundColor = UIColor.green
-    generalView.backgroundColor = UIColor.cyan
-    nameLabel.textColor = UIColor.white
-    nameLabel.font = UIFont.systemFont(ofSize: 14)
+   square.widthAnchor.constraint(equalToConstant: n).isActive = true
+   square.heightAnchor.constraint(equalToConstant: n).isActive = true
+   nameLabel.widthAnchor.constraint(equalToConstant: n).isActive = true
+   nameLabel.heightAnchor.constraint(equalToConstant: l).isActive = true
+   generalView.widthAnchor.constraint(equalToConstant: n).isActive = true
+   generalView.heightAnchor.constraint(equalToConstant: n + l).isActive = true
+   square.backgroundColor = UIColor.blue
+   nameLabel.backgroundColor = UIColor.green
+   generalView.backgroundColor = UIColor.cyan
+   nameLabel.textColor = UIColor.white
+   nameLabel.font = UIFont.systemFont(ofSize: 14)
 
-    let deleteButton = UIButton()
-    deleteButton.translatesAutoresizingMaskIntoConstraints = false
+   let deleteButton = UIButton()
+   deleteButton.translatesAutoresizingMaskIntoConstraints = false
 
-    let sin45: CGFloat = 0.7071
-    let squareRadius: CGFloat = n / 2
-    let deltaX: CGFloat = sin45 * squareRadius
-    let deltaY: CGFloat = squareRadius - deltaX
-    let deleteButtonWidth: CGFloat = deltaX
-    let deleteButtonHeight: CGFloat = deltaX
-    deleteButton.layer.cornerRadius = deleteButtonWidth / 2
+   let sin45: CGFloat = 0.7071
+   let squareRadius: CGFloat = n / 2
+   let deltaX: CGFloat = sin45 * squareRadius
+   let deltaY: CGFloat = squareRadius - deltaX
+   let deleteButtonWidth: CGFloat = deltaX
+   let deleteButtonHeight: CGFloat = deltaX
+   deleteButton.layer.cornerRadius = deleteButtonWidth / 2
 
-    deleteButton.widthAnchor.constraint(equalToConstant: deleteButtonWidth).isActive = true
-    deleteButton.heightAnchor.constraint(equalToConstant: deleteButtonHeight).isActive = true
-    deleteButton.backgroundColor = UIColor.gray
-    deleteButton.clipsToBounds = true
+   deleteButton.widthAnchor.constraint(equalToConstant: deleteButtonWidth).isActive = true
+   deleteButton.heightAnchor.constraint(equalToConstant: deleteButtonHeight).isActive = true
+   deleteButton.backgroundColor = UIColor.gray
+   deleteButton.clipsToBounds = true
 
-    deleteButton.layer.borderWidth = 3
-    deleteButton.layer.borderColor = UIColor.white.cgColor
-    deleteButton.setTitle("✕", for: .normal)
-    deleteButton.titleLabel?.font = UIFont.systemFont(ofSize: 30)
+   deleteButton.layer.borderWidth = 3
+   deleteButton.layer.borderColor = UIColor.white.cgColor
+   deleteButton.setTitle("✕", for: .normal)
+   deleteButton.titleLabel?.font = UIFont.systemFont(ofSize: 30)
 
-    deleteButton.addTarget(self, action: #selector(didPressDeleteButton), for: .touchUpInside)
+   deleteButton.addTarget(self, action: #selector(didPressDeleteButton), for: .touchUpInside)
 
-    square.addSubview(deleteButton)
-    deleteButton.centerYAnchor.constraint(equalTo: square.topAnchor, constant: deltaY).isActive = true
-    deleteButton.centerXAnchor.constraint(equalTo: square.centerXAnchor, constant: deltaX).isActive = true
-  }
+   square.addSubview(deleteButton)
+   deleteButton.centerYAnchor.constraint(equalTo: square.topAnchor, constant: deltaY).isActive = true
+   deleteButton.centerXAnchor.constraint(equalTo: square.centerXAnchor, constant: deltaX).isActive = true
+ }
 
-  @objc func didPressDeleteButton() {
-    if view.backgroundColor == UIColor.red {
-      view.backgroundColor = UIColor.white
-    } else {
-      view.backgroundColor = UIColor.red
-    }
-  }
+ @objc func didPressDeleteButton() {
+   if view.backgroundColor == UIColor.red {
+     view.backgroundColor = UIColor.white
+   } else {
+     view.backgroundColor = UIColor.red
+   }
+ }
 
-  override func didReceiveMemoryWarning() {
-    super.didReceiveMemoryWarning()
-  }
-}
+ override func didReceiveMemoryWarning() {
+   super.didReceiveMemoryWarning()
+ }
+ }
+
+ */

+ 0 - 0
deltachat-ios/ActionCell.swift → deltachat-ios/View/ActionCell.swift


+ 36 - 24
deltachat-ios/ContactCell.swift → deltachat-ios/View/ContactCell.swift

@@ -9,9 +9,39 @@
 import UIKit
 
 class ContactCell: UITableViewCell {
-  let avatar = UIView()
-  let imgView = UIImageView()
-  let initialsLabel = UILabel()
+  private let initialsLabelSize: CGFloat = 54
+  private let imgSize: CGFloat = 25
+
+  let avatar: UIView = {
+    let avatar = UIView()
+    return avatar
+  }()
+
+  lazy var imgView: UIImageView = {
+    let imgView = UIImageView()
+    let img = UIImage(named: "approval")!.withRenderingMode(.alwaysTemplate)
+    imgView.isHidden = true
+    imgView.image = img
+    imgView.bounds = CGRect(
+      x: 0,
+      y: 0,
+      width: imgSize, height: imgSize
+    )
+    return imgView
+  }()
+
+  lazy var initialsLabel: UILabel = {
+    let initialsLabel = UILabel()
+    initialsLabel.textAlignment = NSTextAlignment.center
+    initialsLabel.textColor = UIColor.white
+    initialsLabel.font = UIFont.systemFont(ofSize: 22)
+    initialsLabel.backgroundColor = UIColor.green
+    let initialsLabelCornerRadius = (initialsLabelSize - 6) / 2
+    initialsLabel.layer.cornerRadius = initialsLabelCornerRadius
+    initialsLabel.clipsToBounds = true
+    return initialsLabel
+  }()
+
   let nameLabel = UILabel()
   let emailLabel = UILabel()
 
@@ -27,15 +57,12 @@ class ContactCell: UITableViewCell {
 
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
     super.init(style: style, reuseIdentifier: reuseIdentifier)
+    setupSubviews()
+  }
 
-    // configure and layout initialsLabel
-    let initialsLabelSize: CGFloat = 54
-    let initialsLabelCornerRadius = (initialsLabelSize - 6) / 2
+  private func setupSubviews() {
     let margin: CGFloat = 15
 
-    initialsLabel.textAlignment = NSTextAlignment.center
-    initialsLabel.textColor = UIColor.white
-    initialsLabel.font = UIFont.systemFont(ofSize: 22)
     initialsLabel.translatesAutoresizingMaskIntoConstraints = false
     avatar.translatesAutoresizingMaskIntoConstraints = false
     initialsLabel.widthAnchor.constraint(equalToConstant: initialsLabelSize - 6).isActive = true
@@ -45,10 +72,6 @@ class ContactCell: UITableViewCell {
     avatar.widthAnchor.constraint(equalToConstant: initialsLabelSize).isActive = true
     avatar.heightAnchor.constraint(equalToConstant: initialsLabelSize).isActive = true
 
-    initialsLabel.backgroundColor = UIColor.green
-
-    initialsLabel.layer.cornerRadius = initialsLabelCornerRadius
-    initialsLabel.clipsToBounds = true
     avatar.addSubview(initialsLabel)
     contentView.addSubview(avatar)
 
@@ -83,16 +106,6 @@ class ContactCell: UITableViewCell {
     emailLabel.textColor = UIColor(hexString: "848ba7")
     emailLabel.lineBreakMode = .byTruncatingTail
 
-    let img = UIImage(named: "approval")!.withRenderingMode(.alwaysTemplate)
-    let imgSize: CGFloat = 25
-
-    imgView.isHidden = true
-    imgView.image = img
-    imgView.bounds = CGRect(
-      x: 0,
-      y: 0,
-      width: imgSize, height: imgSize
-    )
     imgView.tintColor = DCColors.primary
 
     avatar.addSubview(imgView)
@@ -108,7 +121,6 @@ class ContactCell: UITableViewCell {
   func setImage(_ img: UIImage) {
     let attachment = NSTextAttachment()
     attachment.image = img
-
     initialsLabel.attributedText = NSAttributedString(attachment: attachment)
   }
 

+ 0 - 0
deltachat-ios/CustomCell.swift → deltachat-ios/View/CustomCell.swift


+ 64 - 0
deltachat-ios/View/GroupNameCell.swift

@@ -0,0 +1,64 @@
+//
+//  GroupNameCell.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 06.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class GroupLabelCell: UITableViewCell {
+  private let groupBadgeSize: CGFloat = 60
+  var groupNameUpdated: ((String) -> Void)? // use this callback to update editButton in navigationController
+
+  lazy var groupBadge: InitialsLabel = {
+    let badge = InitialsLabel(size: groupBadgeSize)
+    badge.set(color: UIColor.lightGray)
+    return badge
+  }()
+
+  lazy var inputField: UITextField = {
+    let textField = UITextField()
+    textField.placeholder = "Group Name"
+    textField.borderStyle = .none
+    textField.becomeFirstResponder()
+    textField.autocorrectionType = .no
+    textField.addTarget(self, action: #selector(nameFieldChanged), for: .editingChanged)
+    return textField
+  }()
+
+  override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+    super.init(style: style, reuseIdentifier: reuseIdentifier)
+    setupSubviews()
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  private func setupSubviews() {
+    contentView.addSubview(groupBadge)
+    groupBadge.translatesAutoresizingMaskIntoConstraints = false
+
+    groupBadge.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor, constant: 0).isActive = true
+    groupBadge.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor, constant: 5).isActive = true
+    groupBadge.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: -5).isActive = true
+    groupBadge.widthAnchor.constraint(equalToConstant: groupBadgeSize).isActive = true
+    groupBadge.heightAnchor.constraint(equalToConstant: groupBadgeSize).isActive = true
+
+    contentView.addSubview(inputField)
+    inputField.translatesAutoresizingMaskIntoConstraints = false
+
+    inputField.leadingAnchor.constraint(equalTo: groupBadge.trailingAnchor, constant: 15).isActive = true
+    inputField.heightAnchor.constraint(equalToConstant: 45).isActive = true
+    inputField.centerYAnchor.constraint(equalTo: groupBadge.centerYAnchor, constant: 0).isActive = true
+    inputField.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor, constant: 0).isActive = true
+  }
+
+  @objc func nameFieldChanged() {
+    let groupName = inputField.text ?? ""
+    groupBadge.set(name: groupName)
+    groupNameUpdated?(groupName)
+  }
+}

+ 39 - 0
deltachat-ios/View/InitialsLabel.swift

@@ -0,0 +1,39 @@
+//
+//  InitialsLabel.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 03.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class InitialsLabel: UILabel {
+  convenience init(name: String, color: UIColor, size: CGFloat) {
+    self.init(size: size)
+    set(name: name)
+    set(color: color)
+  }
+
+  init(size: CGFloat) {
+    super.init(frame: CGRect(x: 0, y: 0, width: size, height: size))
+    textAlignment = NSTextAlignment.center
+    textColor = UIColor.white
+    adjustsFontSizeToFitWidth = true
+    let initialsLabelCornerRadius = size / 2
+    layer.cornerRadius = initialsLabelCornerRadius
+    clipsToBounds = true
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  func set(name: String) {
+    text = Utils.getInitials(inputName: name)
+  }
+
+  func set(color: UIColor) {
+    backgroundColor = color
+  }
+}

+ 0 - 0
deltachat-ios/ProgressHud.swift → deltachat-ios/View/ProgressHud.swift


+ 0 - 0
deltachat-ios/QrCodeView.swift → deltachat-ios/View/QrCodeView.swift


+ 0 - 0
deltachat-ios/TextFieldCell.swift → deltachat-ios/View/TextFieldCell.swift


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