Ver Fonte

Merge pull request #67 from deltachat/ChatDetail

Chat Detail Implementation
nayooti há 6 anos atrás
pai
commit
12dd88c4ac

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

@@ -8,7 +8,6 @@
 
 
 /* Begin PBXBuildFile section */
 /* Begin PBXBuildFile section */
 		6795F63A82E94FF7CD2CEC0F /* Pods_deltachat_iosTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F7009234DB9408201A6CDCB /* Pods_deltachat_iosTests.framework */; };
 		6795F63A82E94FF7CD2CEC0F /* Pods_deltachat_iosTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F7009234DB9408201A6CDCB /* Pods_deltachat_iosTests.framework */; };
-		7070FB3D20FDD9FE000DC258 /* NewGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB3C20FDD9FE000DC258 /* NewGroupViewController.swift */; };
 		7070FB4020FF3421000DC258 /* dc_chat.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB3E20FF3420000DC258 /* dc_chat.c */; };
 		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 */; };
 		7070FB4120FF3421000DC258 /* dc_smtp.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB3F20FF3421000DC258 /* dc_smtp.c */; };
 		7070FB5D20FF345F000DC258 /* dc_mimefactory.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB4220FF345B000DC258 /* dc_mimefactory.c */; };
 		7070FB5D20FF345F000DC258 /* dc_mimefactory.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB4220FF345B000DC258 /* dc_mimefactory.c */; };
@@ -48,7 +47,7 @@
 		7070FB9220FF4118000DC258 /* dc_imap.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB8820FF4118000DC258 /* dc_imap.c */; };
 		7070FB9220FF4118000DC258 /* dc_imap.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB8820FF4118000DC258 /* dc_imap.c */; };
 		7070FB9320FF4118000DC258 /* dc_msg.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB8920FF4118000DC258 /* dc_msg.c */; };
 		7070FB9320FF4118000DC258 /* dc_msg.c in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB8920FF4118000DC258 /* dc_msg.c */; };
 		7070FB9B2101ECBB000DC258 /* GroupNameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB9A2101ECBB000DC258 /* GroupNameController.swift */; };
 		7070FB9B2101ECBB000DC258 /* GroupNameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7070FB9A2101ECBB000DC258 /* GroupNameController.swift */; };
-		7092474120B3869500AF8799 /* ContactProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7092474020B3869500AF8799 /* ContactProfileViewController.swift */; };
+		7092474120B3869500AF8799 /* ContactDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7092474020B3869500AF8799 /* ContactDetailViewController.swift */; };
 		70B08FCD21073B910097D3EA /* NewGroupMemberChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */; };
 		70B08FCD21073B910097D3EA /* NewGroupMemberChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */; };
 		70B8882E2091B8550074812E /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B8882D2091B8550074812E /* ContactCell.swift */; };
 		70B8882E2091B8550074812E /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B8882D2091B8550074812E /* ContactCell.swift */; };
 		78113B71224400F300BCA958 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78113B6F224400F300BCA958 /* libssl.a */; };
 		78113B71224400F300BCA958 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78113B6F224400F300BCA958 /* libssl.a */; };
@@ -97,7 +96,7 @@
 		AE851AC7227C776400ED86F0 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC6227C776400ED86F0 /* Location.swift */; };
 		AE851AC7227C776400ED86F0 /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC6227C776400ED86F0 /* Location.swift */; };
 		AE851AC9227C77CF00ED86F0 /* Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC8227C77CF00ED86F0 /* Media.swift */; };
 		AE851AC9227C77CF00ED86F0 /* Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851AC8227C77CF00ED86F0 /* Media.swift */; };
 		AE851ACE227CA54400ED86F0 /* InitialsLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */; };
 		AE851ACE227CA54400ED86F0 /* InitialsLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */; };
-		AE851AD0227DF50900ED86F0 /* ChatDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACF227DF50900ED86F0 /* ChatDetailViewController.swift */; };
+		AE851AD0227DF50900ED86F0 /* SingleChatDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACF227DF50900ED86F0 /* SingleChatDetailViewController.swift */; };
 		AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */; };
 		AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */; };
 		AEACE2DF1FB3246400DCDD78 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2DE1FB3246400DCDD78 /* Message.swift */; };
 		AEACE2DF1FB3246400DCDD78 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2DE1FB3246400DCDD78 /* Message.swift */; };
 		AEACE2E31FB32B5C00DCDD78 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2E21FB32B5C00DCDD78 /* Constants.swift */; };
 		AEACE2E31FB32B5C00DCDD78 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2E21FB32B5C00DCDD78 /* Constants.swift */; };
@@ -105,6 +104,9 @@
 		AEE56D762253431E007DC082 /* AccountSetupController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE56D752253431E007DC082 /* AccountSetupController.swift */; };
 		AEE56D762253431E007DC082 /* AccountSetupController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE56D752253431E007DC082 /* AccountSetupController.swift */; };
 		AEE56D7D2253ADB4007DC082 /* HudHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE56D7C2253ADB4007DC082 /* HudHandler.swift */; };
 		AEE56D7D2253ADB4007DC082 /* HudHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE56D7C2253ADB4007DC082 /* HudHandler.swift */; };
 		AEE56D80225504DB007DC082 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE56D7F225504DB007DC082 /* Extensions.swift */; };
 		AEE56D80225504DB007DC082 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE56D7F225504DB007DC082 /* Extensions.swift */; };
+		AEE6EC382281AF2D00EDC689 /* InitialsBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE6EC372281AF2D00EDC689 /* InitialsBadge.swift */; };
+		AEE6EC3F2282C59C00EDC689 /* GroupMembersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE6EC3E2282C59C00EDC689 /* GroupMembersViewController.swift */; };
+		AEE6EC412282DF5700EDC689 /* MailboxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE6EC402282DF5700EDC689 /* MailboxViewController.swift */; };
 /* End PBXBuildFile section */
 /* End PBXBuildFile section */
 
 
 /* Begin PBXContainerItemProxy section */
 /* Begin PBXContainerItemProxy section */
@@ -142,7 +144,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>"; };
 		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; };
 		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; };
 		6241BE1534A653E79AD5D01D /* Pods_deltachat_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_deltachat_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-		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>"; };
 		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>"; };
 		7070FB3F20FF3421000DC258 /* dc_smtp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_smtp.c; sourceTree = "<group>"; };
 		7070FB4220FF345B000DC258 /* dc_mimefactory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_mimefactory.c; sourceTree = "<group>"; };
 		7070FB4220FF345B000DC258 /* dc_mimefactory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_mimefactory.c; sourceTree = "<group>"; };
@@ -191,7 +192,7 @@
 		7070FB8820FF4118000DC258 /* dc_imap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_imap.c; sourceTree = "<group>"; };
 		7070FB8820FF4118000DC258 /* dc_imap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_imap.c; sourceTree = "<group>"; };
 		7070FB8920FF4118000DC258 /* dc_msg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_msg.c; sourceTree = "<group>"; };
 		7070FB8920FF4118000DC258 /* dc_msg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dc_msg.c; sourceTree = "<group>"; };
 		7070FB9A2101ECBB000DC258 /* GroupNameController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupNameController.swift; sourceTree = "<group>"; };
 		7070FB9A2101ECBB000DC258 /* GroupNameController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupNameController.swift; sourceTree = "<group>"; };
-		7092474020B3869500AF8799 /* ContactProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactProfileViewController.swift; sourceTree = "<group>"; };
+		7092474020B3869500AF8799 /* ContactDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDetailViewController.swift; sourceTree = "<group>"; };
 		70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGroupMemberChoiceController.swift; sourceTree = "<group>"; };
 		70B08FCC21073B910097D3EA /* NewGroupMemberChoiceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewGroupMemberChoiceController.swift; sourceTree = "<group>"; };
 		70B8882D2091B8550074812E /* ContactCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = "<group>"; };
 		70B8882D2091B8550074812E /* ContactCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = "<group>"; };
 		78113B6F224400F300BCA958 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = "deltachat-ios/libraries/openssl/lib/libssl.a"; sourceTree = "<group>"; };
 		78113B6F224400F300BCA958 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = "deltachat-ios/libraries/openssl/lib/libssl.a"; sourceTree = "<group>"; };
@@ -290,7 +291,7 @@
 		AE851AC6227C776400ED86F0 /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.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>"; };
 		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>"; };
 		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>"; };
+		AE851ACF227DF50900ED86F0 /* SingleChatDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleChatDetailViewController.swift; sourceTree = "<group>"; };
 		AEA9CC2F22522DA20061D113 /* librpgp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = librpgp.h; 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>"; };
 		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>"; };
 		AEACE2DE1FB3246400DCDD78 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
@@ -299,6 +300,9 @@
 		AEE56D752253431E007DC082 /* AccountSetupController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSetupController.swift; sourceTree = "<group>"; };
 		AEE56D752253431E007DC082 /* AccountSetupController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSetupController.swift; sourceTree = "<group>"; };
 		AEE56D7C2253ADB4007DC082 /* HudHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HudHandler.swift; sourceTree = "<group>"; };
 		AEE56D7C2253ADB4007DC082 /* HudHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HudHandler.swift; sourceTree = "<group>"; };
 		AEE56D7F225504DB007DC082 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
 		AEE56D7F225504DB007DC082 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
+		AEE6EC372281AF2D00EDC689 /* InitialsBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialsBadge.swift; sourceTree = "<group>"; };
+		AEE6EC3E2282C59C00EDC689 /* GroupMembersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMembersViewController.swift; sourceTree = "<group>"; };
+		AEE6EC402282DF5700EDC689 /* MailboxViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailboxViewController.swift; sourceTree = "<group>"; };
 		FECB35E2B04CD5F5D02C157A /* Pods-deltachat-iosTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-deltachat-iosTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-deltachat-iosTests/Pods-deltachat-iosTests.release.xcconfig"; sourceTree = "<group>"; };
 		FECB35E2B04CD5F5D02C157A /* Pods-deltachat-iosTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-deltachat-iosTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-deltachat-iosTests/Pods-deltachat-iosTests.release.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 /* End PBXFileReference section */
 
 
@@ -589,15 +593,16 @@
 				AEE56D752253431E007DC082 /* AccountSetupController.swift */,
 				AEE56D752253431E007DC082 /* AccountSetupController.swift */,
 				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
 				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
 				789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */,
 				789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */,
-				7092474020B3869500AF8799 /* ContactProfileViewController.swift */,
+				7092474020B3869500AF8799 /* ContactDetailViewController.swift */,
 				7AE0A5481FC42F65005ECB4B /* NewChatViewController.swift */,
 				7AE0A5481FC42F65005ECB4B /* NewChatViewController.swift */,
 				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
 				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
 				78E45E3F21D3D70700D4B15E /* ContactListController.swift */,
 				78E45E3F21D3D70700D4B15E /* ContactListController.swift */,
 				78ED838E21D5927A00243125 /* ProfileViewController.swift */,
 				78ED838E21D5927A00243125 /* ProfileViewController.swift */,
 				78E45E3921D3CFBC00D4B15E /* SettingsController.swift */,
 				78E45E3921D3CFBC00D4B15E /* SettingsController.swift */,
-				7070FB3C20FDD9FE000DC258 /* NewGroupViewController.swift */,
 				7070FB9A2101ECBB000DC258 /* GroupNameController.swift */,
 				7070FB9A2101ECBB000DC258 /* GroupNameController.swift */,
-				AE851ACF227DF50900ED86F0 /* ChatDetailViewController.swift */,
+				AE851ACF227DF50900ED86F0 /* SingleChatDetailViewController.swift */,
+				AEE6EC3E2282C59C00EDC689 /* GroupMembersViewController.swift */,
+				AEE6EC402282DF5700EDC689 /* MailboxViewController.swift */,
 			);
 			);
 			path = Controller;
 			path = Controller;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -636,6 +641,7 @@
 				AE38B31722672DFC00EC37A1 /* ActionCell.swift */,
 				AE38B31722672DFC00EC37A1 /* ActionCell.swift */,
 				AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */,
 				AE851ACD227CA54300ED86F0 /* InitialsLabel.swift */,
 				AE25F08F22807AD800CDEA66 /* GroupNameCell.swift */,
 				AE25F08F22807AD800CDEA66 /* GroupNameCell.swift */,
+				AEE6EC372281AF2D00EDC689 /* InitialsBadge.swift */,
 			);
 			);
 			path = View;
 			path = View;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -946,7 +952,6 @@
 				7070FB6D20FF345F000DC258 /* dc_imex.c in Sources */,
 				7070FB6D20FF345F000DC258 /* dc_imex.c in Sources */,
 				7070FB6620FF345F000DC258 /* dc_param.c in Sources */,
 				7070FB6620FF345F000DC258 /* dc_param.c in Sources */,
 				7070FB9220FF4118000DC258 /* dc_imap.c in Sources */,
 				7070FB9220FF4118000DC258 /* dc_imap.c in Sources */,
-				7070FB3D20FDD9FE000DC258 /* NewGroupViewController.swift in Sources */,
 				7070FB7720FF345F000DC258 /* dc_qr.c in Sources */,
 				7070FB7720FF345F000DC258 /* dc_qr.c in Sources */,
 				78E45E4421D3F14A00D4B15E /* UIImage+Extension.swift in Sources */,
 				78E45E4421D3F14A00D4B15E /* UIImage+Extension.swift in Sources */,
 				70B08FCD21073B910097D3EA /* NewGroupMemberChoiceController.swift in Sources */,
 				70B08FCD21073B910097D3EA /* NewGroupMemberChoiceController.swift in Sources */,
@@ -960,6 +965,7 @@
 				AE851AC7227C776400ED86F0 /* Location.swift in Sources */,
 				AE851AC7227C776400ED86F0 /* Location.swift in Sources */,
 				7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */,
 				7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */,
 				AE25F09022807AD800CDEA66 /* GroupNameCell.swift in Sources */,
 				AE25F09022807AD800CDEA66 /* GroupNameCell.swift in Sources */,
+				AEE6EC3F2282C59C00EDC689 /* GroupMembersViewController.swift in Sources */,
 				78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */,
 				78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */,
 				AE8519EA2272FDCA00ED86F0 /* DeviceContactsHandler.swift in Sources */,
 				AE8519EA2272FDCA00ED86F0 /* DeviceContactsHandler.swift in Sources */,
 				78ED838321D5379000243125 /* TextFieldCell.swift in Sources */,
 				78ED838321D5379000243125 /* TextFieldCell.swift in Sources */,
@@ -974,6 +980,7 @@
 				7070FB6020FF345F000DC258 /* dc_hash.c in Sources */,
 				7070FB6020FF345F000DC258 /* dc_hash.c in Sources */,
 				AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */,
 				AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */,
 				7070FB4020FF3421000DC258 /* dc_chat.c in Sources */,
 				7070FB4020FF3421000DC258 /* dc_chat.c in Sources */,
+				AEE6EC412282DF5700EDC689 /* MailboxViewController.swift in Sources */,
 				7070FB7320FF345F000DC258 /* dc_aheader.c in Sources */,
 				7070FB7320FF345F000DC258 /* dc_aheader.c in Sources */,
 				7070FB6120FF345F000DC258 /* dc_securejoin.c in Sources */,
 				7070FB6120FF345F000DC258 /* dc_securejoin.c in Sources */,
 				78ED838F21D5927A00243125 /* ProfileViewController.swift in Sources */,
 				78ED838F21D5927A00243125 /* ProfileViewController.swift in Sources */,
@@ -997,12 +1004,13 @@
 				7A451DBE1FB4AD0700177250 /* Wrapper.swift in Sources */,
 				7A451DBE1FB4AD0700177250 /* Wrapper.swift in Sources */,
 				AE851ACE227CA54400ED86F0 /* InitialsLabel.swift in Sources */,
 				AE851ACE227CA54400ED86F0 /* InitialsLabel.swift in Sources */,
 				7070FB6420FF345F000DC258 /* dc_dehtml.c in Sources */,
 				7070FB6420FF345F000DC258 /* dc_dehtml.c in Sources */,
+				AEE6EC382281AF2D00EDC689 /* InitialsBadge.swift in Sources */,
 				70B8882E2091B8550074812E /* ContactCell.swift in Sources */,
 				70B8882E2091B8550074812E /* ContactCell.swift in Sources */,
 				7070FB8D20FF4118000DC258 /* dc_sqlite3.c in Sources */,
 				7070FB8D20FF4118000DC258 /* dc_sqlite3.c in Sources */,
 				7A451D941FB1B1DB00177250 /* wrapper.c in Sources */,
 				7A451D941FB1B1DB00177250 /* wrapper.c in Sources */,
-				7092474120B3869500AF8799 /* ContactProfileViewController.swift in Sources */,
+				7092474120B3869500AF8799 /* ContactDetailViewController.swift in Sources */,
 				7070FB5E20FF345F000DC258 /* dc_token.c in Sources */,
 				7070FB5E20FF345F000DC258 /* dc_token.c in Sources */,
-				AE851AD0227DF50900ED86F0 /* ChatDetailViewController.swift in Sources */,
+				AE851AD0227DF50900ED86F0 /* SingleChatDetailViewController.swift in Sources */,
 				7070FB6C20FF345F000DC258 /* dc_keyring.c in Sources */,
 				7070FB6C20FF345F000DC258 /* dc_keyring.c in Sources */,
 				7A451DB01FB1F84900177250 /* AppCoordinator.swift in Sources */,
 				7A451DB01FB1F84900177250 /* AppCoordinator.swift in Sources */,
 				AE38B31822672DFC00EC37A1 /* ActionCell.swift in Sources */,
 				AE38B31822672DFC00EC37A1 /* ActionCell.swift in Sources */,

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

@@ -129,6 +129,7 @@ class AccountSetupController: UITableViewController {
 
 
   init() {
   init() {
     super.init(style: .grouped)
     super.init(style: .grouped)
+    hidesBottomBarWhenPushed = true
   }
   }
 
 
   required init?(coder _: NSCoder) {
   required init?(coder _: NSCoder) {
@@ -574,10 +575,10 @@ class AdvancedSectionHeader: UIView {
 
 
  // TODO: to add Eye-icon -> uncomment -> add to inputField.rightView
  // 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() {
  init() {
  super.init(style: .default, reuseIdentifier: nil)
  super.init(style: .default, reuseIdentifier: nil)

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

@@ -1,40 +0,0 @@
-//
-//  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.
-   }
-   */
-}

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

@@ -170,4 +170,23 @@ extension ChatListController: UITableViewDataSource, UITableViewDelegate {
       coordinator?.showChat(chatId: chatId)
       coordinator?.showChat(chatId: chatId)
     }
     }
   }
   }
+
+
+	func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
+		let section = indexPath.section
+		let row = indexPath.row
+		guard let chatList = chatList else {
+			return nil
+		}
+
+		// assigning swipe by delete to chats
+		let delete = UITableViewRowAction(style: .destructive, title: "Delete") { [unowned self] _, indexPath in
+			let chatId = chatList.getChatId(index: row)
+			dc_delete_chat(mailboxPointer, UInt32(chatId))
+			self.getChatList()
+
+		}
+		delete.backgroundColor = UIColor.red
+		return [delete]
+	}
 }
 }

+ 22 - 13
deltachat-ios/Controller/ChatViewController.swift

@@ -26,6 +26,10 @@ class ChatViewController: MessagesViewController {
   var msgChangedObserver: Any?
   var msgChangedObserver: Any?
   var incomingMsgObserver: Any?
   var incomingMsgObserver: Any?
 
 
+  lazy var navBarTap: UITapGestureRecognizer = {
+    UITapGestureRecognizer(target: self, action: #selector(chatProfilePressed))
+  }()
+
   var disableWriting = false
   var disableWriting = false
 
 
   var previewView: UIView?
   var previewView: UIView?
@@ -37,6 +41,7 @@ class ChatViewController: MessagesViewController {
     if let title = title {
     if let title = title {
       updateTitleView(title: title, subtitle: nil)
       updateTitleView(title: title, subtitle: nil)
     }
     }
+    hidesBottomBarWhenPushed = true
   }
   }
 
 
   required init?(coder _: NSCoder) {
   required init?(coder _: NSCoder) {
@@ -47,23 +52,10 @@ class ChatViewController: MessagesViewController {
     messagesCollectionView.register(CustomCell.self)
     messagesCollectionView.register(CustomCell.self)
     super.viewDidLoad()
     super.viewDidLoad()
     view.backgroundColor = DCColors.chatBackgroundColor
     view.backgroundColor = DCColors.chatBackgroundColor
-    let navBarTap = UITapGestureRecognizer(target: self, action: #selector(chatProfilePressed))
-    navigationController?.navigationBar.addGestureRecognizer(navBarTap)
     if !MRConfig.configured {
     if !MRConfig.configured {
       // TODO: display message about nothing being configured
       // TODO: display message about nothing being configured
       return
       return
     }
     }
-
-    let chat = MRChat(id: chatId)
-    updateTitleView(title: chat.name, subtitle: chat.subtitle)
-
-    if let image = chat.profileImage {
-      navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .done, target: self, action: #selector(chatProfilePressed))
-    } else {
-      let initialsLabel = InitialsLabel(name: chat.name, color: chat.color, size: 28)
-      navigationItem.rightBarButtonItem = UIBarButtonItem(customView: initialsLabel)
-    }
-
     configureMessageCollectionView()
     configureMessageCollectionView()
 
 
     if !disableWriting {
     if !disableWriting {
@@ -77,6 +69,20 @@ class ChatViewController: MessagesViewController {
 
 
   override func viewWillAppear(_ animated: Bool) {
   override func viewWillAppear(_ animated: Bool) {
     super.viewWillAppear(animated)
     super.viewWillAppear(animated)
+
+    // this will be removed in viewWillDisappear
+    navigationController?.navigationBar.addGestureRecognizer(navBarTap)
+
+    let chat = MRChat(id: chatId)
+    updateTitleView(title: chat.name, subtitle: chat.subtitle)
+
+    if let image = chat.profileImage {
+      navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style: .done, target: self, action: #selector(chatProfilePressed))
+    } else {
+      let initialsLabel = InitialsLabel(name: chat.name, color: chat.color, size: 28)
+      navigationItem.rightBarButtonItem = UIBarButtonItem(customView: initialsLabel)
+    }
+
     configureMessageMenu()
     configureMessageMenu()
 
 
     if #available(iOS 11.0, *) {
     if #available(iOS 11.0, *) {
@@ -121,6 +127,9 @@ class ChatViewController: MessagesViewController {
   override func viewWillDisappear(_ animated: Bool) {
   override func viewWillDisappear(_ animated: Bool) {
     super.viewWillDisappear(animated)
     super.viewWillDisappear(animated)
 
 
+    // the navigationController will be used when chatDetail is pushed, so we have to remove that gestureRecognizer
+    navigationController?.navigationBar.removeGestureRecognizer(navBarTap)
+
     let cnt = Int(dc_get_fresh_msg_cnt(mailboxPointer, UInt32(chatId)))
     let cnt = Int(dc_get_fresh_msg_cnt(mailboxPointer, UInt32(chatId)))
     logger.info("updating count for chat \(cnt)")
     logger.info("updating count for chat \(cnt)")
     UIApplication.shared.applicationIconBadgeNumber = cnt
     UIApplication.shared.applicationIconBadgeNumber = cnt

+ 16 - 14
deltachat-ios/Controller/ContactProfileViewController.swift → deltachat-ios/Controller/ContactDetailViewController.swift

@@ -8,7 +8,9 @@
 
 
 import UIKit
 import UIKit
 
 
-class ContactProfileViewController: UITableViewController {
+class ContactDetailViewController: UITableViewController {
+  weak var coordinator: ContactDetailCoordinator?
+
   let contactId: Int
   let contactId: Int
 
 
   var contact: MRContact {
   var contact: MRContact {
@@ -24,19 +26,16 @@ class ContactProfileViewController: UITableViewController {
     fatalError("init(coder:) has not been implemented")
     fatalError("init(coder:) has not been implemented")
   }
   }
 
 
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    title = "Info"
+  }
+
   override func viewWillAppear(_: Bool) {
   override func viewWillAppear(_: Bool) {
     navigationController?.navigationBar.prefersLargeTitles = false
     navigationController?.navigationBar.prefersLargeTitles = false
     tableView.reloadData()
     tableView.reloadData()
   }
   }
 
 
-  func displayNewChat(contactId: Int) {
-    let chatId = dc_create_chat_by_contact_id(mailboxPointer, UInt32(contactId))
-    let chatVC = ChatViewController(chatId: Int(chatId))
-
-    chatVC.hidesBottomBarWhenPushed = true
-    navigationController?.pushViewController(chatVC, animated: true)
-  }
-
   override func didReceiveMemoryWarning() {
   override func didReceiveMemoryWarning() {
     super.didReceiveMemoryWarning()
     super.didReceiveMemoryWarning()
     // Dispose of any resources that can be recreated.
     // Dispose of any resources that can be recreated.
@@ -82,16 +81,16 @@ class ContactProfileViewController: UITableViewController {
   override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
   override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
     let row = indexPath.row
     let row = indexPath.row
 
 
-    if row == 1 {
+    if row == 0 {
       let alert = UIAlertController(title: "Not implemented", message: "Settings are not implemented yet.", preferredStyle: .alert)
       let alert = UIAlertController(title: "Not implemented", message: "Settings are not implemented yet.", preferredStyle: .alert)
       alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
       alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
       present(alert, animated: true, completion: nil)
       present(alert, animated: true, completion: nil)
     }
     }
-    if row == 2 {
+    if row == 1 {
       let newContactController = NewContactController(contactIdForUpdate: contactId)
       let newContactController = NewContactController(contactIdForUpdate: contactId)
       navigationController?.pushViewController(newContactController, animated: true)
       navigationController?.pushViewController(newContactController, animated: true)
     }
     }
-    if row == 3 {
+    if row == 2 {
       displayNewChat(contactId: contactId)
       displayNewChat(contactId: contactId)
     }
     }
   }
   }
@@ -114,9 +113,7 @@ class ContactProfileViewController: UITableViewController {
       } else {
       } else {
         contactCell.setBackupImage(name: contact.name, color: contact.color)
         contactCell.setBackupImage(name: contact.name, color: contact.color)
       }
       }
-
       contactCell.setVerified(isVerified: contact.isVerified)
       contactCell.setVerified(isVerified: contact.isVerified)
-
       return contactCell
       return contactCell
     }
     }
 
 
@@ -125,4 +122,9 @@ class ContactProfileViewController: UITableViewController {
 
 
     return vw
     return vw
   }
   }
+
+  private func displayNewChat(contactId: Int) {
+    let chatId = dc_create_chat_by_contact_id(mailboxPointer, UInt32(contactId))
+    coordinator?.showChat(chatId: Int(chatId))
+  }
 }
 }

+ 1 - 3
deltachat-ios/Controller/ContactListController.swift

@@ -73,7 +73,6 @@ class ContactListController: UITableViewController {
       cell.nameLabel.text = contact.name
       cell.nameLabel.text = contact.name
       cell.emailLabel.text = contact.email
       cell.emailLabel.text = contact.email
 
 
-      // TODO: provider a nice selection
       cell.selectionStyle = .none
       cell.selectionStyle = .none
 
 
       if let img = contact.profileImage {
       if let img = contact.profileImage {
@@ -88,7 +87,6 @@ class ContactListController: UITableViewController {
 
 
   override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
   override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
     let contactId = contactIds[indexPath.row]
     let contactId = contactIds[indexPath.row]
-    let contactProfileController = ContactProfileViewController(contactId: contactId)
-    navigationController?.pushViewController(contactProfileController, animated: true)
+    coordinator?.showContactDetail(contactId: contactId)
   }
   }
 }
 }

+ 165 - 0
deltachat-ios/Controller/GroupMembersViewController.swift

@@ -0,0 +1,165 @@
+//
+//  GroupMemberViewController.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 08.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class NewGroupViewController: GroupMembersViewController {
+  weak var coordinator: NewGroupCoordinator?
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    title = "New Group"
+    navigationController?.navigationBar.prefersLargeTitles = false
+    let groupCreationNextButton = UIBarButtonItem(title: "Next", style: .done, target: self, action: #selector(nextButtonPressed))
+    navigationItem.rightBarButtonItem = groupCreationNextButton
+    contactIds = Utils.getContactIds()
+  }
+
+  override func didReceiveMemoryWarning() {
+    super.didReceiveMemoryWarning()
+  }
+
+  @objc func nextButtonPressed() {
+    coordinator?.showGroupNameController(contactIdsForGroup: selectedContactIds)
+  }
+}
+
+class AddGroupMembersViewController: GroupMembersViewController {
+  private var chatId: Int?
+
+  private lazy var resetButton: UIBarButtonItem = {
+    let button = UIBarButtonItem(title: "Reset", style: .plain, target: self, action: #selector(resetButtonPressed))
+    button.isEnabled = false
+    return button
+  }()
+
+  override var selectedContactIds: Set<Int> {
+    didSet {
+      resetButton.isEnabled = !selectedContactIds.isEmpty
+    }
+  }
+
+  private lazy var chat: MRChat? = {
+    if let chatId = chatId {
+      return MRChat(id: chatId)
+    }
+    return nil
+  }()
+
+  private lazy var chatMemberIds: [Int] = {
+    if let chat = chat {
+      return chat.contactIds
+    }
+    return []
+  }()
+
+  private lazy var memberCandidateIds: [Int] = {
+    var contactIds = Set(Utils.getContactIds()) // turn into set to speed up search
+    for member in chatMemberIds {
+      contactIds.remove(member)
+    }
+    return Array(contactIds)
+  }()
+
+  init(chatId: Int) {
+    super.init()
+    self.chatId = chatId
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    super.contactIds = memberCandidateIds
+    super.navigationItem.rightBarButtonItem = resetButton
+    title = "Add Group Members"
+    // Do any additional setup after loading the view.
+  }
+
+  override func viewWillDisappear(_: Bool) {
+    guard let chatId = chatId else {
+      return
+    }
+    for contactId in selectedContactIds {
+      dc_add_contact_to_chat(mailboxPointer, UInt32(chatId), UInt32(contactId))
+    }
+  }
+
+  @objc func resetButtonPressed() {
+    selectedContactIds = []
+    tableView.reloadData()
+  }
+}
+
+class GroupMembersViewController: UITableViewController {
+  let contactCellReuseIdentifier = "contactCell"
+
+  var contactIds: [Int] = [] {
+    didSet {
+      tableView.reloadData()
+    }
+  }
+
+  var selectedContactIds: Set<Int> = []
+
+  init() {
+    super.init(nibName: nil, bundle: nil)
+    hidesBottomBarWhenPushed = true
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    tableView.register(ContactCell.self, forCellReuseIdentifier: contactCellReuseIdentifier)
+  }
+
+  override func numberOfSections(in _: UITableView) -> Int {
+    return 1
+  }
+
+  override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
+    return contactIds.count
+  }
+
+  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+    guard let cell: ContactCell = tableView.dequeueReusableCell(withIdentifier: contactCellReuseIdentifier, for: indexPath) as? ContactCell else {
+      fatalError("shouldn't happen")
+    }
+
+    let row = indexPath.row
+    let contactRow = row
+
+    let contact = MRContact(id: contactIds[contactRow])
+    cell.nameLabel.text = contact.name
+    cell.emailLabel.text = contact.email
+    cell.initialsLabel.text = Utils.getInitials(inputName: contact.name)
+    cell.accessoryType = selectedContactIds.contains(contactIds[row]) ? .checkmark : .none
+    cell.setColor(contact.color)
+
+    return cell
+  }
+
+  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+    let row = indexPath.row
+    if let cell = tableView.cellForRow(at: indexPath) {
+      tableView.deselectRow(at: indexPath, animated: true)
+      let contactId = contactIds[row]
+      if selectedContactIds.contains(contactId) {
+        selectedContactIds.remove(contactId)
+        cell.accessoryType = .none
+      } else {
+        selectedContactIds.insert(contactId)
+        cell.accessoryType = .checkmark
+      }
+    }
+  }
+}

+ 26 - 0
deltachat-ios/Controller/MailboxViewController.swift

@@ -0,0 +1,26 @@
+//
+//  MailbovViewController.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 08.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class MailboxViewController: ChatViewController {
+  override init(chatId: Int, title: String? = nil) {
+    super.init(chatId: chatId, title: title)
+    hidesBottomBarWhenPushed = false
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+
+    // Do any additional setup after loading the view.
+  }
+}

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

@@ -59,6 +59,7 @@ class NewChatViewController: UITableViewController {
 
 
   init() {
   init() {
     super.init(style: .grouped)
     super.init(style: .grouped)
+    hidesBottomBarWhenPushed = true
   }
   }
 
 
   required init?(coder _: NSCoder) {
   required init?(coder _: NSCoder) {
@@ -79,7 +80,6 @@ class NewChatViewController: UITableViewController {
     super.viewWillAppear(animated)
     super.viewWillAppear(animated)
     deviceContactAccessGranted = CNContactStore.authorizationStatus(for: .contacts) == .authorized
     deviceContactAccessGranted = CNContactStore.authorizationStatus(for: .contacts) == .authorized
     contactIds = Utils.getContactIds()
     contactIds = Utils.getContactIds()
-
     // this will show the searchbar on launch -> will be set back to true on viewDidAppear
     // this will show the searchbar on launch -> will be set back to true on viewDidAppear
     if #available(iOS 11.0, *) {
     if #available(iOS 11.0, *) {
       navigationItem.hidesSearchBarWhenScrolling = false
       navigationItem.hidesSearchBarWhenScrolling = false
@@ -112,7 +112,6 @@ class NewChatViewController: UITableViewController {
   }
   }
 
 
   override func viewWillDisappear(_: Bool) {
   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) */
     title = "Chats" /* hack: when navigating to chatView (removing this viewController), there was a delayed backButton update (showing 'New Chat' for a moment) */
   }
   }
 
 

+ 5 - 6
deltachat-ios/Controller/NewContactController.swift

@@ -51,10 +51,6 @@ class NewContactController: UITableViewController {
     }
     }
   }
   }
 
 
-  override func viewWillAppear(_: Bool) {
-    navigationController?.setNavigationBarHidden(false, animated: false)
-  }
-
   // for creating a new contact
   // for creating a new contact
   init() {
   init() {
     cells = [emailCell, nameCell]
     cells = [emailCell, nameCell]
@@ -88,15 +84,18 @@ class NewContactController: UITableViewController {
     }
     }
   }
   }
 
 
+  override func viewWillAppear(_: Bool) {
+    navigationController?.setNavigationBarHidden(false, animated: false)
+    navigationController?.navigationBar.prefersLargeTitles = false
+  }
+
   @objc func emailTextChanged() {
   @objc func emailTextChanged() {
     let emailText = emailCell.textField.text ?? ""
     let emailText = emailCell.textField.text ?? ""
-
     model.email = emailText
     model.email = emailText
   }
   }
 
 
   @objc func nameTextChanged() {
   @objc func nameTextChanged() {
     let nameText = nameCell.textField.text ?? ""
     let nameText = nameCell.textField.text ?? ""
-
     model.name = nameText
     model.name = nameText
   }
   }
 
 

+ 0 - 80
deltachat-ios/Controller/NewGroupViewController.swift

@@ -1,80 +0,0 @@
-//
-//  NewGroupViewController.swift
-//  deltachat-ios
-//
-//  Created by Alla Reinsch on 17.07.18.
-//  Copyright © 2018 Jonas Reinsch. All rights reserved.
-//
-
-import UIKit
-
-class NewGroupViewController: UITableViewController {
-  weak var coordinator: NewGroupCoordinator?
-
-  let contactCellReuseIdentifier = "xyz"
-  var contactIds: [Int] = Utils.getContactIds()
-  var contactIdsForGroup: Set<Int> = [] {
-    didSet {
-      let c = contactIdsForGroup.count
-      navigationItem.prompt = "\(c) members and me"
-    }
-  }
-
-  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(nextButtonPressed))
-    navigationItem.rightBarButtonItem = groupCreationNextButton
-  }
-
-  override func didReceiveMemoryWarning() {
-    super.didReceiveMemoryWarning()
-  }
-
-  override func numberOfSections(in _: UITableView) -> Int {
-    return 1
-  }
-
-  override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
-    return contactIds.count
-  }
-
-  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-    guard let cell: ContactCell = tableView.dequeueReusableCell(withIdentifier: contactCellReuseIdentifier, for: indexPath) as? ContactCell else {
-      fatalError("shouldn't happen")
-    }
-
-    let row = indexPath.row
-    let contactRow = row
-
-    let contact = MRContact(id: contactIds[contactRow])
-    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(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-    let row = indexPath.row
-    if let cell = tableView.cellForRow(at: indexPath) {
-      tableView.deselectRow(at: indexPath, animated: true)
-      let contactId = contactIds[row]
-      if contactIdsForGroup.contains(contactId) {
-        contactIdsForGroup.remove(contactId)
-        cell.accessoryType = .none
-      } else {
-        contactIdsForGroup.insert(contactId)
-        cell.accessoryType = .checkmark
-      }
-    }
-  }
-
-  @objc func nextButtonPressed() {
-    coordinator?.showGroupNameController(contactIdsForGroup: contactIdsForGroup)
-  }
-}

+ 353 - 0
deltachat-ios/Controller/SingleChatDetailViewController.swift

@@ -0,0 +1,353 @@
+//
+//  ChatDetailViewController.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 04.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+class ChatDetailViewController: UIViewController {
+  weak var coordinator: ChatDetailCoordinator?
+
+  fileprivate var chat: MRChat
+
+  var chatDetailTable: UITableView = {
+    let table = UITableView(frame: .zero, style: .grouped)
+    table.bounces = false
+    table.register(UITableViewCell.self, forCellReuseIdentifier: "tableCell")
+    table.register(ActionCell.self, forCellReuseIdentifier: "actionCell")
+    table.register(ContactCell.self, forCellReuseIdentifier: "contactCell")
+
+    return table
+  }()
+
+  init(chatId: Int) {
+    chat = MRChat(id: chatId)
+    super.init(nibName: nil, bundle: nil)
+    setupSubviews()
+  }
+
+  override func viewWillAppear(_: Bool) {
+    chatDetailTable.reloadData() // to display updates
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  private func setupSubviews() {
+    view.addSubview(chatDetailTable)
+    chatDetailTable.translatesAutoresizingMaskIntoConstraints = false
+
+    chatDetailTable.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
+    chatDetailTable.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
+    chatDetailTable.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
+    chatDetailTable.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
+  }
+
+  @objc func editButtonPressed() {
+    // will be overwritten
+  }
+
+  func showNotificationSetup() {
+    let notificationSetupAlert = UIAlertController(title: "Notifications Setup is not implemented yet", message: "But you get an idea where this is going", preferredStyle: .actionSheet)
+    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
+    notificationSetupAlert.addAction(cancelAction)
+    present(notificationSetupAlert, animated: true, completion: nil)
+  }
+}
+
+class SingleChatDetailViewController: ChatDetailViewController {
+  var contact: MRContact? {
+    if let id = chat.contactIds.first {
+      return MRContact(id: id)
+    }
+    return nil
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    title = "Info"
+    chatDetailTable.delegate = self
+    chatDetailTable.dataSource = self
+  }
+
+  @objc override func editButtonPressed() {
+    if let id = chat.contactIds.first {
+      coordinator?.showSingleChatEdit(contactId: id)
+    }
+  }
+}
+
+extension SingleChatDetailViewController: UITableViewDelegate, UITableViewDataSource {
+  func numberOfSections(in _: UITableView) -> Int {
+    return 2
+  }
+
+  func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
+    return 1
+  }
+
+  func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+    if section == 0 {
+      guard let contact = contact else {
+        return nil
+      }
+      let bg = UIColor(red: 248 / 255, green: 248 / 255, blue: 255 / 255, alpha: 1.0)
+
+      let contactCell = ContactCell()
+      contactCell.backgroundColor = bg
+      contactCell.nameLabel.text = contact.name
+      contactCell.emailLabel.text = contact.email
+      contactCell.darkMode = false
+      contactCell.selectionStyle = .none
+      if let img = chat.profileImage {
+        contactCell.setImage(img)
+      } else {
+        contactCell.setBackupImage(name: contact.name, color: contact.color)
+      }
+      contactCell.setVerified(isVerified: chat.isVerified)
+      return contactCell
+    } else {
+      return nil
+    }
+  }
+
+  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+    let section = indexPath.section
+
+    if section == 0 {
+      let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
+      cell.textLabel?.text = "Notifications"
+      cell.selectionStyle = .none
+      return cell
+    } else if section == 1 {
+      let cell = tableView.dequeueReusableCell(withIdentifier: "actionCell", for: indexPath) as! ActionCell
+      if let contact = contact {
+        cell.actionTitle = contact.isBlocked ? "Unblock Contact" : "Block Contact"
+        cell.actionColor = contact.isBlocked ? SystemColor.blue.uiColor : UIColor.red // SystemColor.red.uiColor
+      }
+      return cell
+    }
+    return UITableViewCell(frame: .zero)
+  }
+
+  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+    let section = indexPath.section
+
+    if section == 0 {
+      showNotificationSetup()
+    } else if section == 1 {
+      if let contact = contact {
+        contact.isBlocked ? contact.unblock() : contact.block()
+        tableView.reloadData()
+      }
+    }
+  }
+}
+
+class GroupChatDetailViewController: ChatDetailViewController {
+  private var currentUser: MRContact? {
+    return groupMembers.filter { $0.email == MRConfig.addr }.first
+  }
+
+  private let editGroupCell = GroupLabelCell()
+
+  private var editingGroupName: Bool = false
+
+  private lazy var editBarButtonItem: UIBarButtonItem = {
+    UIBarButtonItem(title: editingGroupName ? "Done" : "Edit", style: .plain, target: self, action: #selector(editButtonPressed))
+  }()
+
+  private var groupMembers: [MRContact] = []
+
+  private let staticCellCountMemberSection = 1 //
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+    title = "Group Info"
+    chatDetailTable.delegate = self
+    chatDetailTable.dataSource = self
+    navigationItem.rightBarButtonItem = editBarButtonItem
+  }
+
+  override func viewWillAppear(_: Bool) {
+    updateGroupMembers()
+    editBarButtonItem.isEnabled = currentUser != nil
+  }
+
+  private func updateGroupMembers() {
+    let ids = chat.contactIds
+    groupMembers = ids.map { MRContact(id: $0) }
+    chatDetailTable.reloadData()
+  }
+
+  @objc override func editButtonPressed() {
+    if editingGroupName {
+      let newName = editGroupCell.getGroupName()
+      dc_set_chat_name(mailboxPointer, UInt32(chat.id), newName)
+      chat = MRChat(id: chat.id) // reload
+    }
+
+    editingGroupName = !editingGroupName
+    editBarButtonItem.title = editingGroupName ? "Save" : "Edit"
+    chatDetailTable.reloadData()
+  }
+
+  private func leaveGroup() {
+    if let userId = currentUser?.id {
+      dc_remove_contact_from_chat(mailboxPointer, UInt32(chat.id), UInt32(userId))
+      editBarButtonItem.isEnabled = false
+      updateGroupMembers()
+    }
+  }
+}
+
+extension GroupChatDetailViewController: UITableViewDelegate, UITableViewDataSource {
+  func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
+    if section == 1 {
+      return "Members:"
+    }
+    return nil
+  }
+
+  func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+    if section == 0 {
+      let bg = UIColor(red: 248 / 255, green: 248 / 255, blue: 255 / 255, alpha: 1.0)
+
+      if editingGroupName {
+        editGroupCell.groupBadge.setColor(chat.color)
+        editGroupCell.backgroundColor = bg
+        editGroupCell.inputField.text = chat.name
+        editGroupCell.groupBadge.setText(chat.name)
+        return editGroupCell
+      } else {
+        let contactCell = ContactCell()
+        contactCell.backgroundColor = bg
+        contactCell.nameLabel.text = chat.name
+        contactCell.emailLabel.text = chat.subtitle
+        contactCell.darkMode = false
+        contactCell.selectionStyle = .none
+        if let img = chat.profileImage {
+          contactCell.setImage(img)
+        } else {
+          contactCell.setBackupImage(name: chat.name, color: chat.color)
+        }
+        contactCell.setVerified(isVerified: chat.isVerified)
+        return contactCell
+      }
+    } else {
+      return nil
+    }
+  }
+
+  func numberOfSections(in _: UITableView) -> Int {
+    /*
+     section 0: config
+     section 1: members
+     section 2: leave group (optional - if user already left group this option will be hidden)
+     */
+
+    if currentUser == nil {
+      return 2
+    }
+    return 3
+  }
+
+  func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
+    if section == 0 {
+      return 1
+    } else if section == 1 {
+      return groupMembers.count + staticCellCountMemberSection // first cell is addGroupMemberCell
+    } else if section == 2 {
+      return 1
+    } else {
+      return 0
+    }
+  }
+
+  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+    let section = indexPath.section
+    let row = indexPath.row
+
+    if section == 0 {
+      let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
+      cell.textLabel?.text = "Notifications"
+      cell.selectionStyle = .none
+      return cell
+    } else if section == 1 {
+      if row == 0 {
+        let cell = tableView.dequeueReusableCell(withIdentifier: "actionCell", for: indexPath) as! ActionCell
+        cell.actionTitle = "Add Members"
+        return cell
+      } else {
+        let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactCell
+        let contact = groupMembers[row - staticCellCountMemberSection]
+        cell.nameLabel.text = contact.name
+        cell.emailLabel.text = contact.email
+        cell.initialsLabel.text = Utils.getInitials(inputName: contact.name)
+        cell.setColor(contact.color)
+        return cell
+      }
+    } else if section == 2 {
+      let cell = tableView.dequeueReusableCell(withIdentifier: "actionCell", for: indexPath) as! ActionCell
+      cell.actionTitle = "Leave Group"
+      cell.actionColor = UIColor.red
+      return cell
+    }
+
+    return UITableViewCell(frame: .zero)
+  }
+
+  func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
+    let section = indexPath.section
+    let row = indexPath.row
+    if section == 0 {
+      showNotificationSetup()
+    } else if section == 1 {
+      if row == 0 {
+        coordinator?.showAddGroupMember(chatId: chat.id)
+      }
+      // ignore for now - in Telegram tapping a contactCell leads into ContactDetail
+    } else if section == 2 {
+      leaveGroup()
+    }
+  }
+
+  func tableView(_: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
+    let section = indexPath.section
+    let row = indexPath.row
+
+    if let currentUser = currentUser {
+      if section == 1, row > 0, groupMembers[row - staticCellCountMemberSection].id != currentUser.id {
+        return true
+      }
+    }
+    return false
+  }
+
+  func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
+    let section = indexPath.section
+    let row = indexPath.row
+
+    // assigning swipe by delete to members (except for current user)
+    if section == 1, row >= staticCellCountMemberSection, groupMembers[row - staticCellCountMemberSection].id != currentUser?.id {
+      let delete = UITableViewRowAction(style: .destructive, title: "Delete") { [unowned self] _, indexPath in
+
+        let memberId = self.groupMembers[row - self.staticCellCountMemberSection].id
+        let success = dc_remove_contact_from_chat(mailboxPointer, UInt32(self.chat.id), UInt32(memberId))
+        if success == 1 {
+          self.groupMembers.remove(at: row - self.staticCellCountMemberSection)
+          tableView.deleteRows(at: [indexPath], with: .fade)
+          tableView.reloadData()
+        }
+      }
+      delete.backgroundColor = UIColor.red
+      return [delete]
+    } else {
+      return nil
+    }
+  }
+}

+ 48 - 6
deltachat-ios/Coordinator/AppCoordinator.swift

@@ -41,7 +41,7 @@ class AppCoordinator: NSObject, Coordinator, UITabBarControllerDelegate {
   }()
   }()
 
 
   private lazy var mailboxController: UIViewController = {
   private lazy var mailboxController: UIViewController = {
-    let controller = ChatViewController(chatId: Int(DC_CHAT_ID_DEADDROP), title: "Mailbox")
+    let controller = MailboxViewController(chatId: Int(DC_CHAT_ID_DEADDROP), title: "Mailbox")
     controller.disableWriting = true
     controller.disableWriting = true
     let nav = NavigationController(rootViewController: controller)
     let nav = NavigationController(rootViewController: controller)
     let settingsImage = UIImage(named: "message")
     let settingsImage = UIImage(named: "message")
@@ -110,9 +110,19 @@ class AppCoordinator: NSObject, Coordinator, UITabBarControllerDelegate {
 class ContactListCoordinator: Coordinator {
 class ContactListCoordinator: Coordinator {
   let navigationController: UINavigationController
   let navigationController: UINavigationController
 
 
+  var childCoordinators: [Coordinator] = []
+
   init(navigationController: UINavigationController) {
   init(navigationController: UINavigationController) {
     self.navigationController = navigationController
     self.navigationController = navigationController
   }
   }
+
+  func showContactDetail(contactId: Int) {
+    let contactDetailController = ContactDetailViewController(contactId: contactId)
+    let coordinator = ContactDetailCoordinator(navigationController: navigationController)
+    childCoordinators.append(coordinator)
+    contactDetailController.coordinator = coordinator
+    navigationController.pushViewController(contactDetailController, animated: true)
+  }
 }
 }
 
 
 // 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
 // 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
@@ -144,7 +154,6 @@ class ChatListCoordinator: Coordinator {
     let coordinator = NewChatCoordinator(navigationController: navigationController)
     let coordinator = NewChatCoordinator(navigationController: navigationController)
     childCoordinators.append(coordinator)
     childCoordinators.append(coordinator)
     newChatVC.coordinator = coordinator
     newChatVC.coordinator = coordinator
-    newChatVC.hidesBottomBarWhenPushed = true
     navigationController.pushViewController(newChatVC, animated: true)
     navigationController.pushViewController(newChatVC, animated: true)
   }
   }
 
 
@@ -153,7 +162,6 @@ class ChatListCoordinator: Coordinator {
     let coordinator = ChatViewCoordinator(navigationController: navigationController)
     let coordinator = ChatViewCoordinator(navigationController: navigationController)
     childCoordinators.append(coordinator)
     childCoordinators.append(coordinator)
     chatVC.coordinator = coordinator
     chatVC.coordinator = coordinator
-    chatVC.hidesBottomBarWhenPushed = true
     navigationController.pushViewController(chatVC, animated: true)
     navigationController.pushViewController(chatVC, animated: true)
   }
   }
 }
 }
@@ -167,8 +175,6 @@ class SettingsCoordinator: Coordinator {
 
 
   func showAccountSetupController() {
   func showAccountSetupController() {
     let accountSetupVC = AccountSetupController()
     let accountSetupVC = AccountSetupController()
-    accountSetupVC.hidesBottomBarWhenPushed = true
-
     navigationController.pushViewController(accountSetupVC, animated: true)
     navigationController.pushViewController(accountSetupVC, animated: true)
   }
   }
 }
 }
@@ -224,6 +230,16 @@ class ChatDetailCoordinator: Coordinator {
   init(navigationController: UINavigationController) {
   init(navigationController: UINavigationController) {
     self.navigationController = navigationController
     self.navigationController = navigationController
   }
   }
+
+  func showSingleChatEdit(contactId: Int) {
+    let newContactController = NewContactController(contactIdForUpdate: contactId)
+    navigationController.pushViewController(newContactController, animated: true)
+  }
+
+  func showAddGroupMember(chatId: Int) {
+    let groupMemberViewController = AddGroupMembersViewController(chatId: chatId)
+    navigationController.pushViewController(groupMemberViewController, animated: true)
+  }
 }
 }
 
 
 class ChatViewCoordinator: Coordinator {
 class ChatViewCoordinator: Coordinator {
@@ -236,7 +252,14 @@ class ChatViewCoordinator: Coordinator {
   }
   }
 
 
   func showChatDetail(chatId: Int) {
   func showChatDetail(chatId: Int) {
-    let chatDetailViewController = ChatDetailViewController(chatId: chatId)
+    let chat = MRChat(id: chatId)
+    let chatDetailViewController: ChatDetailViewController
+    switch chat.chatType {
+    case .SINGLE:
+      chatDetailViewController = SingleChatDetailViewController(chatId: chatId) // inherits from ChatDetailViewController
+    case .GROUP, .VERYFIEDGROUP:
+      chatDetailViewController = GroupChatDetailViewController(chatId: chatId) // inherits from ChatDetailViewController
+    }
     let coordinator = ChatDetailCoordinator(navigationController: navigationController)
     let coordinator = ChatDetailCoordinator(navigationController: navigationController)
     childCoordinators.append(coordinator)
     childCoordinators.append(coordinator)
     chatDetailViewController.coordinator = coordinator
     chatDetailViewController.coordinator = coordinator
@@ -280,3 +303,22 @@ class GroupNameCoordinator: Coordinator {
     navigationController.pushViewController(chatViewController, animated: true)
     navigationController.pushViewController(chatViewController, animated: true)
   }
   }
 }
 }
+
+class ContactDetailCoordinator: Coordinator {
+  let navigationController: UINavigationController
+
+  private var childCoordinators: [Coordinator] = []
+
+  init(navigationController: UINavigationController) {
+    self.navigationController = navigationController
+  }
+
+  func showChat(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)
+  }
+}

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

@@ -340,6 +340,12 @@ class MRMessage: MessageType {
   }
   }
 }
 }
 
 
+enum ChatType: Int {
+  case SINGLE = 100
+  case GROUP = 120
+  case VERYFIEDGROUP = 130
+}
+
 class MRChat {
 class MRChat {
   var chatPointer: UnsafeMutablePointer<dc_chat_t>
   var chatPointer: UnsafeMutablePointer<dc_chat_t>
 
 
@@ -358,6 +364,10 @@ class MRChat {
     return Int(chatPointer.pointee.type)
     return Int(chatPointer.pointee.type)
   }
   }
 
 
+  var chatType: ChatType {
+    return ChatType(rawValue: type) ?? ChatType.GROUP // group as fallback - shouldn't get here
+  }
+
   var color: UIColor {
   var color: UIColor {
     return UIColor(netHex: Int(dc_chat_get_color(chatPointer)))
     return UIColor(netHex: Int(dc_chat_get_color(chatPointer)))
   }
   }
@@ -366,6 +376,10 @@ class MRChat {
     return dc_chat_is_verified(chatPointer) > 0
     return dc_chat_is_verified(chatPointer) > 0
   }
   }
 
 
+  var contactIds: [Int] {
+    return Utils.copyAndFreeArray(inputArray: dc_get_chat_contacts(mailboxPointer, UInt32(id)))
+  }
+
   lazy var profileImage: UIImage? = { [unowned self] in
   lazy var profileImage: UIImage? = { [unowned self] in
     let file = dc_chat_get_profile_image(chatPointer)
     let file = dc_chat_get_profile_image(chatPointer)
     if let cFile = file {
     if let cFile = file {

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

@@ -20,7 +20,7 @@ struct Constants {
     static let deltachatImapEmailKey = "__DELTACHAT_IMAP_EMAIL_KEY__"
     static let deltachatImapEmailKey = "__DELTACHAT_IMAP_EMAIL_KEY__"
     static let deltachatImapPasswordKey = "__DELTACHAT_IMAP_PASSWORD_KEY__"
     static let deltachatImapPasswordKey = "__DELTACHAT_IMAP_PASSWORD_KEY__"
   }
   }
-	
+
   static let defaultShadow = UIImage(color: UIColor(hexString: "ff2b82"), size: CGSize(width: 1, height: 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))
   static let onlineShadow = UIImage(color: UIColor(hexString: "3ed67e"), size: CGSize(width: 1, height: 1))
 
 

+ 10 - 7
deltachat-ios/View/ActionCell.swift

@@ -17,6 +17,12 @@ class ActionCell: UITableViewCell {
     }
     }
   }
   }
 
 
+  var actionColor: UIColor? {
+    didSet {
+      actionLabel.textColor = actionColor ?? UIColor.systemBlue
+    }
+  }
+
   private lazy var actionLabel: UILabel = {
   private lazy var actionLabel: UILabel = {
     let label = UILabel()
     let label = UILabel()
     label.text = actionTitle
     label.text = actionTitle
@@ -25,15 +31,16 @@ class ActionCell: UITableViewCell {
   }()
   }()
 
 
   // use this constructor if cell won't be reused
   // use this constructor if cell won't be reused
-  init(title: String) {
+  convenience init(title: String) {
+    self.init(style: .default, reuseIdentifier: nil)
     actionTitle = title
     actionTitle = title
-    super.init(style: .default, reuseIdentifier: nil)
-    setupSubviews()
+    selectionStyle = .none
   }
   }
 
 
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
     super.init(style: style, reuseIdentifier: reuseIdentifier)
     super.init(style: style, reuseIdentifier: reuseIdentifier)
     setupSubviews()
     setupSubviews()
+    selectionStyle = .none
   }
   }
 
 
   required init?(coder _: NSCoder) {
   required init?(coder _: NSCoder) {
@@ -45,10 +52,6 @@ class ActionCell: UITableViewCell {
     // Initialization code
     // Initialization code
   }
   }
 
 
-  override func setSelected(_: Bool, animated _: Bool) {
-    // no selection style ...
-  }
-
   private func setupSubviews() {
   private func setupSubviews() {
     contentView.addSubview(actionLabel)
     contentView.addSubview(actionLabel)
     actionLabel.translatesAutoresizingMaskIntoConstraints = false
     actionLabel.translatesAutoresizingMaskIntoConstraints = false

+ 4 - 1
deltachat-ios/View/ContactCell.swift

@@ -8,6 +8,8 @@
 
 
 import UIKit
 import UIKit
 
 
+// TODO: integrate InitialsBadge in here
+
 class ContactCell: UITableViewCell {
 class ContactCell: UITableViewCell {
   private let initialsLabelSize: CGFloat = 54
   private let initialsLabelSize: CGFloat = 54
   private let imgSize: CGFloat = 25
   private let imgSize: CGFloat = 25
@@ -57,11 +59,12 @@ class ContactCell: UITableViewCell {
 
 
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
     super.init(style: style, reuseIdentifier: reuseIdentifier)
     super.init(style: style, reuseIdentifier: reuseIdentifier)
+    selectionStyle = .none
     setupSubviews()
     setupSubviews()
   }
   }
 
 
   private func setupSubviews() {
   private func setupSubviews() {
-    let margin: CGFloat = 15
+    let margin: CGFloat = 10
 
 
     initialsLabel.translatesAutoresizingMaskIntoConstraints = false
     initialsLabel.translatesAutoresizingMaskIntoConstraints = false
     avatar.translatesAutoresizingMaskIntoConstraints = false
     avatar.translatesAutoresizingMaskIntoConstraints = false

+ 12 - 5
deltachat-ios/View/GroupNameCell.swift

@@ -9,12 +9,15 @@
 import UIKit
 import UIKit
 
 
 class GroupLabelCell: UITableViewCell {
 class GroupLabelCell: UITableViewCell {
-  private let groupBadgeSize: CGFloat = 60
+  var groupBadgeSize: CGFloat = 54
+
   var groupNameUpdated: ((String) -> Void)? // use this callback to update editButton in navigationController
   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)
+  lazy var groupBadge: InitialsBadge = {
+    let badge = InitialsBadge(frame: .zero)
+    badge.layer.cornerRadius = groupBadgeSize / 2
+    badge.clipsToBounds = true
+    badge.setColor(UIColor.lightGray)
     return badge
     return badge
   }()
   }()
 
 
@@ -58,7 +61,11 @@ class GroupLabelCell: UITableViewCell {
 
 
   @objc func nameFieldChanged() {
   @objc func nameFieldChanged() {
     let groupName = inputField.text ?? ""
     let groupName = inputField.text ?? ""
-    groupBadge.set(name: groupName)
+    groupBadge.setText(groupName)
     groupNameUpdated?(groupName)
     groupNameUpdated?(groupName)
   }
   }
+
+  func getGroupName() -> String {
+    return inputField.text ?? ""
+  }
 }
 }

+ 52 - 0
deltachat-ios/View/InitialsBadge.swift

@@ -0,0 +1,52 @@
+//
+//  IntitialsBadge.swift
+//  deltachat-ios
+//
+//  Created by Bastian van de Wetering on 07.05.19.
+//  Copyright © 2019 Jonas Reinsch. All rights reserved.
+//
+
+import UIKit
+
+// shall be used for contactCell/ groups
+
+class InitialsBadge: UIView {
+  private lazy var label: UILabel = {
+    let label = UILabel()
+    label.textAlignment = NSTextAlignment.center
+    label.textColor = UIColor.white
+    label.font = UIFont.systemFont(ofSize: 22)
+    // label.adjustsFontSizeToFitWidth = true
+    return label
+  }()
+
+  override init(frame: CGRect) {
+    super.init(frame: frame)
+    setupSubviews()
+
+    layer.cornerRadius = frame.width / 2
+    clipsToBounds = true
+  }
+
+  required init?(coder _: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  private func setupSubviews() {
+    addSubview(label)
+    label.translatesAutoresizingMaskIntoConstraints = false
+    label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 2).isActive = true
+    label.topAnchor.constraint(equalTo: topAnchor, constant: 2).isActive = true
+    label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -2).isActive = true
+    label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -2).isActive = true
+  }
+
+  func setColor(_ color: UIColor) {
+    backgroundColor = color
+  }
+
+  func setText(_ text: String) {
+    let initials = Utils.getInitials(inputName: text)
+    label.text = initials
+  }
+}