Răsfoiți Sursa

remove MessageKit and remove or comment out all remaining references in code

cyberta 4 ani în urmă
părinte
comite
79db9fc84e
84 a modificat fișierele cu 33 adăugiri și 9906 ștergeri
  1. 8 370
      deltachat-ios.xcodeproj/project.pbxproj
  2. 2 2
      deltachat-ios/Chat/Views/Cells/NewImageTextCell.swift
  3. 1 0
      deltachat-ios/Chat/Views/DetectorType.swift
  4. 4 3
      deltachat-ios/Chat/Views/MessageLabelDelegate.swift
  5. 2 2
      deltachat-ios/Chat/Views/NewMessageLabel.swift
  6. 0 1527
      deltachat-ios/Controller/ChatViewController.swift
  7. 1 1
      deltachat-ios/Controller/ContactDetailViewController.swift
  8. 5 4
      deltachat-ios/Controller/MailboxViewController.swift
  9. 1 1
      deltachat-ios/Controller/NewChatViewController.swift
  10. 1 1
      deltachat-ios/Controller/NewContactController.swift
  11. 1 1
      deltachat-ios/Controller/NewGroupController.swift
  12. 3 3
      deltachat-ios/DC/DcMsg+Extension.swift
  13. 0 43
      deltachat-ios/Extensions/Bundle+Extensions.swift
  14. 0 238
      deltachat-ios/MessageKit/Controllers/BasicAudioController.swift
  15. 0 147
      deltachat-ios/MessageKit/Controllers/MessagesViewController+Keyboard.swift
  16. 0 109
      deltachat-ios/MessageKit/Controllers/MessagesViewController+Menu.swift
  17. 0 448
      deltachat-ios/MessageKit/Controllers/MessagesViewController.swift
  18. 0 90
      deltachat-ios/MessageKit/Layout/AudioMessageSizeCalculator.swift
  19. 0 50
      deltachat-ios/MessageKit/Layout/CellSizeCalculator.swift
  20. 0 74
      deltachat-ios/MessageKit/Layout/ContactMessageSizeCalculator.swift
  21. 0 73
      deltachat-ios/MessageKit/Layout/FileMessageSizeCalculator.swift
  22. 0 44
      deltachat-ios/MessageKit/Layout/LocationMessageSizeCalculator.swift
  23. 0 62
      deltachat-ios/MessageKit/Layout/MediaMessageSizeCalculator.swift
  24. 0 292
      deltachat-ios/MessageKit/Layout/MessageSizeCalculator.swift
  25. 0 342
      deltachat-ios/MessageKit/Layout/MessagesCollectionViewFlowLayout.swift
  26. 0 109
      deltachat-ios/MessageKit/Layout/MessagesCollectionViewLayoutAttributes.swift
  27. 0 131
      deltachat-ios/MessageKit/Layout/TextMediaMessageSizeCalculator.swift
  28. 0 97
      deltachat-ios/MessageKit/Layout/TextMessageSizeCalculator.swift
  29. 0 43
      deltachat-ios/MessageKit/Layout/TypingIndicatorCellSizeCalculator.swift
  30. 0 48
      deltachat-ios/MessageKit/Models/AccessoryPosition.swift
  31. 0 48
      deltachat-ios/MessageKit/Models/Avatar.swift
  32. 0 98
      deltachat-ios/MessageKit/Models/AvatarPosition.swift
  33. 0 56
      deltachat-ios/MessageKit/Models/HorizontalEdgeInsets.swift
  34. 0 47
      deltachat-ios/MessageKit/Models/LabelAlignment.swift
  35. 0 64
      deltachat-ios/MessageKit/Models/LocationMessageSnapshotOptions.swift
  36. 0 86
      deltachat-ios/MessageKit/Models/MessageKind.swift
  37. 0 66
      deltachat-ios/MessageKit/Models/MessageKitDateFormatter.swift
  38. 0 38
      deltachat-ios/MessageKit/Models/MessageKitError.swift
  39. 0 151
      deltachat-ios/MessageKit/Models/MessageStyle.swift
  40. 0 81
      deltachat-ios/MessageKit/Models/NSConstraintLayoutSet.swift
  41. 0 57
      deltachat-ios/MessageKit/Models/Sender.swift
  42. 0 42
      deltachat-ios/MessageKit/Protocols/AudioItem.swift
  43. 0 41
      deltachat-ios/MessageKit/Protocols/ContactItem.swift
  44. 0 37
      deltachat-ios/MessageKit/Protocols/LocationItem.swift
  45. 0 50
      deltachat-ios/MessageKit/Protocols/MediaItem.swift
  46. 0 180
      deltachat-ios/MessageKit/Protocols/MessageCellDelegate.swift
  47. 0 43
      deltachat-ios/MessageKit/Protocols/MessageType.swift
  48. 0 159
      deltachat-ios/MessageKit/Protocols/MessagesDataSource.swift
  49. 0 315
      deltachat-ios/MessageKit/Protocols/MessagesDisplayDelegate.swift
  50. 0 164
      deltachat-ios/MessageKit/Protocols/MessagesLayoutDelegate.swift
  51. 0 38
      deltachat-ios/MessageKit/Protocols/SenderType.swift
  52. 0 55
      deltachat-ios/MessageKit/Supporting/MessageInputBar.swift
  53. 0 73
      deltachat-ios/MessageKit/Supporting/MessageKit+Availability.swift
  54. 0 29
      deltachat-ios/MessageKit/Supporting/MessageKit.h
  55. 0 111
      deltachat-ios/MessageKit/Views/AudioPlayerView.swift
  56. 0 207
      deltachat-ios/MessageKit/Views/AvatarView.swift
  57. 0 49
      deltachat-ios/MessageKit/Views/BubbleCircle.swift
  58. 0 142
      deltachat-ios/MessageKit/Views/Cells/AnimatedImageMessageCell.swift
  59. 0 163
      deltachat-ios/MessageKit/Views/Cells/AudioMessageCell.swift
  60. 0 142
      deltachat-ios/MessageKit/Views/Cells/ContactMessageCell.swift
  61. 0 141
      deltachat-ios/MessageKit/Views/Cells/FileMessageCell.swift
  62. 0 53
      deltachat-ios/MessageKit/Views/Cells/InfoMessageCell.swift
  63. 0 111
      deltachat-ios/MessageKit/Views/Cells/LocationMessageCell.swift
  64. 0 102
      deltachat-ios/MessageKit/Views/Cells/MediaMessageCell.swift
  65. 0 45
      deltachat-ios/MessageKit/Views/Cells/MessageCollectionViewCell.swift
  66. 0 352
      deltachat-ios/MessageKit/Views/Cells/MessageContentCell.swift
  67. 0 193
      deltachat-ios/MessageKit/Views/Cells/TextMediaMessageCell.swift
  68. 0 101
      deltachat-ios/MessageKit/Views/Cells/TextMessageCell.swift
  69. 0 66
      deltachat-ios/MessageKit/Views/Cells/TypingIndicatorCell.swift
  70. 0 89
      deltachat-ios/MessageKit/Views/FileView.swift
  71. 0 40
      deltachat-ios/MessageKit/Views/HeadersFooters/MessageReusableView.swift
  72. 0 38
      deltachat-ios/MessageKit/Views/InsetLabel.swift
  73. 0 88
      deltachat-ios/MessageKit/Views/MessageContainerView.swift
  74. 0 545
      deltachat-ios/MessageKit/Views/MessageLabel.swift
  75. 0 202
      deltachat-ios/MessageKit/Views/MessagesCollectionView.swift
  76. 0 122
      deltachat-ios/MessageKit/Views/PlayButtonView.swift
  77. 0 155
      deltachat-ios/MessageKit/Views/TypingBubble.swift
  78. 0 165
      deltachat-ios/MessageKit/Views/TypingIndicator.swift
  79. 0 19
      deltachat-ios/Model/Audio.swift
  80. 0 14
      deltachat-ios/Model/Location.swift
  81. 0 29
      deltachat-ios/Model/Media.swift
  82. 0 45
      deltachat-ios/Model/Message.swift
  83. 2 2
      deltachat-ios/View/Cell/FileTableViewCell.swift
  84. 2 2
      deltachat-ios/View/Cell/GalleryCell.swift

+ 8 - 370
deltachat-ios.xcodeproj/project.pbxproj

@@ -10,8 +10,6 @@
 		3008CB7224F93EB900E6A617 /* NewAudioMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3008CB7124F93EB900E6A617 /* NewAudioMessageCell.swift */; };
 		3008CB7424F9436C00E6A617 /* NewAudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3008CB7324F9436C00E6A617 /* NewAudioPlayerView.swift */; };
 		3008CB7624F95B6D00E6A617 /* NewAudioController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3008CB7524F95B6D00E6A617 /* NewAudioController.swift */; };
-		300C509D234B551900F8AE22 /* TextMediaMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300C509C234B551900F8AE22 /* TextMediaMessageCell.swift */; };
-		300C50A1234BDAB800F8AE22 /* TextMediaMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300C50A0234BDAB800F8AE22 /* TextMediaMessageSizeCalculator.swift */; };
 		30149D9322F21129003C12B5 /* QrViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30149D9222F21129003C12B5 /* QrViewController.swift */; };
 		3015634423A003BA00E9DEF4 /* AudioRecorderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3015634323A003BA00E9DEF4 /* AudioRecorderController.swift */; };
 		3022E6BE22E8768800763272 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3022E6C022E8768800763272 /* InfoPlist.strings */; };
@@ -21,12 +19,11 @@
 		302B84C72396770B001C261F /* RelayHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B84C42396627F001C261F /* RelayHelper.swift */; };
 		302B84CE2397F6CD001C261F /* URL+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B84CD2397F6CD001C261F /* URL+Extension.swift */; };
 		302E1BB4252B5AB4008F4264 /* NewPlayButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E1BB3252B5AB4008F4264 /* NewPlayButtonView.swift */; };
-		3040F45E234DFBC000FA34D5 /* Audio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3040F45D234DFBC000FA34D5 /* Audio.swift */; };
-		3040F460234F419400FA34D5 /* BasicAudioController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3040F45F234F419300FA34D5 /* BasicAudioController.swift */; };
-		3040F462234F550300FA34D5 /* AudioPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3040F461234F550300FA34D5 /* AudioPlayerView.swift */; };
 		304219D3243F588500516852 /* DcCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 304219D1243F588500516852 /* DcCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		304219D92440734A00516852 /* DcMsg+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304219D82440734A00516852 /* DcMsg+Extension.swift */; };
 		304F5E44244F571C00462538 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A9FB14A1FB061E2001FEA36 /* Assets.xcassets */; };
+		3052C60A253F082E007D13EA /* MessageLabelDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3052C609253F082E007D13EA /* MessageLabelDelegate.swift */; };
+		3052C60E253F088E007D13EA /* DetectorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3052C60D253F088E007D13EA /* DetectorType.swift */; };
 		3057027F24C5B2F800D84EFC /* ChatListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3057027E24C5B2F800D84EFC /* ChatListViewModel.swift */; };
 		3057028724C5C88300D84EFC /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 306011B422E5E7FB00C1CE6F /* Localizable.stringsdict */; };
 		3057028C24C5E7B600D84EFC /* ContactCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE77838E23E4276D0093EABD /* ContactCellViewModel.swift */; };
@@ -39,65 +36,7 @@
 		305961CD2346125100C80F33 /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961832346125000C80F33 /* UIEdgeInsets+Extensions.swift */; };
 		305961CF2346125100C80F33 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961852346125000C80F33 /* UIColor+Extensions.swift */; };
 		305961D02346125100C80F33 /* NSAttributedString+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961862346125000C80F33 /* NSAttributedString+Extensions.swift */; };
-		305961D12346125100C80F33 /* Bundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961872346125000C80F33 /* Bundle+Extensions.swift */; };
 		305961D22346125100C80F33 /* CGRect+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961882346125000C80F33 /* CGRect+Extensions.swift */; };
-		305961D32346125100C80F33 /* MessagesViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059618A2346125000C80F33 /* MessagesViewController+Keyboard.swift */; };
-		305961D42346125100C80F33 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059618B2346125000C80F33 /* MessagesViewController.swift */; };
-		305961D52346125100C80F33 /* MessagesViewController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059618C2346125000C80F33 /* MessagesViewController+Menu.swift */; };
-		305961D62346125100C80F33 /* MessageInputBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059618E2346125000C80F33 /* MessageInputBar.swift */; };
-		305961D72346125100C80F33 /* MessageKit+Availability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961902346125000C80F33 /* MessageKit+Availability.swift */; };
-		305961D92346125100C80F33 /* ContactItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961932346125000C80F33 /* ContactItem.swift */; };
-		305961DA2346125100C80F33 /* MediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961942346125000C80F33 /* MediaItem.swift */; };
-		305961DB2346125100C80F33 /* AudioItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961952346125000C80F33 /* AudioItem.swift */; };
-		305961DC2346125100C80F33 /* MessagesLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961962346125000C80F33 /* MessagesLayoutDelegate.swift */; };
-		305961DD2346125100C80F33 /* SenderType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961972346125000C80F33 /* SenderType.swift */; };
-		305961DE2346125100C80F33 /* MessageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961982346125000C80F33 /* MessageType.swift */; };
-		305961DF2346125100C80F33 /* MessageCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961992346125000C80F33 /* MessageCellDelegate.swift */; };
-		305961E02346125100C80F33 /* MessageLabelDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059619A2346125000C80F33 /* MessageLabelDelegate.swift */; };
-		305961E12346125100C80F33 /* LocationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059619B2346125000C80F33 /* LocationItem.swift */; };
-		305961E22346125100C80F33 /* MessagesDisplayDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059619C2346125000C80F33 /* MessagesDisplayDelegate.swift */; };
-		305961E32346125100C80F33 /* MessagesDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059619D2346125000C80F33 /* MessagesDataSource.swift */; };
-		305961E42346125100C80F33 /* MessageKitDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059619F2346125100C80F33 /* MessageKitDateFormatter.swift */; };
-		305961E52346125100C80F33 /* LabelAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A02346125100C80F33 /* LabelAlignment.swift */; };
-		305961E62346125100C80F33 /* LocationMessageSnapshotOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A12346125100C80F33 /* LocationMessageSnapshotOptions.swift */; };
-		305961E72346125100C80F33 /* AccessoryPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A22346125100C80F33 /* AccessoryPosition.swift */; };
-		305961E82346125100C80F33 /* Sender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A32346125100C80F33 /* Sender.swift */; };
-		305961E92346125100C80F33 /* MessageKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A42346125100C80F33 /* MessageKind.swift */; };
-		305961EA2346125100C80F33 /* MessageStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A52346125100C80F33 /* MessageStyle.swift */; };
-		305961EB2346125100C80F33 /* MessageKitError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A62346125100C80F33 /* MessageKitError.swift */; };
-		305961EC2346125100C80F33 /* Avatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A72346125100C80F33 /* Avatar.swift */; };
-		305961ED2346125100C80F33 /* DetectorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A82346125100C80F33 /* DetectorType.swift */; };
-		305961EE2346125100C80F33 /* AvatarPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961A92346125100C80F33 /* AvatarPosition.swift */; };
-		305961EF2346125100C80F33 /* HorizontalEdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961AA2346125100C80F33 /* HorizontalEdgeInsets.swift */; };
-		305961F02346125100C80F33 /* NSConstraintLayoutSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961AB2346125100C80F33 /* NSConstraintLayoutSet.swift */; };
-		305961F12346125100C80F33 /* ContactMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961AE2346125100C80F33 /* ContactMessageCell.swift */; };
-		305961F22346125100C80F33 /* LocationMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961AF2346125100C80F33 /* LocationMessageCell.swift */; };
-		305961F32346125100C80F33 /* MediaMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B02346125100C80F33 /* MediaMessageCell.swift */; };
-		305961F42346125100C80F33 /* TextMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B12346125100C80F33 /* TextMessageCell.swift */; };
-		305961F52346125100C80F33 /* TypingIndicatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B22346125100C80F33 /* TypingIndicatorCell.swift */; };
-		305961F62346125100C80F33 /* MessageContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B32346125100C80F33 /* MessageContentCell.swift */; };
-		305961F72346125100C80F33 /* MessageCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B42346125100C80F33 /* MessageCollectionViewCell.swift */; };
-		305961F82346125100C80F33 /* AudioMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B52346125100C80F33 /* AudioMessageCell.swift */; };
-		305961F92346125100C80F33 /* MessageLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B62346125100C80F33 /* MessageLabel.swift */; };
-		305961FA2346125100C80F33 /* MessageReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B82346125100C80F33 /* MessageReusableView.swift */; };
-		305961FB2346125100C80F33 /* TypingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961B92346125100C80F33 /* TypingIndicator.swift */; };
-		305961FC2346125100C80F33 /* MessageContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961BA2346125100C80F33 /* MessageContainerView.swift */; };
-		305961FD2346125100C80F33 /* TypingBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961BB2346125100C80F33 /* TypingBubble.swift */; };
-		305961FE2346125100C80F33 /* InsetLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961BC2346125100C80F33 /* InsetLabel.swift */; };
-		305961FF2346125100C80F33 /* AvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961BD2346125100C80F33 /* AvatarView.swift */; };
-		305962002346125100C80F33 /* MessagesCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961BE2346125100C80F33 /* MessagesCollectionView.swift */; };
-		305962012346125100C80F33 /* PlayButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961BF2346125100C80F33 /* PlayButtonView.swift */; };
-		305962022346125100C80F33 /* BubbleCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C02346125100C80F33 /* BubbleCircle.swift */; };
-		305962032346125100C80F33 /* CellSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C22346125100C80F33 /* CellSizeCalculator.swift */; };
-		305962042346125100C80F33 /* MessagesCollectionViewLayoutAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C32346125100C80F33 /* MessagesCollectionViewLayoutAttributes.swift */; };
-		305962052346125100C80F33 /* ContactMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C42346125100C80F33 /* ContactMessageSizeCalculator.swift */; };
-		305962062346125100C80F33 /* TypingIndicatorCellSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C52346125100C80F33 /* TypingIndicatorCellSizeCalculator.swift */; };
-		305962072346125100C80F33 /* MessagesCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C62346125100C80F33 /* MessagesCollectionViewFlowLayout.swift */; };
-		305962082346125100C80F33 /* MediaMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C72346125100C80F33 /* MediaMessageSizeCalculator.swift */; };
-		305962092346125100C80F33 /* AudioMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C82346125100C80F33 /* AudioMessageSizeCalculator.swift */; };
-		3059620A2346125100C80F33 /* TextMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961C92346125100C80F33 /* TextMessageSizeCalculator.swift */; };
-		3059620B2346125100C80F33 /* LocationMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961CA2346125100C80F33 /* LocationMessageSizeCalculator.swift */; };
-		3059620C2346125100C80F33 /* MessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305961CB2346125100C80F33 /* MessageSizeCalculator.swift */; };
 		3059620E234614E700C80F33 /* DcContact+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059620D234614E700C80F33 /* DcContact+Extension.swift */; };
 		305962102346154D00C80F33 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059620F2346154D00C80F33 /* String+Extension.swift */; };
 		3060119C22DDE24000C1CE6F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3060119E22DDE24000C1CE6F /* Localizable.strings */; };
@@ -105,11 +44,7 @@
 		306C32322445CDE9001D89F3 /* DcLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306C32312445CDE9001D89F3 /* DcLogger.swift */; };
 		30734326249A280B00BF9AD1 /* MediaQualityController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30734325249A280B00BF9AD1 /* MediaQualityController.swift */; };
 		307D822E241669C7006D2490 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307D822D241669C7006D2490 /* LocationManager.swift */; };
-		308FEA4C2462F11300FCEAD6 /* FileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FEA4B2462F11300FCEAD6 /* FileView.swift */; };
-		308FEA50246AB67100FCEAD6 /* FileMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FEA4F246AB67100FCEAD6 /* FileMessageCell.swift */; };
-		308FEA52246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308FEA51246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift */; };
 		3095A351237DD1F700AB07F7 /* MediaPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3095A350237DD1F700AB07F7 /* MediaPicker.swift */; };
-		30A2EC36247D72720024ADD8 /* AnimatedImageMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A2EC35247D72720024ADD8 /* AnimatedImageMessageCell.swift */; };
 		30A4149724F6EFBE00EC91EB /* NewInfoMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A4149624F6EFBE00EC91EB /* NewInfoMessageCell.swift */; };
 		30B0ACFA24AB5B99004D5E29 /* SettingsEphemeralMessageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0ACF924AB5B99004D5E29 /* SettingsEphemeralMessageController.swift */; };
 		30C0D49D237C4908008E2A0E /* CertificateCheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C0D49C237C4908008E2A0E /* CertificateCheckController.swift */; };
@@ -141,7 +76,6 @@
 		789E879621D6CB58003ED1C5 /* QrCodeReaderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789E879521D6CB58003ED1C5 /* QrCodeReaderController.swift */; };
 		78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E3921D3CFBC00D4B15E /* SettingsController.swift */; };
 		78E45E4421D3F14A00D4B15E /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */; };
-		78E45E4C21D404AE00D4B15E /* InfoMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E45E4B21D404AE00D4B15E /* InfoMessageCell.swift */; };
 		78ED838321D5379000243125 /* TextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78ED838221D5379000243125 /* TextFieldCell.swift */; };
 		78ED839421D5AF8A00243125 /* QrCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78ED839321D5AF8A00243125 /* QrCodeView.swift */; };
 		7A0052C81FBE6CB40048C3BF /* NewContactController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0052C71FBE6CB40048C3BF /* NewContactController.swift */; };
@@ -175,16 +109,12 @@
 		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 */; };
 		AE851AD0227DF50900ED86F0 /* GroupChatDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE851ACF227DF50900ED86F0 /* GroupChatDetailViewController.swift */; };
 		AE8DD451249D1DFB009A4BC1 /* FileTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE8DD450249D1DFB009A4BC1 /* FileTableViewCell.swift */; };
 		AE8F503524753DFE007FEE0B /* GalleryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE8F503424753DFE007FEE0B /* GalleryViewController.swift */; };
 		AE9DAF0D22C1215D004C9591 /* EditContactController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE9DAF0C22C1215D004C9591 /* EditContactController.swift */; };
 		AE9DAF0F22C278C6004C9591 /* ChatTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE9DAF0E22C278C6004C9591 /* ChatTitleView.swift */; };
 		AEA0F6A124474146009F887B /* ProfileInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEA0F6A024474146009F887B /* ProfileInfoViewController.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 */; };
 		AEACE2E51FB32E1900DCDD78 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEACE2E41FB32E1900DCDD78 /* Utils.swift */; };
 		AEC67A1C241CE9E4007DDBE1 /* AppStateRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEC67A1B241CE9E4007DDBE1 /* AppStateRestorer.swift */; };
@@ -255,8 +185,6 @@
 		3008CB7124F93EB900E6A617 /* NewAudioMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewAudioMessageCell.swift; sourceTree = "<group>"; };
 		3008CB7324F9436C00E6A617 /* NewAudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewAudioPlayerView.swift; sourceTree = "<group>"; };
 		3008CB7524F95B6D00E6A617 /* NewAudioController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewAudioController.swift; sourceTree = "<group>"; };
-		300C509C234B551900F8AE22 /* TextMediaMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextMediaMessageCell.swift; sourceTree = "<group>"; };
-		300C50A0234BDAB800F8AE22 /* TextMediaMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextMediaMessageSizeCalculator.swift; sourceTree = "<group>"; };
 		30149D9222F21129003C12B5 /* QrViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrViewController.swift; sourceTree = "<group>"; };
 		3015634323A003BA00E9DEF4 /* AudioRecorderController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderController.swift; sourceTree = "<group>"; };
 		3022E6BF22E8768800763272 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -284,11 +212,10 @@
 		302B84C42396627F001C261F /* RelayHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayHelper.swift; sourceTree = "<group>"; };
 		302B84CD2397F6CD001C261F /* URL+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extension.swift"; sourceTree = "<group>"; };
 		302E1BB3252B5AB4008F4264 /* NewPlayButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NewPlayButtonView.swift; path = "deltachat-ios/Chat/Views/NewPlayButtonView.swift"; sourceTree = SOURCE_ROOT; };
-		3040F45D234DFBC000FA34D5 /* Audio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Audio.swift; sourceTree = "<group>"; };
-		3040F45F234F419300FA34D5 /* BasicAudioController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicAudioController.swift; sourceTree = "<group>"; };
-		3040F461234F550300FA34D5 /* AudioPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerView.swift; sourceTree = "<group>"; };
 		304219D1243F588500516852 /* DcCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DcCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		304219D82440734A00516852 /* DcMsg+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DcMsg+Extension.swift"; sourceTree = "<group>"; };
+		3052C609253F082E007D13EA /* MessageLabelDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageLabelDelegate.swift; sourceTree = "<group>"; };
+		3052C60D253F088E007D13EA /* DetectorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectorType.swift; sourceTree = "<group>"; };
 		3057027E24C5B2F800D84EFC /* ChatListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListViewModel.swift; sourceTree = "<group>"; };
 		3057029A24C6441300D84EFC /* EmptyStateLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyStateLabel.swift; sourceTree = "<group>"; };
 		3057029C24C6442800D84EFC /* FlexLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexLabel.swift; sourceTree = "<group>"; };
@@ -296,66 +223,7 @@
 		305961832346125000C80F33 /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIEdgeInsets+Extensions.swift"; sourceTree = "<group>"; };
 		305961852346125000C80F33 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
 		305961862346125000C80F33 /* NSAttributedString+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Extensions.swift"; sourceTree = "<group>"; };
-		305961872346125000C80F33 /* Bundle+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bundle+Extensions.swift"; sourceTree = "<group>"; };
 		305961882346125000C80F33 /* CGRect+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGRect+Extensions.swift"; sourceTree = "<group>"; };
-		3059618A2346125000C80F33 /* MessagesViewController+Keyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessagesViewController+Keyboard.swift"; sourceTree = "<group>"; };
-		3059618B2346125000C80F33 /* MessagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = "<group>"; };
-		3059618C2346125000C80F33 /* MessagesViewController+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessagesViewController+Menu.swift"; sourceTree = "<group>"; };
-		3059618E2346125000C80F33 /* MessageInputBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageInputBar.swift; sourceTree = "<group>"; };
-		3059618F2346125000C80F33 /* MessageKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageKit.h; sourceTree = "<group>"; };
-		305961902346125000C80F33 /* MessageKit+Availability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageKit+Availability.swift"; sourceTree = "<group>"; };
-		305961932346125000C80F33 /* ContactItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactItem.swift; sourceTree = "<group>"; };
-		305961942346125000C80F33 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = "<group>"; };
-		305961952346125000C80F33 /* AudioItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioItem.swift; sourceTree = "<group>"; };
-		305961962346125000C80F33 /* MessagesLayoutDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesLayoutDelegate.swift; sourceTree = "<group>"; };
-		305961972346125000C80F33 /* SenderType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SenderType.swift; sourceTree = "<group>"; };
-		305961982346125000C80F33 /* MessageType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageType.swift; sourceTree = "<group>"; };
-		305961992346125000C80F33 /* MessageCellDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellDelegate.swift; sourceTree = "<group>"; };
-		3059619A2346125000C80F33 /* MessageLabelDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageLabelDelegate.swift; sourceTree = "<group>"; };
-		3059619B2346125000C80F33 /* LocationItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationItem.swift; sourceTree = "<group>"; };
-		3059619C2346125000C80F33 /* MessagesDisplayDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesDisplayDelegate.swift; sourceTree = "<group>"; };
-		3059619D2346125000C80F33 /* MessagesDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesDataSource.swift; sourceTree = "<group>"; };
-		3059619F2346125100C80F33 /* MessageKitDateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageKitDateFormatter.swift; sourceTree = "<group>"; };
-		305961A02346125100C80F33 /* LabelAlignment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelAlignment.swift; sourceTree = "<group>"; };
-		305961A12346125100C80F33 /* LocationMessageSnapshotOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationMessageSnapshotOptions.swift; sourceTree = "<group>"; };
-		305961A22346125100C80F33 /* AccessoryPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessoryPosition.swift; sourceTree = "<group>"; };
-		305961A32346125100C80F33 /* Sender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sender.swift; sourceTree = "<group>"; };
-		305961A42346125100C80F33 /* MessageKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageKind.swift; sourceTree = "<group>"; };
-		305961A52346125100C80F33 /* MessageStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageStyle.swift; sourceTree = "<group>"; };
-		305961A62346125100C80F33 /* MessageKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageKitError.swift; sourceTree = "<group>"; };
-		305961A72346125100C80F33 /* Avatar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Avatar.swift; sourceTree = "<group>"; };
-		305961A82346125100C80F33 /* DetectorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetectorType.swift; sourceTree = "<group>"; };
-		305961A92346125100C80F33 /* AvatarPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarPosition.swift; sourceTree = "<group>"; };
-		305961AA2346125100C80F33 /* HorizontalEdgeInsets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalEdgeInsets.swift; sourceTree = "<group>"; };
-		305961AB2346125100C80F33 /* NSConstraintLayoutSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSConstraintLayoutSet.swift; sourceTree = "<group>"; };
-		305961AE2346125100C80F33 /* ContactMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactMessageCell.swift; sourceTree = "<group>"; };
-		305961AF2346125100C80F33 /* LocationMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationMessageCell.swift; sourceTree = "<group>"; };
-		305961B02346125100C80F33 /* MediaMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaMessageCell.swift; sourceTree = "<group>"; };
-		305961B12346125100C80F33 /* TextMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextMessageCell.swift; sourceTree = "<group>"; };
-		305961B22346125100C80F33 /* TypingIndicatorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorCell.swift; sourceTree = "<group>"; };
-		305961B32346125100C80F33 /* MessageContentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageContentCell.swift; sourceTree = "<group>"; };
-		305961B42346125100C80F33 /* MessageCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCollectionViewCell.swift; sourceTree = "<group>"; };
-		305961B52346125100C80F33 /* AudioMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioMessageCell.swift; sourceTree = "<group>"; };
-		305961B62346125100C80F33 /* MessageLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageLabel.swift; sourceTree = "<group>"; };
-		305961B82346125100C80F33 /* MessageReusableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageReusableView.swift; sourceTree = "<group>"; };
-		305961B92346125100C80F33 /* TypingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicator.swift; sourceTree = "<group>"; };
-		305961BA2346125100C80F33 /* MessageContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageContainerView.swift; sourceTree = "<group>"; };
-		305961BB2346125100C80F33 /* TypingBubble.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingBubble.swift; sourceTree = "<group>"; };
-		305961BC2346125100C80F33 /* InsetLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsetLabel.swift; sourceTree = "<group>"; };
-		305961BD2346125100C80F33 /* AvatarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarView.swift; sourceTree = "<group>"; };
-		305961BE2346125100C80F33 /* MessagesCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesCollectionView.swift; sourceTree = "<group>"; };
-		305961BF2346125100C80F33 /* PlayButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayButtonView.swift; sourceTree = "<group>"; };
-		305961C02346125100C80F33 /* BubbleCircle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleCircle.swift; sourceTree = "<group>"; };
-		305961C22346125100C80F33 /* CellSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellSizeCalculator.swift; sourceTree = "<group>"; };
-		305961C32346125100C80F33 /* MessagesCollectionViewLayoutAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesCollectionViewLayoutAttributes.swift; sourceTree = "<group>"; };
-		305961C42346125100C80F33 /* ContactMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactMessageSizeCalculator.swift; sourceTree = "<group>"; };
-		305961C52346125100C80F33 /* TypingIndicatorCellSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorCellSizeCalculator.swift; sourceTree = "<group>"; };
-		305961C62346125100C80F33 /* MessagesCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagesCollectionViewFlowLayout.swift; sourceTree = "<group>"; };
-		305961C72346125100C80F33 /* MediaMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaMessageSizeCalculator.swift; sourceTree = "<group>"; };
-		305961C82346125100C80F33 /* AudioMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioMessageSizeCalculator.swift; sourceTree = "<group>"; };
-		305961C92346125100C80F33 /* TextMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextMessageSizeCalculator.swift; sourceTree = "<group>"; };
-		305961CA2346125100C80F33 /* LocationMessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationMessageSizeCalculator.swift; sourceTree = "<group>"; };
-		305961CB2346125100C80F33 /* MessageSizeCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageSizeCalculator.swift; sourceTree = "<group>"; };
 		3059620D234614E700C80F33 /* DcContact+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DcContact+Extension.swift"; sourceTree = "<group>"; };
 		3059620F2346154D00C80F33 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
 		305FE03523A81B4C0053BE90 /* EmptyStateLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyStateLabel.swift; sourceTree = "<group>"; };
@@ -402,11 +270,7 @@
 		306C32312445CDE9001D89F3 /* DcLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DcLogger.swift; sourceTree = "<group>"; };
 		30734325249A280B00BF9AD1 /* MediaQualityController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaQualityController.swift; sourceTree = "<group>"; };
 		307D822D241669C7006D2490 /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = "<group>"; };
-		308FEA4B2462F11300FCEAD6 /* FileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileView.swift; sourceTree = "<group>"; };
-		308FEA4F246AB67100FCEAD6 /* FileMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMessageCell.swift; sourceTree = "<group>"; };
-		308FEA51246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMessageSizeCalculator.swift; sourceTree = "<group>"; };
 		3095A350237DD1F700AB07F7 /* MediaPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPicker.swift; sourceTree = "<group>"; };
-		30A2EC35247D72720024ADD8 /* AnimatedImageMessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatedImageMessageCell.swift; sourceTree = "<group>"; };
 		30A4149624F6EFBE00EC91EB /* NewInfoMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewInfoMessageCell.swift; sourceTree = "<group>"; };
 		30AC265E237F1807002A943F /* AvatarHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarHelper.swift; sourceTree = "<group>"; };
 		30B0ACF924AB5B99004D5E29 /* SettingsEphemeralMessageController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsEphemeralMessageController.swift; sourceTree = "<group>"; };
@@ -441,7 +305,6 @@
 		78C7036A21D46752005D4525 /* deltachat-ios.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "deltachat-ios.entitlements"; sourceTree = "<group>"; };
 		78E45E3921D3CFBC00D4B15E /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
 		78E45E4321D3F14A00D4B15E /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = "<group>"; };
-		78E45E4B21D404AE00D4B15E /* InfoMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoMessageCell.swift; sourceTree = "<group>"; };
 		78ED838221D5379000243125 /* TextFieldCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldCell.swift; sourceTree = "<group>"; };
 		78ED839321D5AF8A00243125 /* QrCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeView.swift; sourceTree = "<group>"; };
 		7A0052C71FBE6CB40048C3BF /* NewContactController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewContactController.swift; sourceTree = "<group>"; };
@@ -481,16 +344,12 @@
 		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>"; };
 		AE851ACF227DF50900ED86F0 /* GroupChatDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatDetailViewController.swift; sourceTree = "<group>"; };
 		AE8DD450249D1DFB009A4BC1 /* FileTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileTableViewCell.swift; sourceTree = "<group>"; };
 		AE8F503424753DFE007FEE0B /* GalleryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryViewController.swift; sourceTree = "<group>"; };
 		AE9DAF0C22C1215D004C9591 /* EditContactController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditContactController.swift; sourceTree = "<group>"; };
 		AE9DAF0E22C278C6004C9591 /* ChatTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTitleView.swift; sourceTree = "<group>"; };
 		AEA0F6A024474146009F887B /* ProfileInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileInfoViewController.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>"; };
 		AEACE2E21FB32B5C00DCDD78 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
 		AEACE2E41FB32E1900DCDD78 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
 		AEB54C7E246DBA610004624C /* FlexLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlexLabel.swift; sourceTree = "<group>"; };
@@ -624,19 +483,6 @@
 			path = ViewModel;
 			sourceTree = "<group>";
 		};
-		3059617E234610A800C80F33 /* MessageKit */ = {
-			isa = PBXGroup;
-			children = (
-				305961892346125000C80F33 /* Controllers */,
-				305961C12346125100C80F33 /* Layout */,
-				3059619E2346125100C80F33 /* Models */,
-				305961922346125000C80F33 /* Protocols */,
-				3059618D2346125000C80F33 /* Supporting */,
-				305961AC2346125100C80F33 /* Views */,
-			);
-			path = MessageKit;
-			sourceTree = "<group>";
-		};
 		305961812346125000C80F33 /* Extensions */ = {
 			isa = PBXGroup;
 			children = (
@@ -645,7 +491,6 @@
 				305961832346125000C80F33 /* UIEdgeInsets+Extensions.swift */,
 				305961852346125000C80F33 /* UIColor+Extensions.swift */,
 				305961862346125000C80F33 /* NSAttributedString+Extensions.swift */,
-				305961872346125000C80F33 /* Bundle+Extensions.swift */,
 				305961882346125000C80F33 /* CGRect+Extensions.swift */,
 				3059620D234614E700C80F33 /* DcContact+Extension.swift */,
 				3059620F2346154D00C80F33 /* String+Extension.swift */,
@@ -656,131 +501,6 @@
 			path = Extensions;
 			sourceTree = "<group>";
 		};
-		305961892346125000C80F33 /* Controllers */ = {
-			isa = PBXGroup;
-			children = (
-				3040F45F234F419300FA34D5 /* BasicAudioController.swift */,
-				3059618A2346125000C80F33 /* MessagesViewController+Keyboard.swift */,
-				3059618B2346125000C80F33 /* MessagesViewController.swift */,
-				3059618C2346125000C80F33 /* MessagesViewController+Menu.swift */,
-			);
-			path = Controllers;
-			sourceTree = "<group>";
-		};
-		3059618D2346125000C80F33 /* Supporting */ = {
-			isa = PBXGroup;
-			children = (
-				3059618E2346125000C80F33 /* MessageInputBar.swift */,
-				3059618F2346125000C80F33 /* MessageKit.h */,
-				305961902346125000C80F33 /* MessageKit+Availability.swift */,
-			);
-			path = Supporting;
-			sourceTree = "<group>";
-		};
-		305961922346125000C80F33 /* Protocols */ = {
-			isa = PBXGroup;
-			children = (
-				305961932346125000C80F33 /* ContactItem.swift */,
-				305961942346125000C80F33 /* MediaItem.swift */,
-				305961952346125000C80F33 /* AudioItem.swift */,
-				305961962346125000C80F33 /* MessagesLayoutDelegate.swift */,
-				305961972346125000C80F33 /* SenderType.swift */,
-				305961982346125000C80F33 /* MessageType.swift */,
-				305961992346125000C80F33 /* MessageCellDelegate.swift */,
-				3059619A2346125000C80F33 /* MessageLabelDelegate.swift */,
-				3059619B2346125000C80F33 /* LocationItem.swift */,
-				3059619C2346125000C80F33 /* MessagesDisplayDelegate.swift */,
-				3059619D2346125000C80F33 /* MessagesDataSource.swift */,
-			);
-			path = Protocols;
-			sourceTree = "<group>";
-		};
-		3059619E2346125100C80F33 /* Models */ = {
-			isa = PBXGroup;
-			children = (
-				3059619F2346125100C80F33 /* MessageKitDateFormatter.swift */,
-				305961A02346125100C80F33 /* LabelAlignment.swift */,
-				305961A12346125100C80F33 /* LocationMessageSnapshotOptions.swift */,
-				305961A22346125100C80F33 /* AccessoryPosition.swift */,
-				305961A32346125100C80F33 /* Sender.swift */,
-				305961A42346125100C80F33 /* MessageKind.swift */,
-				305961A52346125100C80F33 /* MessageStyle.swift */,
-				305961A62346125100C80F33 /* MessageKitError.swift */,
-				305961A72346125100C80F33 /* Avatar.swift */,
-				305961A82346125100C80F33 /* DetectorType.swift */,
-				305961A92346125100C80F33 /* AvatarPosition.swift */,
-				305961AA2346125100C80F33 /* HorizontalEdgeInsets.swift */,
-				305961AB2346125100C80F33 /* NSConstraintLayoutSet.swift */,
-			);
-			path = Models;
-			sourceTree = "<group>";
-		};
-		305961AC2346125100C80F33 /* Views */ = {
-			isa = PBXGroup;
-			children = (
-				305961B72346125100C80F33 /* HeadersFooters */,
-				305961AD2346125100C80F33 /* Cells */,
-				305961B62346125100C80F33 /* MessageLabel.swift */,
-				305961B92346125100C80F33 /* TypingIndicator.swift */,
-				305961BA2346125100C80F33 /* MessageContainerView.swift */,
-				305961BB2346125100C80F33 /* TypingBubble.swift */,
-				305961BC2346125100C80F33 /* InsetLabel.swift */,
-				305961BD2346125100C80F33 /* AvatarView.swift */,
-				305961BE2346125100C80F33 /* MessagesCollectionView.swift */,
-				305961BF2346125100C80F33 /* PlayButtonView.swift */,
-				305961C02346125100C80F33 /* BubbleCircle.swift */,
-				3040F461234F550300FA34D5 /* AudioPlayerView.swift */,
-				308FEA4B2462F11300FCEAD6 /* FileView.swift */,
-			);
-			path = Views;
-			sourceTree = "<group>";
-		};
-		305961AD2346125100C80F33 /* Cells */ = {
-			isa = PBXGroup;
-			children = (
-				300C509C234B551900F8AE22 /* TextMediaMessageCell.swift */,
-				30A2EC35247D72720024ADD8 /* AnimatedImageMessageCell.swift */,
-				305961AE2346125100C80F33 /* ContactMessageCell.swift */,
-				78E45E4B21D404AE00D4B15E /* InfoMessageCell.swift */,
-				305961AF2346125100C80F33 /* LocationMessageCell.swift */,
-				305961B02346125100C80F33 /* MediaMessageCell.swift */,
-				305961B12346125100C80F33 /* TextMessageCell.swift */,
-				308FEA4F246AB67100FCEAD6 /* FileMessageCell.swift */,
-				305961B22346125100C80F33 /* TypingIndicatorCell.swift */,
-				305961B32346125100C80F33 /* MessageContentCell.swift */,
-				305961B42346125100C80F33 /* MessageCollectionViewCell.swift */,
-				305961B52346125100C80F33 /* AudioMessageCell.swift */,
-			);
-			path = Cells;
-			sourceTree = "<group>";
-		};
-		305961B72346125100C80F33 /* HeadersFooters */ = {
-			isa = PBXGroup;
-			children = (
-				305961B82346125100C80F33 /* MessageReusableView.swift */,
-			);
-			path = HeadersFooters;
-			sourceTree = "<group>";
-		};
-		305961C12346125100C80F33 /* Layout */ = {
-			isa = PBXGroup;
-			children = (
-				305961C22346125100C80F33 /* CellSizeCalculator.swift */,
-				305961C32346125100C80F33 /* MessagesCollectionViewLayoutAttributes.swift */,
-				305961C42346125100C80F33 /* ContactMessageSizeCalculator.swift */,
-				305961C52346125100C80F33 /* TypingIndicatorCellSizeCalculator.swift */,
-				305961C62346125100C80F33 /* MessagesCollectionViewFlowLayout.swift */,
-				305961C72346125100C80F33 /* MediaMessageSizeCalculator.swift */,
-				300C50A0234BDAB800F8AE22 /* TextMediaMessageSizeCalculator.swift */,
-				308FEA51246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift */,
-				305961C82346125100C80F33 /* AudioMessageSizeCalculator.swift */,
-				305961C92346125100C80F33 /* TextMessageSizeCalculator.swift */,
-				305961CA2346125100C80F33 /* LocationMessageSizeCalculator.swift */,
-				305961CB2346125100C80F33 /* MessageSizeCalculator.swift */,
-			);
-			path = Layout;
-			sourceTree = "<group>";
-		};
 		30E8F2112447285600CE2C90 /* DcShare */ = {
 			isa = PBXGroup;
 			children = (
@@ -814,6 +534,8 @@
 				30F8817524DA97DA0023780E /* BackgroundContainer.swift */,
 				3008CB7324F9436C00E6A617 /* NewAudioPlayerView.swift */,
 				30EF7323252FF15F00E2C54A /* NewMessageLabel.swift */,
+				3052C609253F082E007D13EA /* MessageLabelDelegate.swift */,
+				3052C60D253F088E007D13EA /* DetectorType.swift */,
 			);
 			path = Views;
 			sourceTree = "<group>";
@@ -868,14 +590,12 @@
 				AE19887623EB2BDA00B4CD5F /* Assets */,
 				AE77838B23E32EAA0093EABD /* ViewModel */,
 				305961812346125000C80F33 /* Extensions */,
-				3059617E234610A800C80F33 /* MessageKit */,
 				7A9FB1431FB061E2001FEA36 /* AppDelegate.swift */,
 				AE851AC3227C695900ED86F0 /* View */,
 				AE851AC2227C695000ED86F0 /* Helper */,
 				30FDB6B224D18E390066C48D /* Chat */,
 				AE851AC1227C694300ED86F0 /* Coordinator */,
 				AE851AC0227C693B00ED86F0 /* Controller */,
-				AE851ABA227C692600ED86F0 /* Model */,
 				AE851ACB227C7A5000ED86F0 /* Handler */,
 				7A9FB15B1FB07364001FEA36 /* libraries */,
 				78C7036A21D46752005D4525 /* deltachat-ios.entitlements */,
@@ -963,17 +683,6 @@
 			path = "deltachat-iosTests";
 			sourceTree = "<group>";
 		};
-		AE851ABA227C692600ED86F0 /* Model */ = {
-			isa = PBXGroup;
-			children = (
-				AEACE2DE1FB3246400DCDD78 /* Message.swift */,
-				AE851AC6227C776400ED86F0 /* Location.swift */,
-				AE851AC8227C77CF00ED86F0 /* Media.swift */,
-				3040F45D234DFBC000FA34D5 /* Audio.swift */,
-			);
-			path = Model;
-			sourceTree = "<group>";
-		};
 		AE851AC0227C693B00ED86F0 /* Controller */ = {
 			isa = PBXGroup;
 			children = (
@@ -981,7 +690,6 @@
 				AE18F28B228C17630007B1BE /* AccountSetup */,
 				AEE56D752253431E007DC082 /* AccountSetupController.swift */,
 				AE0D26FC1FB1FE88002FAFCE /* ChatListController.swift */,
-				AEACE2DC1FB323CA00DCDD78 /* ChatViewController.swift */,
 				7092474020B3869500AF8799 /* ContactDetailViewController.swift */,
 				AE9DAF0C22C1215D004C9591 /* EditContactController.swift */,
 				AE52EA1F229EB9F000C586C9 /* EditGroupViewController.swift */,
@@ -1438,67 +1146,38 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				305961DC2346125100C80F33 /* MessagesLayoutDelegate.swift in Sources */,
-				3059620A2346125100C80F33 /* TextMessageSizeCalculator.swift in Sources */,
 				78ED839421D5AF8A00243125 /* QrCodeView.swift in Sources */,
-				305961F02346125100C80F33 /* NSConstraintLayoutSet.swift in Sources */,
 				3059620E234614E700C80F33 /* DcContact+Extension.swift in Sources */,
 				AED423D7249F580700B6B2BB /* BlockedContactsViewController.swift in Sources */,
 				3008CB7424F9436C00E6A617 /* NewAudioPlayerView.swift in Sources */,
 				AED62BCE247687E6009E220D /* LocationStreamingIndicator.swift in Sources */,
-				305961F72346125100C80F33 /* MessageCollectionViewCell.swift in Sources */,
-				AE851AC9227C77CF00ED86F0 /* Media.swift in Sources */,
-				AEACE2DF1FB3246400DCDD78 /* Message.swift in Sources */,
 				AE9DAF0F22C278C6004C9591 /* ChatTitleView.swift in Sources */,
 				AE4AEE3522B1030D000AA495 /* PreviewController.swift in Sources */,
 				7070FB9B2101ECBB000DC258 /* NewGroupController.swift in Sources */,
-				305961EA2346125100C80F33 /* MessageStyle.swift in Sources */,
-				305961F92346125100C80F33 /* MessageLabel.swift in Sources */,
 				304219D92440734A00516852 /* DcMsg+Extension.swift in Sources */,
-				305961FA2346125100C80F33 /* MessageReusableView.swift in Sources */,
-				3040F462234F550300FA34D5 /* AudioPlayerView.swift in Sources */,
 				AE52EA19229EB53C00C586C9 /* ContactDetailHeader.swift in Sources */,
 				78E45E4421D3F14A00D4B15E /* UIImage+Extension.swift in Sources */,
 				30734326249A280B00BF9AD1 /* MediaQualityController.swift in Sources */,
-				3040F460234F419400FA34D5 /* BasicAudioController.swift in Sources */,
-				30A2EC36247D72720024ADD8 /* AnimatedImageMessageCell.swift in Sources */,
-				305962082346125100C80F33 /* MediaMessageSizeCalculator.swift in Sources */,
 				AE6EC5282497B9B200A400E4 /* ThumbnailCache.swift in Sources */,
 				30FDB70524D1C1000066C48D /* ChatViewControllerNew.swift in Sources */,
 				3057029D24C6442800D84EFC /* FlexLabel.swift in Sources */,
 				AE52EA20229EB9F000C586C9 /* EditGroupViewController.swift in Sources */,
 				AE18F294228C602A0007B1BE /* SecuritySettingsController.swift in Sources */,
 				AE39D323249CFC1A007346A1 /* DocumentGalleryController.swift in Sources */,
-				305961FD2346125100C80F33 /* TypingBubble.swift in Sources */,
-				305961D72346125100C80F33 /* MessageKit+Availability.swift in Sources */,
 				AE8DD451249D1DFB009A4BC1 /* FileTableViewCell.swift in Sources */,
-				3040F45E234DFBC000FA34D5 /* Audio.swift in Sources */,
-				305961FE2346125100C80F33 /* InsetLabel.swift in Sources */,
 				3095A351237DD1F700AB07F7 /* MediaPicker.swift in Sources */,
 				B21005DB23383664004C70C5 /* SettingsClassicViewController.swift in Sources */,
-				305961F62346125100C80F33 /* MessageContentCell.swift in Sources */,
-				305961E42346125100C80F33 /* MessageKitDateFormatter.swift in Sources */,
 				AEC67A1C241CE9E4007DDBE1 /* AppStateRestorer.swift in Sources */,
-				305961D32346125100C80F33 /* MessagesViewController+Keyboard.swift in Sources */,
 				3008CB7224F93EB900E6A617 /* NewAudioMessageCell.swift in Sources */,
-				305961EF2346125100C80F33 /* HorizontalEdgeInsets.swift in Sources */,
 				302E1BB4252B5AB4008F4264 /* NewPlayButtonView.swift in Sources */,
-				305961D62346125100C80F33 /* MessageInputBar.swift in Sources */,
-				305961ED2346125100C80F33 /* DetectorType.swift in Sources */,
-				305962062346125100C80F33 /* TypingIndicatorCellSizeCalculator.swift in Sources */,
-				AE851AC7227C776400ED86F0 /* Location.swift in Sources */,
 				7AE0A5491FC42F65005ECB4B /* NewChatViewController.swift in Sources */,
-				305961E52346125100C80F33 /* LabelAlignment.swift in Sources */,
 				AE77838F23E4276D0093EABD /* ContactCellViewModel.swift in Sources */,
 				B20462E62440C99600367A57 /* SettingsAutodelSetController.swift in Sources */,
-				305961E82346125100C80F33 /* Sender.swift in Sources */,
-				305961EE2346125100C80F33 /* AvatarPosition.swift in Sources */,
 				3015634423A003BA00E9DEF4 /* AudioRecorderController.swift in Sources */,
 				AE25F09022807AD800CDEA66 /* AvatarSelectionCell.swift in Sources */,
 				30A4149724F6EFBE00EC91EB /* NewInfoMessageCell.swift in Sources */,
 				302B84C6239676F0001C261F /* AvatarHelper.swift in Sources */,
 				AE77838D23E32ED20093EABD /* ContactDetailViewModel.swift in Sources */,
-				305961E62346125100C80F33 /* LocationMessageSnapshotOptions.swift in Sources */,
 				AEE6EC3F2282C59C00EDC689 /* GroupMembersViewController.swift in Sources */,
 				B26B3BC7236DC3DC008ED35A /* SwitchCell.swift in Sources */,
 				AEE700252438E0E500D6992E /* ProgressAlertHandler.swift in Sources */,
@@ -1506,21 +1185,15 @@
 				306C32322445CDE9001D89F3 /* DcLogger.swift in Sources */,
 				78E45E3A21D3CFBC00D4B15E /* SettingsController.swift in Sources */,
 				AE8519EA2272FDCA00ED86F0 /* DeviceContactsHandler.swift in Sources */,
-				3059620B2346125100C80F33 /* LocationMessageSizeCalculator.swift in Sources */,
-				305962072346125100C80F33 /* MessagesCollectionViewFlowLayout.swift in Sources */,
 				78ED838321D5379000243125 /* TextFieldCell.swift in Sources */,
 				305702A124C6453700D84EFC /* TypeAlias.swift in Sources */,
 				AE19887523EB264000B4CD5F /* HelpViewController.swift in Sources */,
-				305961D52346125100C80F33 /* MessagesViewController+Menu.swift in Sources */,
-				305961F22346125100C80F33 /* LocationMessageCell.swift in Sources */,
 				AE0D26FD1FB1FE88002FAFCE /* ChatListController.swift in Sources */,
 				30149D9322F21129003C12B5 /* QrViewController.swift in Sources */,
 				AEE56D80225504DB007DC082 /* Extensions.swift in Sources */,
-				308FEA50246AB67100FCEAD6 /* FileMessageCell.swift in Sources */,
 				7A0052C81FBE6CB40048C3BF /* NewContactController.swift in Sources */,
 				AEE56D762253431E007DC082 /* AccountSetupController.swift in Sources */,
 				AE8F503524753DFE007FEE0B /* GalleryViewController.swift in Sources */,
-				AEACE2DD1FB323CA00DCDD78 /* ChatViewController.swift in Sources */,
 				AEE6EC412282DF5700EDC689 /* MailboxViewController.swift in Sources */,
 				AEF53BD5248904BF00D309C1 /* GalleryTimeLabel.swift in Sources */,
 				AEE6EC482283045D00EDC689 /* EditSettingsController.swift in Sources */,
@@ -1528,85 +1201,50 @@
 				30EF7308252F6A3300E2C54A /* PaddingTextView.swift in Sources */,
 				30E348E124F53772005C93D1 /* NewImageTextCell.swift in Sources */,
 				3008CB7624F95B6D00E6A617 /* NewAudioController.swift in Sources */,
-				305961DF2346125100C80F33 /* MessageCellDelegate.swift in Sources */,
 				302B84CE2397F6CD001C261F /* URL+Extension.swift in Sources */,
 				7A9FB1441FB061E2001FEA36 /* AppDelegate.swift in Sources */,
 				AE76E5EE242BF2EA003CF461 /* WelcomeViewController.swift in Sources */,
-				308FEA52246ABA2700FCEAD6 /* FileMessageSizeCalculator.swift in Sources */,
-				305961F52346125100C80F33 /* TypingIndicatorCell.swift in Sources */,
-				305961FF2346125100C80F33 /* AvatarView.swift in Sources */,
+				3052C60A253F082E007D13EA /* MessageLabelDelegate.swift in Sources */,
 				AE0AA9562478191900D42A7F /* GridCollectionViewFlowLayout.swift in Sources */,
-				3059620C2346125100C80F33 /* MessageSizeCalculator.swift in Sources */,
-				305962042346125100C80F33 /* MessagesCollectionViewLayoutAttributes.swift in Sources */,
 				AEA0F6A124474146009F887B /* ProfileInfoViewController.swift in Sources */,
 				305961D02346125100C80F33 /* NSAttributedString+Extensions.swift in Sources */,
 				302B84C72396770B001C261F /* RelayHelper.swift in Sources */,
 				305961CF2346125100C80F33 /* UIColor+Extensions.swift in Sources */,
 				AEACE2E51FB32E1900DCDD78 /* Utils.swift in Sources */,
+				3052C60E253F088E007D13EA /* DetectorType.swift in Sources */,
 				AEC67A1E241FCFE0007DDBE1 /* ChatListViewModel.swift in Sources */,
-				300C509D234B551900F8AE22 /* TextMediaMessageCell.swift in Sources */,
-				305961E92346125100C80F33 /* MessageKind.swift in Sources */,
-				305962022346125100C80F33 /* BubbleCircle.swift in Sources */,
 				30FDB71F24D8170E0066C48D /* NewTextMessageCell.swift in Sources */,
 				AE1988A523EB2FBA00B4CD5F /* Errors.swift in Sources */,
-				305961DD2346125100C80F33 /* SenderType.swift in Sources */,
-				305961E32346125100C80F33 /* MessagesDataSource.swift in Sources */,
 				AEFBE22F23FEF23D0045327A /* ProviderInfoCell.swift in Sources */,
 				AE6EC5242497663200A400E4 /* UIImageView+Extensions.swift in Sources */,
-				305961E22346125100C80F33 /* MessagesDisplayDelegate.swift in Sources */,
-				305962092346125100C80F33 /* AudioMessageSizeCalculator.swift in Sources */,
-				305961DB2346125100C80F33 /* AudioItem.swift in Sources */,
 				30F8817624DA97DA0023780E /* BackgroundContainer.swift in Sources */,
 				30B0ACFA24AB5B99004D5E29 /* SettingsEphemeralMessageController.swift in Sources */,
-				305962012346125100C80F33 /* PlayButtonView.swift in Sources */,
-				308FEA4C2462F11300FCEAD6 /* FileView.swift in Sources */,
 				B20462E42440A4A600367A57 /* SettingsAutodelOverviewController.swift in Sources */,
-				305961F32346125100C80F33 /* MediaMessageCell.swift in Sources */,
 				305962102346154D00C80F33 /* String+Extension.swift in Sources */,
-				78E45E4C21D404AE00D4B15E /* InfoMessageCell.swift in Sources */,
 				789E879621D6CB58003ED1C5 /* QrCodeReaderController.swift in Sources */,
 				305961D22346125100C80F33 /* CGRect+Extensions.swift in Sources */,
-				305961E12346125100C80F33 /* LocationItem.swift in Sources */,
-				305961E72346125100C80F33 /* AccessoryPosition.swift in Sources */,
 				3057029B24C6441300D84EFC /* EmptyStateLabel.swift in Sources */,
 				30260CA7238F02F700D8D52C /* MultilineTextFieldCell.swift in Sources */,
-				305961DE2346125100C80F33 /* MessageType.swift in Sources */,
-				305961DA2346125100C80F33 /* MediaItem.swift in Sources */,
-				305961EB2346125100C80F33 /* MessageKitError.swift in Sources */,
 				70B8882E2091B8550074812E /* ContactCell.swift in Sources */,
-				305961F82346125100C80F33 /* AudioMessageCell.swift in Sources */,
-				305961EC2346125100C80F33 /* Avatar.swift in Sources */,
 				305961CD2346125100C80F33 /* UIEdgeInsets+Extensions.swift in Sources */,
 				30EF7324252FF15F00E2C54A /* NewMessageLabel.swift in Sources */,
-				305962032346125100C80F33 /* CellSizeCalculator.swift in Sources */,
-				305961E02346125100C80F33 /* MessageLabelDelegate.swift in Sources */,
 				30C0D49D237C4908008E2A0E /* CertificateCheckController.swift in Sources */,
-				305961D92346125100C80F33 /* ContactItem.swift in Sources */,
-				305961FB2346125100C80F33 /* TypingIndicator.swift in Sources */,
 				7092474120B3869500AF8799 /* ContactDetailViewController.swift in Sources */,
-				300C50A1234BDAB800F8AE22 /* TextMediaMessageSizeCalculator.swift in Sources */,
 				30F9B9EC235F2116006E7ACF /* MessageCounter.swift in Sources */,
 				AE0AA952247800E700D42A7F /* GalleryCell.swift in Sources */,
 				AE0AA958247834A400D42A7F /* Date+Extension.swift in Sources */,
 				307D822E241669C7006D2490 /* LocationManager.swift in Sources */,
-				305961F12346125100C80F33 /* ContactMessageCell.swift in Sources */,
 				AE851AD0227DF50900ED86F0 /* GroupChatDetailViewController.swift in Sources */,
 				30FDB72124D838240066C48D /* BaseMessageCell.swift in Sources */,
-				305961D12346125100C80F33 /* Bundle+Extensions.swift in Sources */,
-				305962002346125100C80F33 /* MessagesCollectionView.swift in Sources */,
 				7A451DB01FB1F84900177250 /* AppCoordinator.swift in Sources */,
 				AE38B31822672DFC00EC37A1 /* ActionCell.swift in Sources */,
 				AE9DAF0D22C1215D004C9591 /* EditContactController.swift in Sources */,
-				305961FC2346125100C80F33 /* MessageContainerView.swift in Sources */,
-				305961D42346125100C80F33 /* MessagesViewController.swift in Sources */,
 				785BE16821E247F1003BE98C /* MessageInfoViewController.swift in Sources */,
 				AED423D3249F578B00B6B2BB /* AddGroupMembersViewController.swift in Sources */,
 				AE851AC5227C755A00ED86F0 /* Protocols.swift in Sources */,
 				AE728F15229D5C390047565B /* PhotoPickerAlertAction.swift in Sources */,
-				305961F42346125100C80F33 /* TextMessageCell.swift in Sources */,
 				AECEF03E244F2D55006C90DA /* QrPageController.swift in Sources */,
 				AEACE2E31FB32B5C00DCDD78 /* Constants.swift in Sources */,
-				305962052346125100C80F33 /* ContactMessageSizeCalculator.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 2 - 2
deltachat-ios/Chat/Views/Cells/NewImageTextCell.swift

@@ -19,8 +19,8 @@ class NewImageTextCell: BaseMessageCell {
     }()
 
     /// The play button view to display on video messages.
-    open lazy var playButtonView: PlayButtonView = {
-        let playButtonView = PlayButtonView()
+    open lazy var playButtonView: NewPlayButtonView = {
+        let playButtonView = NewPlayButtonView()
         playButtonView.isHidden = true
         translatesAutoresizingMaskIntoConstraints = false
         return playButtonView

+ 1 - 0
deltachat-ios/MessageKit/Models/DetectorType.swift → deltachat-ios/Chat/Views/DetectorType.swift

@@ -75,3 +75,4 @@ public enum DetectorType: Hashable {
     }
 
 }
+

+ 4 - 3
deltachat-ios/MessageKit/Protocols/MessageLabelDelegate.swift → deltachat-ios/Chat/Views/MessageLabelDelegate.swift

@@ -56,13 +56,13 @@ public protocol MessageLabelDelegate: AnyObject {
     /// - Parameters:
     ///   - transitInformation: The selected transit information.
     func didSelectTransitInformation(_ transitInformation: [String: String])
-    
+
     /// Triggered when a tap occurs on a mention
     ///
     /// - Parameters:
     ///   - mention: The selected mention
     func didSelectMention(_ mention: String)
-    
+
     /// Triggered when a tap occurs on a hashtag
     ///
     /// - Parameters:
@@ -87,7 +87,7 @@ public extension MessageLabelDelegate {
     func didSelectPhoneNumber(_ phoneNumber: String) {}
 
     func didSelectURL(_ url: URL) {}
-    
+
     func didSelectTransitInformation(_ transitInformation: [String: String]) {}
 
     func didSelectMention(_ mention: String) {}
@@ -97,3 +97,4 @@ public extension MessageLabelDelegate {
     func didSelectCustom(_ pattern: String, match: String?) {}
 
 }
+

+ 2 - 2
deltachat-ios/Chat/Views/NewMessageLabel.swift

@@ -300,7 +300,7 @@ open class NewMessageLabel: UILabel {
         case .hashtag:
             return hashtagAttributes
         case .custom(let regex):
-            return customAttributes[regex] ?? MessageLabel.defaultAttributes
+            return customAttributes[regex] ?? NewMessageLabel.defaultAttributes
         }
 
     }
@@ -318,7 +318,7 @@ open class NewMessageLabel: UILabel {
         case .transitInformation:
             return transitInformationAttributes
         default:
-            fatalError(MessageKitError.unrecognizedCheckingResult)
+            fatalError("link detector failure: unrecognized checking result")
         }
     }
 

+ 0 - 1527
deltachat-ios/Controller/ChatViewController.swift

@@ -1,1527 +0,0 @@
-import MapKit
-import QuickLook
-import UIKit
-import InputBarAccessoryView
-import AVFoundation
-import DcCore
-import SDWebImage
-
-extension ChatViewController: MediaPickerDelegate {
-    func onVideoSelected(url: NSURL) {
-        sendVideo(url: url)
-    }
-
-    func onImageSelected(url: NSURL) {
-        sendImage(url: url)
-    }
-
-    func onImageSelected(image: UIImage) {
-        sendImage(image)
-    }
-
-    func onVoiceMessageRecorded(url: NSURL) {
-        sendVoiceMessage(url: url)
-    }
-
-    func onDocumentSelected(url: NSURL) {
-        sendDocumentMessage(url: url)
-    }
-
-}
-
-class ChatViewController: MessagesViewController {
-    var dcContext: DcContext
-    let outgoingAvatarOverlap: CGFloat = 17.5
-    let loadCount = 30
-    let chatId: Int
-    var messageList: [DcMsg] = []
-
-    var msgChangedObserver: Any?
-    var incomingMsgObserver: Any?
-    var ephemeralTimerModifiedObserver: Any?
-
-    private lazy var refreshControl: UIRefreshControl = {
-        let refreshControl = UIRefreshControl()
-        return UIRefreshControl()
-    }()
-
-    private weak var timer: Timer?
-
-    lazy var navBarTap: UITapGestureRecognizer = {
-        UITapGestureRecognizer(target: self, action: #selector(chatProfilePressed))
-    }()
-
-    private var locationStreamingItem: UIBarButtonItem = {
-        let indicator = LocationStreamingIndicator()
-        return UIBarButtonItem(customView: indicator)
-    }()
-
-
-    private lazy var muteItem: UIBarButtonItem = {
-        let imageView = UIImageView()
-        imageView.tintColor = DcColors.defaultTextColor
-        imageView.image =  #imageLiteral(resourceName: "volume_off").withRenderingMode(.alwaysTemplate)
-        imageView.translatesAutoresizingMaskIntoConstraints = false
-        imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
-        imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
-        return UIBarButtonItem(customView: imageView)
-    }()
-
-    private lazy var ephemeralMessageItem: UIBarButtonItem = {
-        let imageView = UIImageView()
-        imageView.tintColor = DcColors.defaultTextColor
-        imageView.image =  #imageLiteral(resourceName: "ephemeral_timer").withRenderingMode(.alwaysTemplate)
-        imageView.translatesAutoresizingMaskIntoConstraints = false
-        imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
-        imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
-        return UIBarButtonItem(customView: imageView)
-    }()
-
-    private lazy var badgeItem: UIBarButtonItem = {
-        let badge: InitialsBadge
-        let chat = dcContext.getChat(chatId: chatId)
-        if let image = chat.profileImage {
-            badge = InitialsBadge(image: image, size: 28, accessibilityLabel: String.localized("menu_view_profile"))
-        } else {
-            badge = InitialsBadge(
-                name: chat.name,
-                color: chat.color,
-                size: 28,
-                accessibilityLabel: String.localized("menu_view_profile")
-            )
-            badge.setLabelFont(UIFont.systemFont(ofSize: 14))
-        }
-        badge.setVerified(chat.isProtected)
-        badge.accessibilityTraits = .button
-        return UIBarButtonItem(customView: badge)
-    }()
-
-    /// The `BasicAudioController` controll the AVAudioPlayer state (play, pause, stop) and udpate audio cell UI accordingly.
-    open lazy var audioController = BasicAudioController(messageCollectionView: messagesCollectionView)
-
-    private var disableWriting: Bool
-    private var showNamesAboveMessage: Bool
-    var showCustomNavBar = true
-
-    private lazy var mediaPicker: MediaPicker? = {
-        let mediaPicker = MediaPicker(navigationController: navigationController)
-        mediaPicker.delegate = self
-        return mediaPicker
-    }()
-
-    var emptyStateView: EmptyStateLabel = {
-        let view =  EmptyStateLabel()
-        return view
-    }()
-
-    override var inputAccessoryView: UIView? {
-        if disableWriting {
-            return nil
-        }
-        return messageInputBar
-    }
-
-    init(dcContext: DcContext, chatId: Int) {
-        let dcChat = dcContext.getChat(chatId: chatId)
-        self.dcContext = dcContext
-        self.chatId = chatId
-        self.disableWriting = !dcChat.canSend
-        self.showNamesAboveMessage = dcChat.isGroup
-        super.init(nibName: nil, bundle: nil)
-        hidesBottomBarWhenPushed = true
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    override func viewDidLoad() {
-        messagesCollectionView.register(InfoMessageCell.self)
-        super.viewDidLoad()
-        if !dcContext.isConfigured() {
-            // TODO: display message about nothing being configured
-            return
-        }
-        configureMessageCollectionView()
-        configureEmptyStateView()
-
-        if !disableWriting {
-            configureMessageInputBar()
-            messageInputBar.inputTextView.text = textDraft
-            messageInputBar.inputTextView.becomeFirstResponder()
-        }
-
-        refreshControl.addTarget(self, action: #selector(loadMoreMessages), for: .valueChanged)
-
-        let notificationCenter = NotificationCenter.default
-        notificationCenter.addObserver(self,
-                                       selector: #selector(setTextDraft),
-                                       name: UIApplication.willResignActiveNotification,
-                                       object: nil)
-    }
-
-    private func startTimer() {
-        timer?.invalidate()
-        timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { [weak self] _ in
-            //reload table
-            DispatchQueue.main.async {
-                guard let self = self else { return }
-                self.messageList = self.getMessageIds(self.messageList.count)
-                self.messagesCollectionView.reloadDataAndKeepOffset()
-                self.refreshControl.endRefreshing()
-            }
-        }
-    }
-
-    private func stopTimer() {
-        timer?.invalidate()
-    }
-
-    private func configureEmptyStateView() {
-        view.addSubview(emptyStateView)
-        emptyStateView.translatesAutoresizingMaskIntoConstraints = false
-        emptyStateView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 40).isActive = true
-        emptyStateView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -40).isActive = true
-        emptyStateView.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor).isActive = true
-    }
-
-    override func viewWillAppear(_ animated: Bool) {
-        super.viewWillAppear(animated)
-        // this will be removed in viewWillDisappear
-        navigationController?.navigationBar.addGestureRecognizer(navBarTap)
-
-        if showCustomNavBar {
-            updateTitle(chat: dcContext.getChat(chatId: chatId))
-        }
-
-        configureMessageMenu()
-
-        let nc = NotificationCenter.default
-        msgChangedObserver = nc.addObserver(
-            forName: dcNotificationChanged,
-            object: nil,
-            queue: OperationQueue.main
-        ) { [weak self] notification in
-            guard let self = self else { return }
-            if let ui = notification.userInfo {
-                if self.disableWriting {
-                    // always refresh, as we can't check currently
-                    self.refreshMessages()
-                } else if let id = ui["message_id"] as? Int {
-                    if id > 0 {
-                        self.updateMessage(id)
-                    } else {
-                        // change might be a deletion
-                        self.refreshMessages()
-                    }
-                }
-                if self.showCustomNavBar {
-                    self.updateTitle(chat: self.dcContext.getChat(chatId: self.chatId))
-                }
-            }
-        }
-
-        incomingMsgObserver = nc.addObserver(
-            forName: dcNotificationIncoming,
-            object: nil, queue: OperationQueue.main
-        ) { [weak self] notification in
-            guard let self = self else { return }
-            if let ui = notification.userInfo {
-                if self.chatId == ui["chat_id"] as? Int {
-                    if let id = ui["message_id"] as? Int {
-                        if id > 0 {
-                            self.insertMessage(DcMsg(id: id))
-                        }
-                    }
-                }
-            }
-        }
-
-        ephemeralTimerModifiedObserver = nc.addObserver(
-            forName: dcEphemeralTimerModified,
-            object: nil, queue: OperationQueue.main
-        ) { [weak self] _ in
-            guard let self = self else { return }
-            self.updateTitle(chat: self.dcContext.getChat(chatId: self.chatId))
-        }
-
-        loadFirstMessages()
-
-        if RelayHelper.sharedInstance.isForwarding() {
-            askToForwardMessage()
-        }
-    }
-
-    override func viewDidAppear(_ animated: Bool) {
-        super.viewDidAppear(animated)
-        AppStateRestorer.shared.storeLastActiveChat(chatId: chatId)
-        // things that do not affect the chatview
-        // and are delayed after the view is displayed
-        dcContext.marknoticedChat(chatId: chatId)
-        let array = dcContext.getFreshMessages()
-        UIApplication.shared.applicationIconBadgeNumber = array.count
-        startTimer()
-    }
-
-    override func viewWillDisappear(_ animated: Bool) {
-        super.viewWillDisappear(animated)
-
-        // the navigationController will be used when chatDetail is pushed, so we have to remove that gestureRecognizer
-        navigationController?.navigationBar.removeGestureRecognizer(navBarTap)
-    }
-
-    override func viewDidDisappear(_ animated: Bool) {
-        super.viewDidDisappear(animated)
-        AppStateRestorer.shared.resetLastActiveChat()
-        setTextDraft()
-        let nc = NotificationCenter.default
-        if let msgChangedObserver = self.msgChangedObserver {
-            nc.removeObserver(msgChangedObserver)
-        }
-        if let incomingMsgObserver = self.incomingMsgObserver {
-            nc.removeObserver(incomingMsgObserver)
-        }
-        if let ephemeralTimerModifiedObserver = self.ephemeralTimerModifiedObserver {
-            nc.removeObserver(ephemeralTimerModifiedObserver)
-        }
-        audioController.stopAnyOngoingPlaying()
-        stopTimer()
-    }
-
-    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
-        let lastSectionVisibleBeforeTransition = self.isLastSectionVisible()
-        coordinator.animate(
-            alongsideTransition: { [weak self] _ in
-                guard let self = self else { return }
-                if self.showCustomNavBar {
-                    self.navigationItem.setRightBarButton(self.badgeItem, animated: true)
-                }
-            },
-            completion: {[weak self] _ in
-                guard let self = self else { return }
-                self.updateTitle(chat: self.dcContext.getChat(chatId: self.chatId))
-                self.messagesCollectionView.reloadDataAndKeepOffset()
-                if lastSectionVisibleBeforeTransition {
-                    self.messagesCollectionView.scrollToBottom(animated: false)
-                }
-            }
-        )
-        super.viewWillTransition(to: size, with: coordinator)
-    }
-
-    private func updateTitle(chat: DcChat) {
-        let titleView =  ChatTitleView()
-
-        var subtitle = "ErrSubtitle"
-        let chatContactIds = chat.contactIds
-        if chat.isGroup {
-            subtitle = String.localized(stringID: "n_members", count: chatContactIds.count)
-        } else if chatContactIds.count >= 1 {
-            if chat.isDeviceTalk {
-                subtitle = String.localized("device_talk_subtitle")
-            } else if chat.isSelfTalk {
-                subtitle = String.localized("chat_self_talk_subtitle")
-            } else {
-                subtitle = DcContact(id: chatContactIds[0]).email
-            }
-        }
-        
-        titleView.updateTitleView(title: chat.name, subtitle: subtitle)
-        navigationItem.titleView = titleView
-
-        var rightBarButtonItems = [badgeItem]
-        if chat.isSendingLocations {
-            rightBarButtonItems.append(locationStreamingItem)
-        }
-        if chat.isMuted {
-            rightBarButtonItems.append(muteItem)
-        }
-
-        if dcContext.getChatEphemeralTimer(chatId: chat.id) > 0 {
-            rightBarButtonItems.append(ephemeralMessageItem)
-        }
-
-        navigationItem.rightBarButtonItems = rightBarButtonItems
-    }
-
-    @objc
-    private func loadMoreMessages() {
-        DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) {
-            DispatchQueue.main.async { [weak self] in
-                guard let self = self else { return }
-                self.messageList = self.getMessageIds(self.loadCount, from: self.messageList.count) + self.messageList
-                self.messagesCollectionView.reloadDataAndKeepOffset()
-                self.refreshControl.endRefreshing()
-            }
-        }
-    }
-
-    @objc
-    private func refreshMessages() {
-        DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 1) {
-            DispatchQueue.main.async { [weak self] in
-                guard let self = self else { return }
-                self.messageList = self.getMessageIds(self.messageList.count)
-                self.messagesCollectionView.reloadDataAndKeepOffset()
-                self.refreshControl.endRefreshing()
-                if self.isLastSectionVisible() {
-                    self.messagesCollectionView.scrollToBottom(animated: true)
-                }
-                self.showEmptyStateView(self.messageList.isEmpty)
-            }
-        }
-    }
-
-    private func loadFirstMessages() {
-        DispatchQueue.global(qos: .userInitiated).async {
-            DispatchQueue.main.async { [weak self] in
-                guard let self = self else { return }
-                self.messageList = self.getMessageIds(self.loadCount)
-                self.messagesCollectionView.reloadData()
-                self.refreshControl.endRefreshing()
-                self.messagesCollectionView.scrollToBottom(animated: false)
-                self.showEmptyStateView(self.messageList.isEmpty)
-            }
-        }
-    }
-
-    private func showEmptyStateView(_ show: Bool) {
-        if show {
-            let dcChat = dcContext.getChat(chatId: chatId)
-            if chatId == DC_CHAT_ID_DEADDROP {
-                if dcContext.showEmails != DC_SHOW_EMAILS_ALL {
-                    emptyStateView.text = String.localized("chat_no_contact_requests")
-                } else {
-                    emptyStateView.text = String.localized("chat_no_messages")
-                }
-            } else if dcChat.isGroup {
-                if dcChat.isUnpromoted {
-                    emptyStateView.text = String.localized("chat_new_group_hint")
-                } else {
-                    emptyStateView.text = String.localized("chat_no_messages")
-                }
-            } else if dcChat.isSelfTalk {
-                emptyStateView.text = String.localized("saved_messages_explain")
-            } else if dcChat.isDeviceTalk {
-                emptyStateView.text = String.localized("device_talk_explain")
-            } else {
-                emptyStateView.text = String.localizedStringWithFormat(String.localized("chat_no_messages_hint"), dcChat.name, dcChat.name)
-            }
-            emptyStateView.isHidden = false
-        } else {
-            emptyStateView.isHidden = true
-        }
-    }
-
-    private var textDraft: String? {
-        return dcContext.getDraft(chatId: chatId)
-    }
-
-    private func getMessageIds(_ count: Int, from: Int? = nil) -> [DcMsg] {
-        let ids = dcContext.getMessageIds(chatId: chatId, count: count, from: from)
-        let markIds: [UInt32] = ids.map { UInt32($0) }
-        dcContext.markSeenMessages(messageIds: markIds, count: ids.count)
-
-        return ids.map {
-            DcMsg(id: $0)
-        }
-    }
-
-    @objc private func setTextDraft() {
-        if let text = self.messageInputBar.inputTextView.text {
-            dcContext.setDraft(chatId: chatId, draftText: text)
-        }
-    }
-
-    private func configureMessageMenu() {
-        var menuItems: [UIMenuItem]
-
-        menuItems = [
-            UIMenuItem(title: String.localized("info"), action: #selector(MessageCollectionViewCell.messageInfo(_:))),
-            UIMenuItem(title: String.localized("delete"), action: #selector(MessageCollectionViewCell.messageDelete(_:))),
-            UIMenuItem(title: String.localized("forward"), action: #selector(MessageCollectionViewCell.messageForward(_:)))
-        ]
-
-        UIMenuController.shared.menuItems = menuItems
-    }
-
-    private func configureMessageCollectionView() {
-        messagesCollectionView.messagesDataSource = self
-        messagesCollectionView.messageCellDelegate = self
-
-        scrollsToBottomOnKeyboardBeginsEditing = true // default false
-        maintainPositionOnKeyboardFrameChanged = true // default false
-        messagesCollectionView.backgroundColor = DcColors.chatBackgroundColor
-        messagesCollectionView.addSubview(refreshControl)
-
-        let layout = messagesCollectionView.collectionViewLayout as? MessagesCollectionViewFlowLayout
-        layout?.sectionInset = UIEdgeInsets(top: 0, left: 8, bottom: 2, right: 8)
-
-        // Hide the outgoing avatar and adjust the label alignment to line up with the messages
-        layout?.setMessageOutgoingAvatarSize(.zero)
-        layout?.setMessageOutgoingMessageTopLabelAlignment(LabelAlignment(textAlignment: .right,
-            textInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 8)))
-        layout?.setMessageOutgoingMessageBottomLabelAlignment(LabelAlignment(textAlignment: .right,
-            textInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 8)))
-
-        // Set outgoing avatar to overlap with the message bubble
-        layout?.setMessageIncomingMessageTopLabelAlignment(LabelAlignment(textAlignment: .left,
-            textInsets: UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 0)))
-        layout?.setMessageIncomingAvatarSize(CGSize(width: 30, height: 30))
-        layout?.setMessageIncomingMessagePadding(UIEdgeInsets(
-            top: 0, left: -18, bottom: 0, right: 0))
-        layout?.setMessageIncomingMessageBottomLabelAlignment(LabelAlignment(textAlignment: .left,
-            textInsets: UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 0)))
-
-        layout?.setMessageIncomingAccessoryViewSize(CGSize(width: 30, height: 30))
-        layout?.setMessageIncomingAccessoryViewPadding(HorizontalEdgeInsets(left: 8, right: 0))
-        layout?.setMessageOutgoingAccessoryViewSize(CGSize(width: 30, height: 30))
-        layout?.setMessageOutgoingAccessoryViewPadding(HorizontalEdgeInsets(left: 0, right: 8))
-
-        messagesCollectionView.messagesLayoutDelegate = self
-        messagesCollectionView.messagesDisplayDelegate = self
-    }
-
-    private func configureMessageInputBar() {
-        messageInputBar.delegate = self
-        messageInputBar.inputTextView.tintColor = DcColors.primary
-        messageInputBar.inputTextView.placeholder = String.localized("chat_input_placeholder")
-        messageInputBar.separatorLine.isHidden = true
-        messageInputBar.inputTextView.tintColor = DcColors.primary
-        messageInputBar.inputTextView.textColor = DcColors.defaultTextColor
-        messageInputBar.backgroundView.backgroundColor = DcColors.chatBackgroundColor
-
-        scrollsToBottomOnKeyboardBeginsEditing = true
-
-        messageInputBar.inputTextView.backgroundColor = DcColors.inputFieldColor
-        messageInputBar.inputTextView.placeholderTextColor = DcColors.placeholderColor
-        messageInputBar.inputTextView.textContainerInset = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 38)
-        messageInputBar.inputTextView.placeholderLabelInsets = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 38)
-        messageInputBar.inputTextView.layer.borderColor = UIColor.themeColor(light: UIColor(red: 200 / 255, green: 200 / 255, blue: 200 / 255, alpha: 1),
-                                                                             dark: UIColor(red: 55 / 255, green: 55/255, blue: 55/255, alpha: 1)).cgColor
-        messageInputBar.inputTextView.layer.borderWidth = 1.0
-        messageInputBar.inputTextView.layer.cornerRadius = 13.0
-        messageInputBar.inputTextView.layer.masksToBounds = true
-        messageInputBar.inputTextView.scrollIndicatorInsets = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
-        configureInputBarItems()
-    }
-
-    private func configureInputBarItems() {
-
-        messageInputBar.setLeftStackViewWidthConstant(to: 40, animated: false)
-        messageInputBar.setRightStackViewWidthConstant(to: 40, animated: false)
-
-
-        let sendButtonImage = UIImage(named: "paper_plane")?.withRenderingMode(.alwaysTemplate)
-        messageInputBar.sendButton.image = sendButtonImage
-        messageInputBar.sendButton.accessibilityLabel = String.localized("menu_send")
-        messageInputBar.sendButton.accessibilityTraits = .button
-        messageInputBar.sendButton.title = nil
-        messageInputBar.sendButton.tintColor = UIColor(white: 1, alpha: 1)
-        messageInputBar.sendButton.layer.cornerRadius = 20
-        messageInputBar.middleContentViewPadding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)
-        // this adds a padding between textinputfield and send button
-        messageInputBar.sendButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
-        messageInputBar.sendButton.setSize(CGSize(width: 40, height: 40), animated: false)
-        messageInputBar.padding = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 12)
-
-        let leftItems = [
-            InputBarButtonItem()
-                .configure {
-                    $0.spacing = .fixed(0)
-                    let clipperIcon = #imageLiteral(resourceName: "ic_attach_file_36pt").withRenderingMode(.alwaysTemplate)
-                    $0.image = clipperIcon
-                    $0.tintColor = DcColors.primary
-                    $0.setSize(CGSize(width: 40, height: 40), animated: false)
-                    $0.accessibilityLabel = String.localized("menu_add_attachment")
-                    $0.accessibilityTraits = .button
-                }.onSelected {
-                    $0.tintColor = UIColor.themeColor(light: .lightGray, dark: .darkGray)
-                }.onDeselected {
-                    $0.tintColor = DcColors.primary
-                }.onTouchUpInside { [weak self] _ in
-                    self?.clipperButtonPressed()
-                }
-        ]
-
-        messageInputBar.setStackViewItems(leftItems, forStack: .left, animated: false)
-
-        // This just adds some more flare
-        messageInputBar.sendButton
-            .onEnabled { item in
-                UIView.animate(withDuration: 0.3, animations: {
-                    item.backgroundColor = DcColors.primary
-                })
-            }.onDisabled { item in
-                UIView.animate(withDuration: 0.3, animations: {
-                    item.backgroundColor = DcColors.colorDisabled
-                })
-            }
-    }
-
-    @objc private func chatProfilePressed() {
-        if chatId != DC_CHAT_ID_DEADDROP {
-            showChatDetail(chatId: chatId)
-        }
-    }
-
-    // MARK: - UICollectionViewDataSource
-    public override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError("notMessagesCollectionView")
-        }
-
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError("nilMessagesDataSource")
-        }
-
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-        switch message.kind {
-        case .text, .attributedText, .emoji:
-            let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .info:
-            let cell = messagesCollectionView.dequeueReusableCell(InfoMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .photo, .video:
-            let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .photoText, .videoText:
-            let cell = messagesCollectionView.dequeueReusableCell(TextMediaMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .animatedImageText:
-            let cell = messagesCollectionView.dequeueReusableCell(AnimatedImageMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .fileText:
-            let cell = messagesCollectionView.dequeueReusableCell(FileMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .location:
-            let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .contact:
-            let cell = messagesCollectionView.dequeueReusableCell(ContactMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .custom:
-            let cell = messagesCollectionView.dequeueReusableCell(InfoMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .audio:
-            let cell = messagesCollectionView.dequeueReusableCell(AudioMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        }
-    }
-
-    override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
-        if action == NSSelectorFromString("messageInfo:") ||
-            action == NSSelectorFromString("messageDelete:") ||
-            action == NSSelectorFromString("messageForward:") {
-            return true
-        } else {
-            return super.collectionView(collectionView, canPerformAction: action, forItemAt: indexPath, withSender: sender)
-        }
-    }
-
-    override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
-        switch action {
-        case NSSelectorFromString("messageInfo:"):
-            let msg = messageList[indexPath.section]
-            logger.info("message: View info \(msg.messageId)")
-
-            let msgViewController = MessageInfoViewController(dcContext: dcContext, message: msg)
-            if let ctrl = navigationController {
-                ctrl.pushViewController(msgViewController, animated: true)
-            }
-        case NSSelectorFromString("messageDelete:"):
-            let msg = messageList[indexPath.section]
-            logger.info("message: delete \(msg.messageId)")
-            askToDeleteMessage(id: msg.id)
-
-        case NSSelectorFromString("messageForward:"):
-            let msg = messageList[indexPath.section]
-            RelayHelper.sharedInstance.setForwardMessage(messageId: msg.id)
-            navigationController?.popViewController(animated: true)
-        default:
-            super.collectionView(collectionView, performAction: action, forItemAt: indexPath, withSender: sender)
-        }
-    }
-
-    private func confirmationAlert(title: String, actionTitle: String, actionStyle: UIAlertAction.Style = .default, actionHandler: @escaping ((UIAlertAction) -> Void), cancelHandler: ((UIAlertAction) -> Void)? = nil) {
-        let alert = UIAlertController(title: title,
-                                             message: nil,
-                                             preferredStyle: .safeActionSheet)
-               alert.addAction(UIAlertAction(title: actionTitle, style: actionStyle, handler: actionHandler))
-
-               alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: cancelHandler ?? { _ in
-                   self.dismiss(animated: true, completion: nil)
-               }))
-               present(alert, animated: true, completion: nil)
-    }
-
-    private func askToChatWith(email: String) {
-        let contactId = self.dcContext.createContact(name: "", email: email)
-        if dcContext.getChatIdByContactId(contactId: contactId) != 0 {
-            self.dismiss(animated: true, completion: nil)
-            let chatId = self.dcContext.createChatByContactId(contactId: contactId)
-            self.showChat(chatId: chatId)
-        } else {
-            confirmationAlert(title: String.localizedStringWithFormat(String.localized("ask_start_chat_with"), email),
-                              actionTitle: String.localized("start_chat"),
-                              actionHandler: { _ in
-                                self.dismiss(animated: true, completion: nil)
-                                let chatId = self.dcContext.createChatByContactId(contactId: contactId)
-                                self.showChat(chatId: chatId)})
-        }
-    }
-
-    private func askToDeleteMessage(id: Int) {
-        let title = String.localized(stringID: "ask_delete_messages", count: 1)
-        confirmationAlert(title: title, actionTitle: String.localized("delete"), actionStyle: .destructive,
-                          actionHandler: { _ in
-                            self.dcContext.deleteMessage(msgId: id)
-                            self.dismiss(animated: true, completion: nil)})
-    }
-
-    private func askToForwardMessage() {
-        let chat = dcContext.getChat(chatId: self.chatId)
-        if chat.isSelfTalk {
-            RelayHelper.sharedInstance.forward(to: self.chatId)
-        } else {
-            confirmationAlert(title: String.localizedStringWithFormat(String.localized("ask_forward"), chat.name),
-                          actionTitle: String.localized("menu_forward"),
-                          actionHandler: { _ in
-                            RelayHelper.sharedInstance.forward(to: self.chatId)
-                            self.dismiss(animated: true, completion: nil)},
-                          cancelHandler: { _ in
-                            self.dismiss(animated: false, completion: nil)
-                            self.navigationController?.popViewController(animated: true)})
-        }
-    }
-
-    // MARK: - coordinator
-    private func showChatDetail(chatId: Int) {
-        let chat = dcContext.getChat(chatId: chatId)
-        switch chat.chatType {
-        case .SINGLE:
-            if let contactId = chat.contactIds.first {
-                let contactDetailController = ContactDetailViewController(dcContext: dcContext, contactId: contactId)
-                navigationController?.pushViewController(contactDetailController, animated: true)
-            }
-        case .GROUP, .VERIFIEDGROUP:
-            let groupChatDetailViewController = GroupChatDetailViewController(chatId: chatId, dcContext: dcContext)
-            navigationController?.pushViewController(groupChatDetailViewController, animated: true)
-        }
-    }
-
-    private func showContactDetail(of contactId: Int, in chatOfType: ChatType, chatId: Int?) {
-        let contactDetailController = ContactDetailViewController(dcContext: dcContext, contactId: contactId)
-        navigationController?.pushViewController(contactDetailController, animated: true)
-    }
-
-    func showChat(chatId: Int) {
-        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
-            navigationController?.popToRootViewController(animated: false)
-            appDelegate.appCoordinator.showChat(chatId: chatId)
-        }
-    }
-
-    private func showDocumentLibrary() {
-        mediaPicker?.showDocumentLibrary()
-    }
-
-    private func showVoiceMessageRecorder() {
-        mediaPicker?.showVoiceRecorder()
-    }
-
-    private func showCameraViewController() {
-       mediaPicker?.showCamera()
-    }
-
-    private func showPhotoVideoLibrary(delegate: MediaPickerDelegate) {
-        mediaPicker?.showPhotoVideoLibrary()
-    }
-
-    private func showMediaGallery(currentIndex: Int, msgIds: [Int]) {
-        let betterPreviewController = PreviewController(type: .multi(msgIds, currentIndex))
-        let nav = UINavigationController(rootViewController: betterPreviewController)
-        nav.modalPresentationStyle = .fullScreen
-        navigationController?.present(nav, animated: true)
-    }
-}
-
-// MARK: - MessagesDataSource
-extension ChatViewController: MessagesDataSource {
-
-    func numberOfSections(in _: MessagesCollectionView) -> Int {
-        return messageList.count
-    }
-
-    func currentSender() -> SenderType {
-        let currentSender = Sender(senderId: "1", displayName: "Alice")
-        return currentSender
-    }
-
-    func messageForItem(at indexPath: IndexPath, in _: MessagesCollectionView) -> MessageType {
-        return messageList[indexPath.section]
-    }
-
-    func avatar(for message: MessageType, at indexPath: IndexPath, in _: MessagesCollectionView) -> Avatar {
-        let message = messageList[indexPath.section]
-        let contact = message.fromContact
-        return Avatar(image: contact.profileImage, initials: DcUtils.getInitials(inputName: contact.displayName))
-    }
-
-    func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        if isInfoMessage(at: indexPath) {
-            return nil
-        }
-
-        if isTimeLabelVisible(at: indexPath) {
-            return NSAttributedString(
-                string: MessageKitDateFormatter.shared.string(from: message.sentDate),
-                attributes: [
-                    NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 10),
-                    NSAttributedString.Key.foregroundColor: DcColors.grayTextColor,
-                ]
-            )
-        }
-
-        return nil
-    }
-
-    func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        var attributedString: NSMutableAttributedString?
-
-        if showNamesAboveMessage && !isPreviousMessageSameSender(at: indexPath) {
-            let name = message.sender.displayName
-            let m = messageList[indexPath.section]
-            attributedString = NSMutableAttributedString(string: name, attributes: [
-                .font: UIFont.systemFont(ofSize: 14),
-                .foregroundColor: m.fromContact.color,
-            ])
-        }
-
-        if isMessageForwarded(at: indexPath) {
-            let forwardedString = NSMutableAttributedString(string: String.localized("forwarded_message"), attributes: [
-                .font: UIFont.systemFont(ofSize: 14),
-                .foregroundColor: DcColors.grayTextColor,
-            ])
-            if attributedString == nil {
-                attributedString = forwardedString
-            } else {
-                attributedString?.append(NSAttributedString(string: "\n", attributes: nil))
-                attributedString?.append(forwardedString)
-            }
-        }
-
-        return attributedString
-    }
-
-    func isMessageForwarded(at indexPath: IndexPath) -> Bool {
-        let m = messageList[indexPath.section]
-        return m.isForwarded
-    }
-
-    func isTimeLabelVisible(at indexPath: IndexPath) -> Bool {
-        guard indexPath.section + 1 < messageList.count else { return false }
-
-        let messageA = messageList[indexPath.section]
-        let messageB = messageList[indexPath.section + 1]
-
-        if messageA.fromContactId == messageB.fromContactId {
-            return false
-        }
-
-        let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)
-        let dateA = messageA.sentDate
-        let dateB = messageB.sentDate
-
-        let dayA = (calendar?.component(.day, from: dateA))
-        let dayB = (calendar?.component(.day, from: dateB))
-
-        return dayA != dayB
-    }
-
-    func isPreviousMessageSameSender(at indexPath: IndexPath) -> Bool {
-        guard indexPath.section - 1 >= 0 else { return false }
-        let messageA = messageList[indexPath.section - 1]
-        let messageB = messageList[indexPath.section]
-
-        if messageA.isInfo {
-            return false
-        }
-
-        return messageA.fromContactId == messageB.fromContactId
-    }
-
-    func isInfoMessage(at indexPath: IndexPath) -> Bool {
-        return messageList[indexPath.section].isInfo
-    }
-
-    func isImmediateNextMessageSameSender(at indexPath: IndexPath) -> Bool {
-        guard indexPath.section + 1 < messageList.count else { return false }
-        let messageA = messageList[indexPath.section]
-        let messageB = messageList[indexPath.section + 1]
-
-        if messageA.isInfo {
-            return false
-        }
-
-        let dateA = messageA.sentDate
-        let dateB = messageB.sentDate
-
-        let timeinterval = dateB.timeIntervalSince(dateA)
-        let minute = 60.0
-
-        return messageA.fromContactId == messageB.fromContactId && timeinterval.isLessThanOrEqualTo(minute)
-
-    }
-
-    func isAvatarHidden(at indexPath: IndexPath) -> Bool {
-        let message = messageList[indexPath.section]
-        return isNextMessageSameSender(at: indexPath) || message.isInfo
-    }
-
-    func isNextMessageSameSender(at indexPath: IndexPath) -> Bool {
-        guard indexPath.section + 1 < messageList.count else { return false }
-        let messageA = messageList[indexPath.section]
-        let messageB = messageList[indexPath.section + 1]
-
-        if messageA.isInfo {
-            return false
-        }
-
-        return messageA.fromContactId == messageB.fromContactId
-    }
-
-    func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        guard indexPath.section < messageList.count else { return nil }
-        let m = messageList[indexPath.section]
-
-        if m.isInfo || isImmediateNextMessageSameSender(at: indexPath) {
-            return nil
-        }
-
-        var timestampAttributes: [NSAttributedString.Key: Any] = [
-            .font: UIFont.systemFont(ofSize: 12),
-            .foregroundColor: DcColors.grayDateColor,
-            .paragraphStyle: NSParagraphStyle()
-        ]
-
-        let text = NSMutableAttributedString()
-        if isFromCurrentSender(message: message) {
-            if let style = NSMutableParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle {
-                style.alignment = .right
-                timestampAttributes[.paragraphStyle] = style
-            }
-
-            text.append(NSAttributedString(string: m.formattedSentDate(), attributes: timestampAttributes))
-
-            if m.showPadlock() {
-                attachPadlock(to: text)
-            }
-
-            attachSendingState(m.state, to: text)
-            return text
-        }
-
-        if !isAvatarHidden(at: indexPath) {
-            if let style = NSMutableParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle {
-                style.firstLineHeadIndent = 22
-                timestampAttributes[.paragraphStyle] = style
-            }
-        }
-
-        text.append(NSAttributedString(string: m.formattedSentDate(), attributes: timestampAttributes))
-        if m.showPadlock() {
-            attachPadlock(to: text)
-        }
-        return text
-    }
-
-    private func attachPadlock(to text: NSMutableAttributedString) {
-        let imageAttachment = NSTextAttachment()
-        imageAttachment.image = UIImage(named: "ic_lock")
-        imageAttachment.image?.accessibilityIdentifier = String.localized("encrypted_message")
-        let imageString = NSMutableAttributedString(attachment: imageAttachment)
-        imageString.addAttributes([NSAttributedString.Key.baselineOffset: -1], range: NSRange(location: 0, length: 1))
-        text.append(NSAttributedString(string: " "))
-        text.append(imageString)
-    }
-
-    private func attachSendingState(_ state: Int, to text: NSMutableAttributedString) {
-        let imageAttachment = NSTextAttachment()
-        var offset = -4
-
-
-        switch Int32(state) {
-        case DC_STATE_OUT_PENDING, DC_STATE_OUT_PREPARING:
-            imageAttachment.image = #imageLiteral(resourceName: "ic_hourglass_empty_white_36pt").scaleDownImage(toMax: 16)?.maskWithColor(color: DcColors.grayDateColor)
-            imageAttachment.image?.accessibilityIdentifier = String.localized("a11y_delivery_status_sending")
-            offset = -2
-        case DC_STATE_OUT_DELIVERED:
-            imageAttachment.image = #imageLiteral(resourceName: "ic_done_36pt").scaleDownImage(toMax: 18)
-            imageAttachment.image?.accessibilityIdentifier = String.localized("a11y_delivery_status_delivered")
-        case DC_STATE_OUT_MDN_RCVD:
-            imageAttachment.image = #imageLiteral(resourceName: "ic_done_all_36pt").scaleDownImage(toMax: 18)
-            imageAttachment.image?.accessibilityIdentifier = String.localized("a11y_delivery_status_read")
-            text.append(NSAttributedString(string: " "))
-        case DC_STATE_OUT_FAILED:
-            imageAttachment.image = #imageLiteral(resourceName: "ic_error_36pt").scaleDownImage(toMax: 16)
-            imageAttachment.image?.accessibilityIdentifier = String.localized("a11y_delivery_status_error")
-            offset = -2
-        default:
-            imageAttachment.image = nil
-        }
-
-        let imageString = NSMutableAttributedString(attachment: imageAttachment)
-        imageString.addAttributes([.baselineOffset: offset],
-                                  range: NSRange(location: 0, length: 1))
-        text.append(imageString)
-    }
-
-    func updateMessage(_ messageId: Int) {
-        if let index = messageList.firstIndex(where: { $0.id == messageId }) {
-            dcContext.markSeenMessages(messageIds: [UInt32(messageId)])
-
-            messageList[index] = DcMsg(id: messageId)
-            // Reload section to update header/footer labels
-            messagesCollectionView.performBatchUpdates({ [weak self] in
-                guard let self = self else { return }
-                self.messagesCollectionView.reloadSections([index])
-                if index > 0 {
-                    self.messagesCollectionView.reloadSections([index - 1])
-                }
-                if index < messageList.count - 1 {
-                    self.messagesCollectionView.reloadSections([index + 1])
-                }
-            }, completion: { [weak self] _ in
-                if self?.isLastSectionVisible() == true {
-                    self?.messagesCollectionView.scrollToBottom(animated: true)
-                }
-            })
-        } else {
-            let msg = DcMsg(id: messageId)
-            if msg.chatId == chatId {
-                insertMessage(msg)
-            }
-        }
-    }
-
-    func insertMessage(_ message: DcMsg) {
-        dcContext.markSeenMessages(messageIds: [UInt32(message.id)])
-        messageList.append(message)
-        emptyStateView.isHidden = true
-        // Reload last section to update header/footer labels and insert a new one
-        messagesCollectionView.performBatchUpdates({
-            messagesCollectionView.insertSections([messageList.count - 1])
-            if messageList.count >= 2 {
-                messagesCollectionView.reloadSections([messageList.count - 2])
-            }
-        }, completion: { [weak self] _ in
-            if self?.isLastSectionVisible() == true {
-                self?.messagesCollectionView.scrollToBottom(animated: true)
-            }
-        })
-    }
-
-    private func sendTextMessage(message: String) {
-        DispatchQueue.global().async {
-            self.dcContext.sendTextInChat(id: self.chatId, message: message)
-        }
-    }
-
-    private func sendImage(_ image: UIImage, message: String? = nil) {
-        DispatchQueue.global().async {
-            if let path = DcUtils.saveImage(image: image) {
-                self.sendImageMessage(viewType: DC_MSG_IMAGE, image: image, filePath: path)
-            }
-        }
-    }
-
-    private func sendAnimatedImage(url: NSURL) {
-        if let path = url.path {
-            let result = SDAnimatedImage(contentsOfFile: path)
-            if let result = result,
-               let animatedImageData = result.animatedImageData,
-               let pathInDocDir = DcUtils.saveImage(data: animatedImageData, suffix: "gif") {
-                self.sendImageMessage(viewType: DC_MSG_GIF, image: result, filePath: pathInDocDir)
-            }
-        }
-    }
-
-    private func sendImageMessage(viewType: Int32, image: UIImage, filePath: String, message: String? = nil) {
-        let msg = DcMsg(viewType: viewType)
-        msg.setFile(filepath: filePath)
-        msg.text = (message ?? "").isEmpty ? nil : message
-        msg.sendInChat(id: self.chatId)
-    }
-
-    private func sendDocumentMessage(url: NSURL) {
-        DispatchQueue.global().async {
-            let msg = DcMsg(viewType: DC_MSG_FILE)
-            msg.setFile(filepath: url.relativePath, mimeType: nil)
-            msg.sendInChat(id: self.chatId)
-        }
-    }
-
-    private func sendVoiceMessage(url: NSURL) {
-        DispatchQueue.global().async {
-            let msg = DcMsg(viewType: DC_MSG_VOICE)
-            msg.setFile(filepath: url.relativePath, mimeType: "audio/m4a")
-            msg.sendInChat(id: self.chatId)
-        }
-    }
-
-    private func sendVideo(url: NSURL) {
-        DispatchQueue.global().async {
-            let msg = DcMsg(viewType: DC_MSG_VIDEO)
-            msg.setFile(filepath: url.relativePath, mimeType: "video/mp4")
-            msg.sendInChat(id: self.chatId)
-        }
-    }
-
-    private func sendImage(url: NSURL) {
-        if url.pathExtension == "gif" {
-            sendAnimatedImage(url: url)
-        } else if let data = try? Data(contentsOf: url as URL),
-                  let image = UIImage(data: data) {
-            sendImage(image)
-        }
-    }
-
-    func isLastSectionVisible() -> Bool {
-        guard !messageList.isEmpty else { return false }
-
-        let lastIndexPath = IndexPath(item: 0, section: messageList.count - 1)
-        return messagesCollectionView.indexPathsForVisibleItems.contains(lastIndexPath)
-    }
-}
-
-// MARK: - MessagesDisplayDelegate
-extension ChatViewController: MessagesDisplayDelegate {
-    // MARK: - Text Messages
-    func textColor(for _: MessageType, at _: IndexPath, in _: MessagesCollectionView) -> UIColor {
-        return DcColors.defaultTextColor
-    }
-
-    // MARK: - All Messages
-    func backgroundColor(for message: MessageType, at _: IndexPath, in _: MessagesCollectionView) -> UIColor {
-        return isFromCurrentSender(message: message) ? DcColors.messagePrimaryColor : DcColors.messageSecondaryColor
-    }
-
-    func messageStyle(for message: MessageType, at indexPath: IndexPath, in _: MessagesCollectionView) -> MessageStyle {
-        if isInfoMessage(at: indexPath) {
-            //styling is hard-coded in info cell
-            return .none
-        }
-
-        var corners: UIRectCorner = []
-
-        if isFromCurrentSender(message: message) {
-            corners.formUnion(.topLeft)
-            corners.formUnion(.bottomLeft)
-            if !isPreviousMessageSameSender(at: indexPath) {
-                corners.formUnion(.topRight)
-            }
-            if !isNextMessageSameSender(at: indexPath) {
-                corners.formUnion(.bottomRight)
-            }
-        } else {
-            corners.formUnion(.topRight)
-            corners.formUnion(.bottomRight)
-            if !isPreviousMessageSameSender(at: indexPath) {
-                corners.formUnion(.topLeft)
-            }
-            if !isNextMessageSameSender(at: indexPath) {
-                corners.formUnion(.bottomLeft)
-            }
-        }
-
-        return .custom { view in
-            let radius: CGFloat = 16
-            let path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
-            let mask = CAShapeLayer()
-            mask.path = path.cgPath
-            view.layer.mask = mask
-        }
-    }
-
-    func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in _: MessagesCollectionView) {
-        let message = messageList[indexPath.section]
-        let contact = message.fromContact
-        let avatar = Avatar(image: contact.profileImage, initials: DcUtils.getInitials(inputName: contact.displayName))
-        avatarView.set(avatar: avatar)
-        avatarView.isHidden = isAvatarHidden(at: indexPath)
-        avatarView.backgroundColor = contact.color
-    }
-
-    func enabledDetectors(for _: MessageType, at _: IndexPath, in _: MessagesCollectionView) -> [DetectorType] {
-        return [.url, .phoneNumber]
-    }
-
-    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedString.Key: Any] {
-        return  [ NSAttributedString.Key.foregroundColor: DcColors.defaultTextColor,
-                  NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue,
-                  NSAttributedString.Key.underlineColor: DcColors.defaultTextColor ]
-    }
-
-}
-
-// MARK: - MessagesLayoutDelegate
-extension ChatViewController: MessagesLayoutDelegate {
-
-    func cellTopLabelHeight(for _: MessageType, at indexPath: IndexPath, in _: MessagesCollectionView) -> CGFloat {
-        if isTimeLabelVisible(at: indexPath) {
-            return 18
-        }
-        return 0
-    }
-
-    func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in _: MessagesCollectionView) -> CGFloat {
-        if isInfoMessage(at: indexPath) {
-            return 0
-        }
-
-        if !isPreviousMessageSameSender(at: indexPath) {
-            return 40
-        } else if isMessageForwarded(at: indexPath) {
-            return 20
-        }
-
-        return 0
-    }
-
-    func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in _: MessagesCollectionView) -> CGFloat {
-        if isInfoMessage(at: indexPath) {
-            return 0
-        }
-
-        if !isImmediateNextMessageSameSender(at: indexPath) {
-            return 16
-        }
-
-        return 0
-    }
-
-    func heightForLocation(message _: MessageType, at _: IndexPath, with _: CGFloat, in _: MessagesCollectionView) -> CGFloat {
-        return 40
-    }
-
-    func footerViewSize(for _: MessageType, at _: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        return CGSize(width: messagesCollectionView.bounds.width, height: 20)
-    }
-
-    @objc private func clipperButtonPressed() {
-        showClipperOptions()
-    }
-
-    private func showClipperOptions() {
-        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .safeActionSheet)
-        let galleryAction = PhotoPickerAlertAction(title: String.localized("gallery"), style: .default, handler: galleryButtonPressed(_:))
-        let cameraAction = PhotoPickerAlertAction(title: String.localized("camera"), style: .default, handler: cameraButtonPressed(_:))
-        let documentAction = UIAlertAction(title: String.localized("files"), style: .default, handler: documentActionPressed(_:))
-        let voiceMessageAction = UIAlertAction(title: String.localized("voice_message"), style: .default, handler: voiceMessageButtonPressed(_:))
-        let isLocationStreaming = dcContext.isSendingLocationsToChat(chatId: chatId)
-        let locationStreamingAction = UIAlertAction(title: isLocationStreaming ? String.localized("stop_sharing_location") : String.localized("location"),
-                                                    style: isLocationStreaming ? .destructive : .default,
-                                                    handler: locationStreamingButtonPressed(_:))
-
-        alert.addAction(cameraAction)
-        alert.addAction(galleryAction)
-        alert.addAction(documentAction)
-        alert.addAction(voiceMessageAction)
-        if UserDefaults.standard.bool(forKey: "location_streaming") {
-            alert.addAction(locationStreamingAction)
-        }
-        alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: nil))
-        self.present(alert, animated: true, completion: {
-            // unfortunately, voiceMessageAction.accessibilityHint does not work,
-            // but this hack does the trick
-            if UIAccessibility.isVoiceOverRunning {
-                if let view = voiceMessageAction.value(forKey: "__representer") as? UIView {
-                    view.accessibilityHint = String.localized("a11y_voice_message_hint_ios")
-                }
-            }
-        })
-    }
-
-    private func documentActionPressed(_ action: UIAlertAction) {
-        showDocumentLibrary()
-    }
-
-    private func voiceMessageButtonPressed(_ action: UIAlertAction) {
-        showVoiceMessageRecorder()
-    }
-
-    private func cameraButtonPressed(_ action: UIAlertAction) {
-        showCameraViewController()
-    }
-
-    private func galleryButtonPressed(_ action: UIAlertAction) {
-        showPhotoVideoLibrary(delegate: self)
-    }
-
-    private func locationStreamingButtonPressed(_ action: UIAlertAction) {
-        let isLocationStreaming = dcContext.isSendingLocationsToChat(chatId: chatId)
-        if isLocationStreaming {
-            locationStreamingFor(seconds: 0)
-        } else {
-            let alert = UIAlertController(title: String.localized("title_share_location"), message: nil, preferredStyle: .safeActionSheet)
-            addDurationSelectionAction(to: alert, key: "share_location_for_5_minutes", duration: Time.fiveMinutes)
-            addDurationSelectionAction(to: alert, key: "share_location_for_30_minutes", duration: Time.thirtyMinutes)
-            addDurationSelectionAction(to: alert, key: "share_location_for_one_hour", duration: Time.oneHour)
-            addDurationSelectionAction(to: alert, key: "share_location_for_two_hours", duration: Time.twoHours)
-            addDurationSelectionAction(to: alert, key: "share_location_for_six_hours", duration: Time.sixHours)
-            alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: nil))
-            self.present(alert, animated: true, completion: nil)
-        }
-    }
-
-    private func addDurationSelectionAction(to alert: UIAlertController, key: String, duration: Int) {
-        let action = UIAlertAction(title: String.localized(key), style: .default, handler: { _ in
-            self.locationStreamingFor(seconds: duration)
-        })
-        alert.addAction(action)
-    }
-
-    private func locationStreamingFor(seconds: Int) {
-            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
-                return
-            }
-            self.dcContext.sendLocationsToChat(chatId: self.chatId, seconds: seconds)
-            appDelegate.locationManager.shareLocation(chatId: self.chatId, duration: seconds)
-    }
-
-}
-
-// MARK: - MessageCellDelegate
-extension ChatViewController: MessageCellDelegate {
-    @objc func didTapMessage(in cell: MessageCollectionViewCell) {
-        if let indexPath = messagesCollectionView.indexPath(for: cell) {
-            let message = messageList[indexPath.section]
-            if message.isSetupMessage {
-                didTapAsm(msg: message, orgText: "")
-            } else {
-                let msgIds = dcContext.getChatMedia(chatId: chatId, messageType: Int32(message.type), messageType2: 0, messageType3: 0)
-                let index = msgIds.firstIndex(of: message.id) ?? 0
-                showMediaGallery(currentIndex: index, msgIds: msgIds)
-            }
-        }
-    }
-
-    private func didTapAsm(msg: DcMsg, orgText: String) {
-        let inputDlg = UIAlertController(
-            title: String.localized("autocrypt_continue_transfer_title"),
-            message: String.localized("autocrypt_continue_transfer_please_enter_code"),
-            preferredStyle: .alert)
-        inputDlg.addTextField(configurationHandler: { (textField) in
-            textField.placeholder = msg.setupCodeBegin + ".."
-            textField.text = orgText
-            textField.keyboardType = UIKeyboardType.numbersAndPunctuation // allows entering spaces; decimalPad would require a mask to keep things readable
-        })
-        inputDlg.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: nil))
-
-        let okAction = UIAlertAction(title: String.localized("ok"), style: .default, handler: { _ in
-            let textField = inputDlg.textFields![0]
-            let modText = textField.text ?? ""
-            let success = self.dcContext.continueKeyTransfer(msgId: msg.id, setupCode: modText)
-
-            let alert = UIAlertController(
-                title: String.localized("autocrypt_continue_transfer_title"),
-                message: String.localized(success ? "autocrypt_continue_transfer_succeeded" : "autocrypt_bad_setup_code"),
-                preferredStyle: .alert)
-            if success {
-                alert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
-            } else {
-                alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: nil))
-                let retryAction = UIAlertAction(title: String.localized("autocrypt_continue_transfer_retry"), style: .default, handler: { _ in
-                    self.didTapAsm(msg: msg, orgText: modText)
-                })
-                alert.addAction(retryAction)
-                alert.preferredAction = retryAction
-            }
-            self.navigationController?.present(alert, animated: true, completion: nil)
-        })
-
-        inputDlg.addAction(okAction)
-        inputDlg.preferredAction = okAction // without setting preferredAction, cancel become shown *bold* as the preferred action
-        navigationController?.present(inputDlg, animated: true, completion: nil)
-    }
-
-    @objc func didTapAvatar(in cell: MessageCollectionViewCell) {
-        if let indexPath = messagesCollectionView.indexPath(for: cell) {
-            let message = messageList[indexPath.section]
-            let chat = dcContext.getChat(chatId: chatId)
-            showContactDetail(of: message.fromContact.id, in: chat.chatType, chatId: chatId)
-        }
-    }
-
-    @objc(didTapCellTopLabelIn:) func didTapCellTopLabel(in _: MessageCollectionViewCell) {
-        logger.info("Top label tapped")
-    }
-
-    @objc(didTapCellBottomLabelIn:) func didTapCellBottomLabel(in _: MessageCollectionViewCell) {
-        print("Bottom label tapped")
-    }
-
-    func didTapPlayButton(in cell: AudioMessageCell) {
-        guard let indexPath = messagesCollectionView.indexPath(for: cell),
-            let message = messagesCollectionView.messagesDataSource?.messageForItem(at: indexPath, in: messagesCollectionView) else {
-                print("Failed to identify message when audio cell receive tap gesture")
-                return
-        }
-        guard audioController.state != .stopped else {
-            // There is no audio sound playing - prepare to start playing for given audio message
-            audioController.playSound(for: message, in: cell)
-            return
-        }
-        if audioController.playingMessage?.messageId == message.messageId {
-            // tap occur in the current cell that is playing audio sound
-            if audioController.state == .playing {
-                audioController.pauseSound(for: message, in: cell)
-            } else {
-                audioController.resumeSound()
-            }
-        } else {
-            // tap occur in a difference cell that the one is currently playing sound. First stop currently playing and start the sound for given message
-            audioController.stopAnyOngoingPlaying()
-            audioController.playSound(for: message, in: cell)
-        }
-    }
-
-    func didStartAudio(in cell: AudioMessageCell) {
-        print("audio started")
-    }
-
-    func didStopAudio(in cell: AudioMessageCell) {
-        print("audio stopped")
-    }
-
-    func didPauseAudio(in cell: AudioMessageCell) {
-        print("audio paused")
-    }
-
-    @objc func didTapBackground(in cell: MessageCollectionViewCell) {
-        print("background of message tapped")
-    }
-}
-
-// MARK: - MessageLabelDelegate
-extension ChatViewController: MessageLabelDelegate {
-
-    func didSelectPhoneNumber(_ phoneNumber: String) {
-        logger.info("phone open", phoneNumber)
-        if let escapedPhoneNumber = phoneNumber.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
-            if let url = NSURL(string: "tel:\(escapedPhoneNumber)") {
-                UIApplication.shared.open(url as URL)
-            }
-        }
-    }
-
-    func didSelectURL(_ url: URL) {
-        if Utils.isEmail(url: url) {
-            print("tapped on contact")
-            let email = Utils.getEmailFrom(url)
-            self.askToChatWith(email: email)
-            ///TODO: implement handling
-        } else {
-            UIApplication.shared.open(url)
-        }
-    }
-}
-
-// MARK: - LocationMessageDisplayDelegate
-/*
- extension ChatViewController: LocationMessageDisplayDelegate {
- func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView? {
- let annotationView = MKAnnotationView(annotation: nil, reuseIdentifier: nil)
- let pinImage = #imageLiteral(resourceName: "ic_block_36pt").withRenderingMode(.alwaysTemplate)
- annotationView.image = pinImage
- annotationView.centerOffset = CGPoint(x: 0, y: -pinImage.size.height / 2)
- return annotationView
- }
- func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? {
- return { view in
- view.layer.transform = CATransform3DMakeScale(0, 0, 0)
- view.alpha = 0.0
- UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0, options: [], animations: {
- view.layer.transform = CATransform3DIdentity
- view.alpha = 1.0
- }, completion: nil)
- }
- }
- }
- */
-
-// MARK: - MessageInputBarDelegate
-extension ChatViewController: InputBarAccessoryViewDelegate {
-    func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) {
-        if inputBar.inputTextView.images.isEmpty {
-            self.sendTextMessage(message: text.trimmingCharacters(in: .whitespacesAndNewlines))
-        } else {
-            let trimmedText = text.replacingOccurrences(of: "\u{FFFC}", with: "", options: .literal, range: nil)
-                .trimmingCharacters(in: .whitespacesAndNewlines)
-            // only 1 attachment allowed for now, thus it takes the first one
-            self.sendImage(inputBar.inputTextView.images[0], message: trimmedText)
-        }
-        inputBar.inputTextView.text = String()
-        inputBar.inputTextView.attributedText = nil
-    }
-}
-
-/*
- extension ChatViewController: MessageInputBarDelegate {
- }
- */
-
-// MARK: - MessageCollectionViewCell
-extension MessageCollectionViewCell {
-
-    @objc func messageForward(_ sender: Any?) {
-        // Get the collectionView
-       if let collectionView = self.superview as? UICollectionView {
-           // Get indexPath
-           if let indexPath = collectionView.indexPath(for: self) {
-               // Trigger action
-               collectionView.delegate?.collectionView?(collectionView,
-                   performAction: #selector(MessageCollectionViewCell.messageForward(_:)),
-                   forItemAt: indexPath, withSender: sender)
-            }
-        }
-    }
-
-    @objc func messageDelete(_ sender: Any?) {
-        // Get the collectionView
-        if let collectionView = self.superview as? UICollectionView {
-            // Get indexPath
-            if let indexPath = collectionView.indexPath(for: self) {
-                // Trigger action
-                collectionView.delegate?.collectionView?(collectionView,
-                    performAction: #selector(MessageCollectionViewCell.messageDelete(_:)),
-                    forItemAt: indexPath, withSender: sender)
-            }
-        }
-    }
-
-    @objc func messageInfo(_ sender: Any?) {
-        // Get the collectionView
-        if let collectionView = self.superview as? UICollectionView {
-            // Get indexPath
-            if let indexPath = collectionView.indexPath(for: self) {
-                // Trigger action
-                collectionView.delegate?.collectionView?(collectionView,
-                    performAction: #selector(MessageCollectionViewCell.messageInfo(_:)),
-                    forItemAt: indexPath, withSender: sender)
-            }
-        }
-    }
-}

+ 1 - 1
deltachat-ios/Controller/ContactDetailViewController.swift

@@ -370,7 +370,7 @@ class ContactDetailViewController: UITableViewController {
     // MARK: - coordinator
     private func showChat(chatId: Int) {
         if let chatlistViewController = navigationController?.viewControllers[0] {
-            let chatViewController = ChatViewController(dcContext: viewModel.context, chatId: chatId)
+            let chatViewController = ChatViewControllerNew(dcContext: viewModel.context, chatId: chatId)
             navigationController?.setViewControllers([chatlistViewController, chatViewController], animated: true)
         }
     }

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

@@ -1,7 +1,7 @@
 import UIKit
 import DcCore
 
-class MailboxViewController: ChatViewController {
+class MailboxViewController: ChatViewControllerNew {
 
     override init(dcContext: DcContext, chatId: Int) {
         super.init(dcContext: dcContext, chatId: chatId)
@@ -23,7 +23,7 @@ class MailboxViewController: ChatViewController {
         super.viewWillAppear(animated)
     }
 
-    override func didTapMessage(in cell: MessageCollectionViewCell) {
+   /* override func didTapMessage(in cell: MessageCollectionViewCell) {
         askToChat(cell: cell)
     }
 
@@ -38,9 +38,9 @@ class MailboxViewController: ChatViewController {
     override func didTapBackground(in cell: MessageCollectionViewCell) {
         askToChat(cell: cell)
     }
+*/
 
-
-    private func askToChat(cell: MessageCollectionViewCell) {
+/*    private func askToChat(cell: MessageCollectionViewCell) {
         if let indexPath = messagesCollectionView.indexPath(for: cell) {
 
             let message = messageList[indexPath.section]
@@ -58,4 +58,5 @@ class MailboxViewController: ChatViewController {
             present(alert, animated: true, completion: nil)
         }
     }
+ */
 }

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

@@ -318,7 +318,7 @@ class NewChatViewController: UITableViewController {
     }
 
     private func showChat(chatId: Int) {
-        let chatViewController = ChatViewController(dcContext: dcContext, chatId: chatId)
+        let chatViewController = ChatViewControllerNew(dcContext: dcContext, chatId: chatId)
         navigationController?.pushViewController(chatViewController, animated: true)
         navigationController?.viewControllers.remove(at: 1)
     }

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

@@ -102,7 +102,7 @@ class NewContactController: UITableViewController {
     // MARK: - coordinator
     private func showChat(chatId: Int) {
         if let chatlistViewController = navigationController?.viewControllers[0] {
-            let chatViewController = ChatViewController(dcContext: dcContext, chatId: chatId)
+            let chatViewController = ChatViewControllerNew(dcContext: dcContext, chatId: chatId)
             navigationController?.setViewControllers([chatlistViewController, chatViewController], animated: true)
         }
     }

+ 1 - 1
deltachat-ios/Controller/NewGroupController.swift

@@ -322,7 +322,7 @@ class NewGroupController: UITableViewController, MediaPickerDelegate {
     // MARK: - coordinator
     private func showGroupChat(chatId: Int) {
         if let chatlistViewController = navigationController?.viewControllers[0] {
-            let chatViewController = ChatViewController(dcContext: dcContext, chatId: chatId)
+            let chatViewController = ChatViewControllerNew(dcContext: dcContext, chatId: chatId)
             navigationController?.setViewControllers([chatlistViewController, chatViewController], animated: true)
         }
     }

+ 3 - 3
deltachat-ios/DC/DcMsg+Extension.swift

@@ -3,9 +3,9 @@ import DcCore
 import UIKit
 import AVFoundation
 
-extension DcMsg: MessageType {
+extension DcMsg {
     
-    public var sender: SenderType {
+   /* public var sender: SenderType {
         return Sender(id: "\(fromContactId)", displayName: fromContact.displayName)
     }
 
@@ -108,7 +108,7 @@ extension DcMsg: MessageType {
 
         let mediaText = [attributedMediaMessageString, attributedFileString, attributedFileSizeString]
         return MessageKind.fileText(Media(url: fileURL, placeholderImage: UIImage(named: "ic_attach_file_36pt"), text: mediaText))
-    }
+    }*/
 
     public func getPrettyFileSize() -> String {
         if self.filesize <= 0 { return "0 B" }

+ 0 - 43
deltachat-ios/Extensions/Bundle+Extensions.swift

@@ -1,43 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-internal extension Bundle {
-
-    static func messageKitAssetBundle() -> Bundle { // swiftlint:disable:this explicit_acl
-        let podBundle = Bundle(for: MessagesViewController.self)
-        
-        guard let resourceBundleUrl = podBundle.url(forResource: "MessageKitAssets", withExtension: "bundle") else {
-            fatalError(MessageKitError.couldNotCreateAssetsPath)
-        }
-        
-        guard let resourceBundle = Bundle(url: resourceBundleUrl) else {
-            fatalError(MessageKitError.couldNotLoadAssetsBundle)
-        }
-        
-        return resourceBundle
-    }
-
-}

+ 0 - 238
deltachat-ios/MessageKit/Controllers/BasicAudioController.swift

@@ -1,238 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-import AVFoundation
-
-/// The `BasicAudioController` update UI for current audio cell that is playing a sound
-/// and also creates and manage an `AVAudioPlayer` states, play, pause and stop.
-open class BasicAudioController: NSObject, AVAudioPlayerDelegate {
-
-    lazy var audioSession: AVAudioSession = {
-        let audioSession = AVAudioSession.sharedInstance()
-        _ = try? audioSession.setCategory(AVAudioSession.Category.playback, options: [.defaultToSpeaker])
-        return audioSession
-    }()
-
-    /// The `AVAudioPlayer` that is playing the sound
-    open var audioPlayer: AVAudioPlayer?
-
-    /// The `AudioMessageCell` that is currently playing sound
-    open weak var playingCell: AudioMessageCell?
-
-    /// The `MessageType` that is currently playing sound
-    open var playingMessage: MessageType?
-
-    /// Specify if current audio controller state: playing, in pause or none
-    open private(set) var state: PlayerState = .stopped
-
-    // The `MessagesCollectionView` where the playing cell exist
-    public weak var messageCollectionView: MessagesCollectionView?
-
-    /// The `Timer` that update playing progress
-    internal var progressTimer: Timer?
-
-    // MARK: - Init Methods
-
-    public init(messageCollectionView: MessagesCollectionView) {
-        self.messageCollectionView = messageCollectionView
-        super.init()
-        NotificationCenter.default.addObserver(self,
-                                               selector: #selector(audioRouteChanged),
-                                               name: AVAudioSession.routeChangeNotification,
-                                               object: AVAudioSession.sharedInstance())
-    }
-
-    deinit {
-        NotificationCenter.default.removeObserver(self)
-    }
-
-    // MARK: - Methods
-
-    /// Used to configure the audio cell UI:
-    ///     1. play button selected state;
-    ///     2. progresssView progress;
-    ///     3. durationLabel text;
-    ///
-    /// - Parameters:
-    ///   - cell: The `AudioMessageCell` that needs to be configure.
-    ///   - message: The `MessageType` that configures the cell.
-    ///
-    /// - Note:
-    ///   This protocol method is called by MessageKit every time an audio cell needs to be configure
-    open func configureAudioCell(_ cell: AudioMessageCell, message: MessageType) {
-        if playingMessage?.messageId == message.messageId, let collectionView = messageCollectionView, let player = audioPlayer {
-            playingCell = cell
-            cell.audioPlayerView.setProgress((player.duration == 0) ? 0 : Float(player.currentTime/player.duration))
-            cell.audioPlayerView.showPlayLayout((player.isPlaying == true) ? true : false)
-            guard let displayDelegate = collectionView.messagesDisplayDelegate else {
-                fatalError("MessagesDisplayDelegate has not been set.")
-            }
-            cell.audioPlayerView.setDuration(formattedText: displayDelegate.audioProgressTextFormat(Float(player.currentTime),
-                                                                                                    for: cell,
-                                                                                                    in: collectionView))
-        }
-    }
-
-    /// Used to start play audio sound
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that contain the audio item to be played.
-    ///   - audioCell: The `AudioMessageCell` that needs to be updated while audio is playing.
-    open func playSound(for message: MessageType, in audioCell: AudioMessageCell) {
-        switch message.kind {
-        case .audio(let item):
-            _ = try? audioSession.setActive(true)
-            playingCell = audioCell
-            playingMessage = message
-            guard let player = try? AVAudioPlayer(contentsOf: item.url) else {
-                print("Failed to create audio player for URL: \(item.url)")
-                return
-            }
-            audioPlayer = player
-            audioPlayer?.prepareToPlay()
-            audioPlayer?.delegate = self
-            audioPlayer?.play()
-            state = .playing
-            audioCell.audioPlayerView.showPlayLayout(true)  // show pause button on audio cell
-            startProgressTimer()
-            audioCell.delegate?.didStartAudio(in: audioCell)
-        default:
-            print("BasicAudioPlayer failed play sound becasue given message kind is not Audio")
-        }
-    }
-
-    /// Used to pause the audio sound
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that contain the audio item to be pause.
-    ///   - audioCell: The `AudioMessageCell` that needs to be updated by the pause action.
-    open func pauseSound(for message: MessageType, in audioCell: AudioMessageCell) {
-        audioPlayer?.pause()
-        state = .pause
-        audioCell.audioPlayerView.showPlayLayout(false) // show play button on audio cell
-        progressTimer?.invalidate()
-        if let cell = playingCell {
-            cell.delegate?.didPauseAudio(in: cell)
-        }
-    }
-
-    /// Stops any ongoing audio playing if exists
-    open func stopAnyOngoingPlaying() {
-        // If the audio player is nil then we don't need to go through the stopping logic
-        guard let player = audioPlayer, let collectionView = messageCollectionView else { return }
-        player.stop()
-        state = .stopped
-        if let cell = playingCell {
-            cell.audioPlayerView.setProgress(0.0)
-            cell.audioPlayerView.showPlayLayout(false)
-            guard let displayDelegate = collectionView.messagesDisplayDelegate else {
-                fatalError("MessagesDisplayDelegate has not been set.")
-            }
-            cell.audioPlayerView.setDuration(formattedText: displayDelegate.audioProgressTextFormat(Float(player.duration),
-                                                                                                    for: cell,
-                                                                                                    in: collectionView))
-            cell.delegate?.didStopAudio(in: cell)
-        }
-        progressTimer?.invalidate()
-        progressTimer = nil
-        audioPlayer = nil
-        playingMessage = nil
-        playingCell = nil
-        try? audioSession.setActive(false)
-    }
-
-    /// Resume a currently pause audio sound
-    open func resumeSound() {
-        guard let player = audioPlayer, let cell = playingCell else {
-            stopAnyOngoingPlaying()
-            return
-        }
-        player.prepareToPlay()
-        player.play()
-        state = .playing
-        startProgressTimer()
-        cell.audioPlayerView.showPlayLayout(true) // show pause button on audio cell
-        cell.delegate?.didStartAudio(in: cell)
-    }
-
-    // MARK: - Fire Methods
-    @objc private func didFireProgressTimer(_ timer: Timer) {
-        guard let player = audioPlayer, let collectionView = messageCollectionView, let cell = playingCell else {
-            return
-        }
-        // check if can update playing cell
-        if let playingCellIndexPath = collectionView.indexPath(for: cell) {
-            // 1. get the current message that decorates the playing cell
-            // 2. check if current message is the same with playing message, if so then update the cell content
-            // Note: Those messages differ in the case of cell reuse
-            let currentMessage = collectionView.messagesDataSource?.messageForItem(at: playingCellIndexPath, in: collectionView)
-            if currentMessage != nil && currentMessage?.messageId == playingMessage?.messageId {
-                // messages are the same update cell content
-                cell.audioPlayerView.setProgress((player.duration == 0) ? 0 : Float(player.currentTime/player.duration))
-                guard let displayDelegate = collectionView.messagesDisplayDelegate else {
-                    fatalError("MessagesDisplayDelegate has not been set.")
-                }
-                cell.audioPlayerView.setDuration(formattedText: displayDelegate.audioProgressTextFormat(Float(player.currentTime),
-                                                                                                        for: cell,
-                                                                                                        in: collectionView))
-            } else {
-                // if the current message is not the same with playing message stop playing sound
-                stopAnyOngoingPlaying()
-            }
-        }
-    }
-
-    // MARK: - Private Methods
-    private func startProgressTimer() {
-        progressTimer?.invalidate()
-        progressTimer = nil
-        progressTimer = Timer.scheduledTimer(timeInterval: 0.1,
-                                             target: self,
-                                             selector: #selector(BasicAudioController.didFireProgressTimer(_:)),
-                                             userInfo: nil,
-                                             repeats: true)
-    }
-
-    // MARK: - AVAudioPlayerDelegate
-    open func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
-        stopAnyOngoingPlaying()
-    }
-
-    open func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
-        stopAnyOngoingPlaying()
-    }
-
-    // MARK: - AVAudioSession.routeChangeNotification handler
-    @objc func audioRouteChanged(note: Notification) {
-      if let userInfo = note.userInfo {
-        if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? Int {
-            if reason == AVAudioSession.RouteChangeReason.oldDeviceUnavailable.rawValue {
-            // headphones plugged out
-            resumeSound()
-          }
-        }
-      }
-    }
-}

+ 0 - 147
deltachat-ios/MessageKit/Controllers/MessagesViewController+Keyboard.swift

@@ -1,147 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import InputBarAccessoryView
-
-internal extension MessagesViewController {
-
-    // MARK: - Register / Unregister Observers
-
-    func addKeyboardObservers() {
-        NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessagesViewController.handleKeyboardDidChangeState(_:)),
-                                               name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
-        NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessagesViewController.handleTextViewDidBeginEditing(_:)),
-                                               name: UITextView.textDidBeginEditingNotification, object: nil)
-        NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessagesViewController.adjustScrollViewTopInset),
-                                               name: UIDevice.orientationDidChangeNotification, object: nil)
-    }
-
-    func removeKeyboardObservers() {
-        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
-        NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: nil)
-        NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
-    }
-
-    // MARK: - Notification Handlers
-
-    @objc
-    private func handleTextViewDidBeginEditing(_ notification: Notification) {
-        if scrollsToBottomOnKeyboardBeginsEditing {
-            guard let inputTextView = notification.object as? InputTextView, inputTextView === messageInputBar.inputTextView else { return }
-            messagesCollectionView.scrollToBottom(animated: true)
-        }
-    }
-
-    @objc
-    private func handleKeyboardDidChangeState(_ notification: Notification) {
-        guard !isMessagesControllerBeingDismissed else { return }
-
-        guard let keyboardStartFrameInScreenCoords = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect else { return }
-        guard !keyboardStartFrameInScreenCoords.isEmpty || UIDevice.current.userInterfaceIdiom != .pad else {
-            // WORKAROUND for what seems to be a bug in iPad's keyboard handling in iOS 11: we receive an extra spurious frame change
-            // notification when undocking the keyboard, with a zero starting frame and an incorrect end frame. The workaround is to
-            // ignore this notification.
-            return
-        }
-        
-        // Note that the check above does not exclude all notifications from an undocked keyboard, only the weird ones.
-        //
-        // We've tried following Apple's recommended approach of tracking UIKeyboardWillShow / UIKeyboardDidHide and ignoring frame
-        // change notifications while the keyboard is hidden or undocked (undocked keyboard is considered hidden by those events).
-        // Unfortunately, we do care about the difference between hidden and undocked, because we have an input bar which is at the
-        // bottom when the keyboard is hidden, and is tied to the keyboard when it's undocked.
-        //
-        // If we follow what Apple recommends and ignore notifications while the keyboard is hidden/undocked, we get an extra inset
-        // at the bottom when the undocked keyboard is visible (the inset that tries to compensate for the missing input bar).
-        // (Alternatives like setting newBottomInset to 0 or to the height of the input bar don't work either.)
-        //
-        // We could make it work by adding extra checks for the state of the keyboard and compensating accordingly, but it seems easier
-        // to simply check whether the current keyboard frame, whatever it is (even when undocked), covers the bottom of the collection
-        // view.
-        
-        guard let keyboardEndFrameInScreenCoords = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
-        let keyboardEndFrame = view.convert(keyboardEndFrameInScreenCoords, from: view.window)
-        
-        let newBottomInset = requiredScrollViewBottomInset(forKeyboardFrame: keyboardEndFrame)
-        let differenceOfBottomInset = newBottomInset - messageCollectionViewBottomInset
-        
-        if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset != 0 {
-            let contentOffset = CGPoint(x: messagesCollectionView.contentOffset.x, y: messagesCollectionView.contentOffset.y + differenceOfBottomInset)
-            messagesCollectionView.setContentOffset(contentOffset, animated: false)
-        }
-        
-        messageCollectionViewBottomInset = newBottomInset
-    }
-
-    // MARK: - Inset Computation
-
-    @objc
-    func adjustScrollViewTopInset() {
-        if #available(iOS 11.0, *) {
-            // No need to add to the top contentInset
-        } else {
-            let navigationBarInset = navigationController?.navigationBar.frame.height ?? 0
-            let statusBarInset: CGFloat = UIApplication.shared.isStatusBarHidden ? 0 : 20
-            let topInset = navigationBarInset + statusBarInset
-            messagesCollectionView.contentInset.top = topInset
-            messagesCollectionView.scrollIndicatorInsets.top = topInset
-        }
-    }
-
-    private func requiredScrollViewBottomInset(forKeyboardFrame keyboardFrame: CGRect) -> CGFloat {
-        // we only need to adjust for the part of the keyboard that covers (i.e. intersects) our collection view;
-        // see https://developer.apple.com/videos/play/wwdc2017/242/ for more details
-        let intersection = messagesCollectionView.frame.intersection(keyboardFrame)
-        
-        if intersection.isNull || (messagesCollectionView.frame.maxY - intersection.maxY) > 0.001 {
-            // The keyboard is hidden, is a hardware one, or is undocked and does not cover the bottom of the collection view.
-            // Note: intersection.maxY may be less than messagesCollectionView.frame.maxY when dealing with undocked keyboards.
-            return max(0, additionalBottomInset - automaticallyAddedBottomInset)
-        } else {
-            return max(0, intersection.height + additionalBottomInset - automaticallyAddedBottomInset)
-        }
-    }
-
-    func requiredInitialScrollViewBottomInset() -> CGFloat {
-        guard let inputAccessoryView = inputAccessoryView else { return 0 }
-        return max(0, inputAccessoryView.frame.height + additionalBottomInset - automaticallyAddedBottomInset)
-    }
-
-    /// iOS 11's UIScrollView can automatically add safe area insets to its contentInset,
-    /// which needs to be accounted for when setting the contentInset based on screen coordinates.
-    ///
-    /// - Returns: The distance automatically added to contentInset.bottom, if any.
-    private var automaticallyAddedBottomInset: CGFloat {
-        if #available(iOS 11.0, *) {
-            return messagesCollectionView.adjustedContentInset.bottom - messagesCollectionView.contentInset.bottom
-        } else {
-            return 0
-        }
-    }
-
-}

+ 0 - 109
deltachat-ios/MessageKit/Controllers/MessagesViewController+Menu.swift

@@ -1,109 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-internal extension MessagesViewController {
-
-    // MARK: - Register / Unregister Observers
-
-    func addMenuControllerObservers() {
-        NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessagesViewController.menuControllerWillShow(_:)),
-                                               name: UIMenuController.willShowMenuNotification, object: nil)
-    }
-
-    func removeMenuControllerObservers() {
-        NotificationCenter.default.removeObserver(self, name: UIMenuController.willShowMenuNotification, object: nil)
-    }
-
-    // MARK: - Notification Handlers
-
-    /// Show menuController and set target rect to selected bubble
-    @objc
-    private func menuControllerWillShow(_ notification: Notification) {
-
-        guard let currentMenuController = notification.object as? UIMenuController,
-            let selectedIndexPath = selectedIndexPathForMenu else { return }
-
-        NotificationCenter.default.removeObserver(self, name: UIMenuController.willShowMenuNotification, object: nil)
-        defer {
-            NotificationCenter.default.addObserver(self,
-                                                   selector: #selector(MessagesViewController.menuControllerWillShow(_:)),
-                                                   name: UIMenuController.willShowMenuNotification, object: nil)
-            selectedIndexPathForMenu = nil
-        }
-
-        currentMenuController.setMenuVisible(false, animated: false)
-
-        guard let selectedCell = messagesCollectionView.cellForItem(at: selectedIndexPath) as? MessageContentCell else { return }
-        let selectedCellMessageBubbleFrame = selectedCell.convert(selectedCell.messageContainerView.frame, to: view)
-
-        var messageInputBarFrame: CGRect = .zero
-        if let messageInputBarSuperview = messageInputBar.superview {
-            messageInputBarFrame = view.convert(messageInputBar.frame, from: messageInputBarSuperview)
-        }
-
-        var topNavigationBarFrame: CGRect = navigationBarFrame
-        if navigationBarFrame != .zero, let navigationBarSuperview = navigationController?.navigationBar.superview {
-            topNavigationBarFrame = view.convert(navigationController!.navigationBar.frame, from: navigationBarSuperview)
-        }
-
-        let menuHeight = currentMenuController.menuFrame.height
-
-        let selectedCellMessageBubblePlusMenuFrame =
-            CGRect(selectedCellMessageBubbleFrame.origin.x,
-                   selectedCellMessageBubbleFrame.origin.y - menuHeight,
-                   selectedCellMessageBubbleFrame.size.width,
-                   selectedCellMessageBubbleFrame.size.height + 2 * menuHeight)
-
-        var targetRect: CGRect = selectedCellMessageBubbleFrame
-        currentMenuController.arrowDirection = .default
-
-        /// Message bubble intersects with navigationBar and keyboard
-        if selectedCellMessageBubblePlusMenuFrame.intersects(topNavigationBarFrame) &&
-            selectedCellMessageBubblePlusMenuFrame.intersects(messageInputBarFrame) {
-
-            let centerY = (selectedCellMessageBubblePlusMenuFrame.intersection(messageInputBarFrame).minY +
-                selectedCellMessageBubblePlusMenuFrame.intersection(topNavigationBarFrame).maxY) / 2
-            targetRect = CGRect(selectedCellMessageBubblePlusMenuFrame.midX, centerY, 1, 1)
-        } /// Message bubble only intersects with navigationBar
-        else if selectedCellMessageBubblePlusMenuFrame.intersects(topNavigationBarFrame) {
-            currentMenuController.arrowDirection = .up
-        }
-
-        currentMenuController.setTargetRect(targetRect, in: view)
-        currentMenuController.setMenuVisible(true, animated: true)
-    }
-
-    // MARK: - Helpers
-
-    private var navigationBarFrame: CGRect {
-        guard let navigationController = navigationController, !navigationController.navigationBar.isHidden else {
-            return .zero
-        }
-        return navigationController.navigationBar.frame
-    }
-}

+ 0 - 448
deltachat-ios/MessageKit/Controllers/MessagesViewController.swift

@@ -1,448 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-import InputBarAccessoryView
-
-/// A subclass of `UIViewController` with a `MessagesCollectionView` object
-/// that is used to display conversation interfaces.
-open class MessagesViewController: UIViewController,
-UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
-
-    /// The `MessagesCollectionView` managed by the messages view controller object.
-    open var messagesCollectionView = MessagesCollectionView()
-
-    /// The `InputBarAccessoryView` used as the `inputAccessoryView` in the view controller.
-    open var messageInputBar = InputBarAccessoryView()
-
-    /// A Boolean value that determines whether the `MessagesCollectionView` scrolls to the
-    /// bottom whenever the `InputTextView` begins editing.
-    ///
-    /// The default value of this property is `false`.
-    open var scrollsToBottomOnKeyboardBeginsEditing: Bool = false
-    
-    /// A Boolean value that determines whether the `MessagesCollectionView`
-    /// maintains it's current position when the height of the `MessageInputBar` changes.
-    ///
-    /// The default value of this property is `false`.
-    open var maintainPositionOnKeyboardFrameChanged: Bool = false
-
-    open override var canBecomeFirstResponder: Bool {
-        return true
-    }
-
-    open override var inputAccessoryView: UIView? {
-        return messageInputBar
-    }
-
-    open override var shouldAutorotate: Bool {
-        return false
-    }
-
-    /// A CGFloat value that adds to (or, if negative, subtracts from) the automatically
-    /// computed value of `messagesCollectionView.contentInset.bottom`. Meant to be used
-    /// as a measure of last resort when the built-in algorithm does not produce the right
-    /// value for your app. Please let us know when you end up having to use this property.
-    open var additionalBottomInset: CGFloat = 0 {
-        didSet {
-            let delta = additionalBottomInset - oldValue
-            messageCollectionViewBottomInset += delta
-        }
-    }
-
-    public var isTypingIndicatorHidden: Bool {
-        return messagesCollectionView.isTypingIndicatorHidden
-    }
-
-    public var selectedIndexPathForMenu: IndexPath?
-
-    private var isFirstLayout: Bool = true
-    
-    internal var isMessagesControllerBeingDismissed: Bool = false
-
-    internal var messageCollectionViewBottomInset: CGFloat = 0 {
-        didSet {
-            messagesCollectionView.contentInset.bottom = messageCollectionViewBottomInset
-            messagesCollectionView.scrollIndicatorInsets.bottom = messageCollectionViewBottomInset
-        }
-    }
-
-    // MARK: - View Life Cycle
-
-    open override func viewDidLoad() {
-        super.viewDidLoad()
-        setupDefaults()
-        setupSubviews()
-        setupConstraints()
-        setupDelegates()
-        addMenuControllerObservers()
-        addObservers()
-    }
-    
-    open override func viewDidAppear(_ animated: Bool) {
-        super.viewDidAppear(animated)
-        isMessagesControllerBeingDismissed = false
-    }
-    
-    open override func viewWillDisappear(_ animated: Bool) {
-        super.viewWillDisappear(animated)
-        isMessagesControllerBeingDismissed = true
-    }
-    
-    open override func viewDidDisappear(_ animated: Bool) {
-        super.viewDidDisappear(animated)
-        isMessagesControllerBeingDismissed = false
-    }
-    
-    open override func viewDidLayoutSubviews() {
-        // Hack to prevent animation of the contentInset after viewDidAppear
-        if isFirstLayout {
-            defer { isFirstLayout = false }
-            addKeyboardObservers()
-            messageCollectionViewBottomInset = requiredInitialScrollViewBottomInset()
-        }
-        adjustScrollViewTopInset()
-    }
-
-    open override func viewSafeAreaInsetsDidChange() {
-        if #available(iOS 11.0, *) {
-            super.viewSafeAreaInsetsDidChange()
-        }
-        messageCollectionViewBottomInset = requiredInitialScrollViewBottomInset()
-    }
-
-    // MARK: - Initializers
-
-    deinit {
-        removeKeyboardObservers()
-        removeMenuControllerObservers()
-        removeObservers()
-        clearMemoryCache()
-    }
-
-    // MARK: - Methods [Private]
-
-    private func setupDefaults() {
-        extendedLayoutIncludesOpaqueBars = true
-        if #available(iOS 11.0, *) {} else {
-            automaticallyAdjustsScrollViewInsets = false
-        }
-        view.backgroundColor = .white
-        messagesCollectionView.keyboardDismissMode = .interactive
-        messagesCollectionView.alwaysBounceVertical = true
-    }
-
-    private func setupDelegates() {
-        messagesCollectionView.delegate = self
-        messagesCollectionView.dataSource = self
-    }
-
-    private func setupSubviews() {
-        view.addSubview(messagesCollectionView)
-    }
-
-    private func setupConstraints() {
-        messagesCollectionView.translatesAutoresizingMaskIntoConstraints = false
-
-        let top = messagesCollectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: topLayoutGuide.length)
-        let bottom = messagesCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
-        if #available(iOS 11.0, *) {
-            let leading = messagesCollectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor)
-            let trailing = messagesCollectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
-            NSLayoutConstraint.activate([top, bottom, trailing, leading])
-        } else {
-            let leading = messagesCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor)
-            let trailing = messagesCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
-            NSLayoutConstraint.activate([top, bottom, trailing, leading])
-        }
-    }
-
-    // MARK: - Typing Indicator API
-
-    /// Sets the typing indicator sate by inserting/deleting the `TypingBubbleCell`
-    ///
-    /// - Parameters:
-    ///   - isHidden: A Boolean value that is to be the new state of the typing indicator
-    ///   - animated: A Boolean value determining if the insertion is to be animated
-    ///   - updates: A block of code that will be executed during `performBatchUpdates`
-    ///              when `animated` is `TRUE` or before the `completion` block executes
-    ///              when `animated` is `FALSE`
-    ///   - completion: A completion block to execute after the insertion/deletion
-    open func setTypingIndicatorViewHidden(_ isHidden: Bool, animated: Bool, whilePerforming updates: (() -> Void)? = nil, completion: ((Bool) -> Void)? = nil) {
-
-        guard isTypingIndicatorHidden != isHidden else {
-            completion?(false)
-            return
-        }
-
-        let section = messagesCollectionView.numberOfSections
-        messagesCollectionView.setTypingIndicatorViewHidden(isHidden)
-
-        if animated {
-            messagesCollectionView.performBatchUpdates({ [weak self] in
-                self?.performUpdatesForTypingIndicatorVisability(at: section)
-                updates?()
-                }, completion: completion)
-        } else {
-            performUpdatesForTypingIndicatorVisability(at: section)
-            updates?()
-            completion?(true)
-        }
-    }
-
-    /// Performs a delete or insert on the `MessagesCollectionView` on the provided section
-    ///
-    /// - Parameter section: The index to modify
-    private func performUpdatesForTypingIndicatorVisability(at section: Int) {
-        if isTypingIndicatorHidden {
-            messagesCollectionView.deleteSections([section - 1])
-        } else {
-            messagesCollectionView.insertSections([section])
-        }
-    }
-
-    /// A method that by default checks if the section is the last in the
-    /// `messagesCollectionView` and that `isTypingIndicatorViewHidden`
-    /// is FALSE
-    ///
-    /// - Parameter section
-    /// - Returns: A Boolean indicating if the TypingIndicator should be presented at the given section
-    public func isSectionReservedForTypingIndicator(_ section: Int) -> Bool {
-        return !messagesCollectionView.isTypingIndicatorHidden && section == self.numberOfSections(in: messagesCollectionView) - 1
-    }
-
-    // MARK: - UICollectionViewDataSource
-
-    open func numberOfSections(in collectionView: UICollectionView) -> Int {
-        guard let collectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        let sections = collectionView.messagesDataSource?.numberOfSections(in: collectionView) ?? 0
-        return collectionView.isTypingIndicatorHidden ? sections : sections + 1
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        guard let collectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        if isSectionReservedForTypingIndicator(section) {
-            return 1
-        }
-        return collectionView.messagesDataSource?.numberOfItems(inSection: section, in: collectionView) ?? 0
-    }
-
-    /// Notes:
-    /// - If you override this method, remember to call MessagesDataSource's customCell(for:at:in:)
-    /// for MessageKind.custom messages, if necessary.
-    ///
-    /// - If you are using the typing indicator you will need to ensure that the section is not
-    /// reserved for it with `isSectionReservedForTypingIndicator` defined in
-    /// `MessagesCollectionViewFlowLayout`
-    open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-
-        if isSectionReservedForTypingIndicator(indexPath.section) {
-            return messagesDataSource.typingIndicator(at: indexPath, in: messagesCollectionView)
-        }
-
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.kind {
-        case .text, .attributedText, .emoji:
-            let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .info:
-            let cell = messagesCollectionView.dequeueReusableCell(InfoMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .photo, .video:
-            let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .photoText, .videoText:
-            let cell = messagesCollectionView.dequeueReusableCell(TextMediaMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .animatedImageText:
-            let cell = messagesCollectionView.dequeueReusableCell(AnimatedImageMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .fileText:
-            let cell = messagesCollectionView.dequeueReusableCell(FileMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .location:
-            let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .audio:
-            let cell = messagesCollectionView.dequeueReusableCell(AudioMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .contact:
-            let cell = messagesCollectionView.dequeueReusableCell(ContactMessageCell.self, for: indexPath)
-            cell.configure(with: message, at: indexPath, and: messagesCollectionView)
-            return cell
-        case .custom:
-            return messagesDataSource.customCell(for: message, at: indexPath, in: messagesCollectionView)
-        }
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
-
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        switch kind {
-        case UICollectionView.elementKindSectionHeader:
-            return displayDelegate.messageHeaderView(for: indexPath, in: messagesCollectionView)
-        case UICollectionView.elementKindSectionFooter:
-            return displayDelegate.messageFooterView(for: indexPath, in: messagesCollectionView)
-        default:
-            fatalError(MessageKitError.unrecognizedSectionKind)
-        }
-    }
-
-    // MARK: - UICollectionViewDelegateFlowLayout
-
-    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
-        guard let messagesFlowLayout = collectionViewLayout as? MessagesCollectionViewFlowLayout else { return .zero }
-        return messagesFlowLayout.sizeForItem(at: indexPath)
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
-
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
-            fatalError(MessageKitError.nilMessagesLayoutDelegate)
-        }
-        if isSectionReservedForTypingIndicator(section) {
-            return .zero
-        }
-        return layoutDelegate.headerViewSize(for: section, in: messagesCollectionView)
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
-        guard let cell = cell as? TypingIndicatorCell else { return }
-        cell.typingBubble.startAnimating()
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.notMessagesCollectionView)
-        }
-        guard let layoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
-            fatalError(MessageKitError.nilMessagesLayoutDelegate)
-        }
-        if isSectionReservedForTypingIndicator(section) {
-            return .zero
-        }
-        return layoutDelegate.footerViewSize(for: section, in: messagesCollectionView)
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else { return false }
-
-        if isSectionReservedForTypingIndicator(indexPath.section) {
-            return false
-        }
-
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.kind {
-        case .text, .attributedText, .emoji, .photo, .animatedImageText, .photoText, .videoText, .fileText, .audio, .video:
-            selectedIndexPathForMenu = indexPath
-            return true
-        default:
-            return false
-        }
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
-        if isSectionReservedForTypingIndicator(indexPath.section) {
-            return false
-        }
-
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.kind {
-        case .text, .emoji, .attributedText, .fileText, .photoText, .videoText, .animatedImageText:
-            return (action == NSSelectorFromString("copy:"))
-        default:
-            return false
-        }
-    }
-
-    open func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        let pasteBoard = UIPasteboard.general
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-
-        switch message.kind {
-        case .text(let text), .emoji(let text):
-            pasteBoard.string = text
-        case .attributedText(let attributedText):
-            pasteBoard.string = attributedText.string
-        case .photoText(let mediaItem), .videoText(let mediaItem), .fileText(let mediaItem):
-            pasteBoard.string = mediaItem.text?[MediaItemConstants.messageText].string
-        default:
-            break
-        }
-    }
-
-    // MARK: - Helpers
-    
-    private func addObservers() {
-        NotificationCenter.default.addObserver(
-            self, selector: #selector(clearMemoryCache), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
-    }
-
-    private func removeObservers() {
-        NotificationCenter.default.removeObserver(self, name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
-    }
-    
-    @objc private func clearMemoryCache() {
-        MessageStyle.bubbleImageCache.removeAllObjects()
-    }
-}

+ 0 - 90
deltachat-ios/MessageKit/Layout/AudioMessageSizeCalculator.swift

@@ -1,90 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class AudioMessageSizeCalculator: MessageSizeCalculator {
-
-    public var incomingMessageLabelInsets = UIEdgeInsets(top: AudioMessageCell.insetTop,
-                                                         left: AudioMessageCell.insetHorizontalBig,
-                                                         bottom: AudioMessageCell.insetBottom,
-                                                         right: AudioMessageCell.insetHorizontalSmall)
-   public var outgoingMessageLabelInsets = UIEdgeInsets(top: AudioMessageCell.insetTop,
-                                                        left: AudioMessageCell.insetHorizontalSmall,
-                                                        bottom: AudioMessageCell.insetBottom,
-                                                        right: AudioMessageCell.insetHorizontalBig)
-
-    public var messageLabelFont = UIFont.preferredFont(forTextStyle: .body)
-
-
-    internal func messageLabelInsets(for message: MessageType) -> UIEdgeInsets {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessageLabelInsets : incomingMessageLabelInsets
-    }
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        switch message.kind {
-        case .audio(let item):
-            let maxWidth = messageContainerMaxWidth(for: message)
-            var itemWidth = item.size.width
-            var itemHeight = item.size.height
-
-            if maxWidth < itemWidth {
-                // Maintain the ratio if width is too great
-                itemHeight = maxWidth * item.size.height / item.size.width
-                itemWidth = maxWidth
-            }
-
-            let maxTextWidth = itemWidth - self.messageLabelInsets(for: message).horizontal
-            var messageContainerSize = CGSize(width: itemWidth, height: itemHeight)
-            if let text = item.text {
-                let textHeight = text.height(withConstrainedWidth: maxTextWidth)
-                messageContainerSize.height += textHeight
-                messageContainerSize.height +=  self.messageLabelInsets(for: message).vertical
-            }
-            return messageContainerSize
-        default:
-            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-        }
-    }
-
-    open override func configure(attributes: UICollectionViewLayoutAttributes) {
-        super.configure(attributes: attributes)
-        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
-
-        let dataSource = messagesLayout.messagesDataSource
-        let indexPath = attributes.indexPath
-        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
-
-        switch message.kind {
-        case .audio:
-            attributes.messageLabelInsets = messageLabelInsets(for: message)
-            attributes.messageLabelFont = messageLabelFont
-        default:
-            break
-        }
-    }
-}

+ 0 - 50
deltachat-ios/MessageKit/Layout/CellSizeCalculator.swift

@@ -1,50 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// An object is responsible for
-/// sizing and configuring cells for given `IndexPath`s.
-open class CellSizeCalculator {
-
-    /// The layout object for which the cell size calculator is used.
-    public weak var layout: UICollectionViewFlowLayout?
-
-    /// Used to configure the layout attributes for a given cell.
-    ///
-    /// - Parameters:
-    /// - attributes: The attributes of the cell.
-    /// The default does nothing
-    open func configure(attributes: UICollectionViewLayoutAttributes) {}
-
-    /// Used to size an item at a given `IndexPath`.
-    ///
-    /// - Parameters:
-    /// - indexPath: The `IndexPath` of the item to be displayed.
-    /// The default return .zero
-    open func sizeForItem(at indexPath: IndexPath) -> CGSize { return .zero }
-    
-    public init() {}
-
-}

+ 0 - 74
deltachat-ios/MessageKit/Layout/ContactMessageSizeCalculator.swift

@@ -1,74 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2018 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class ContactMessageSizeCalculator: MessageSizeCalculator {
-
-    public var incomingMessageNameLabelInsets = UIEdgeInsets(top: 7, left: 46, bottom: 7, right: 30)
-    public var outgoingMessageNameLabelInsets = UIEdgeInsets(top: 7, left: 41, bottom: 7, right: 35)
-    public var contactLabelFont = UIFont.preferredFont(forTextStyle: .body)
-
-    internal func contactLabelInsets(for message: MessageType) -> UIEdgeInsets {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessageNameLabelInsets : incomingMessageNameLabelInsets
-    }
-
-    open override func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
-        let maxWidth = super.messageContainerMaxWidth(for: message)
-        let textInsets = contactLabelInsets(for: message)
-        return maxWidth - textInsets.horizontal
-    }
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        let maxWidth = messageContainerMaxWidth(for: message)
-
-        var messageContainerSize: CGSize
-        let attributedText: NSAttributedString
-
-        switch message.kind {
-        case .contact(let item):
-            attributedText = NSAttributedString(string: item.displayName, attributes: [.font: contactLabelFont])
-        default:
-            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-        }
-
-        messageContainerSize = labelSize(for: attributedText, considering: maxWidth)
-
-        let messageInsets = contactLabelInsets(for: message)
-        messageContainerSize.width += messageInsets.horizontal
-        messageContainerSize.height += messageInsets.vertical
-
-        return messageContainerSize
-    }
-
-    open override func configure(attributes: UICollectionViewLayoutAttributes) {
-        super.configure(attributes: attributes)
-        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
-        attributes.messageLabelFont = contactLabelFont
-    }
-
-}

+ 0 - 73
deltachat-ios/MessageKit/Layout/FileMessageSizeCalculator.swift

@@ -1,73 +0,0 @@
-import Foundation
-import UIKit
-
-open class FileMessageSizeCalculator: MessageSizeCalculator {
-
-    var defaultFileMessageCellWidth: CGFloat {
-        switch UIApplication.shared.statusBarOrientation {
-        case .landscapeLeft, .landscapeRight:
-            return UIScreen.main.bounds.size.width * 0.66
-        default:
-            return UIScreen.main.bounds.size.width * 0.85
-        }
-    }
-
-    private var incomingMessageLabelInsets = UIEdgeInsets(top: 0,
-                                                         left: FileMessageCell.insetHorizontalBig,
-                                                         bottom: FileMessageCell.insetVertical,
-                                                         right: FileMessageCell.insetHorizontalSmall)
-    private var outgoingMessageLabelInsets = UIEdgeInsets(top: 0,
-                                                         left: FileMessageCell.insetHorizontalSmall,
-                                                         bottom: FileMessageCell.insetVertical,
-                                                         right: FileMessageCell.insetHorizontalBig)
-
-    private var messageLabelFont = UIFont.preferredFont(forTextStyle: .body)
-
-    internal func messageLabelInsets(for message: MessageType) -> UIEdgeInsets {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessageLabelInsets : incomingMessageLabelInsets
-    }
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        let sizeForMediaItem = { (maxWidth: CGFloat, item: MediaItem) -> CGSize in
-            var messageContainerSize = CGSize(width: maxWidth, height: FileView.defaultHeight)
-            switch message.kind {
-            case .fileText(let mediaItem):
-                if let messageText = mediaItem.text?[MediaItemConstants.messageText], !messageText.string.isEmpty {
-                    let messageTextHeight = messageText.height(withConstrainedWidth: maxWidth - self.messageLabelInsets(for: message).horizontal)
-                    messageContainerSize.height += messageTextHeight + self.messageLabelInsets(for: message).bottom
-                }
-            default:
-                safe_fatalError("only fileText types can be calculated by FileMessageSizeCalculator")
-            }
-            return messageContainerSize
-        }
-
-        switch message.kind {
-        case .fileText(let item):
-            let maxImageWidth = item.image != nil ? messageContainerMaxWidth(for: message) : defaultFileMessageCellWidth
-            return sizeForMediaItem(maxImageWidth, item)
-        default:
-            safe_fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-            return .zero
-        }
-    }
-
-    open override func configure(attributes: UICollectionViewLayoutAttributes) {
-        super.configure(attributes: attributes)
-        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
-
-        let dataSource = messagesLayout.messagesDataSource
-        let indexPath = attributes.indexPath
-        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
-
-        switch message.kind {
-        case .fileText:
-            attributes.messageLabelInsets = messageLabelInsets(for: message)
-            attributes.messageLabelFont = messageLabelFont
-        default:
-            break
-        }
-    }
-}

+ 0 - 44
deltachat-ios/MessageKit/Layout/LocationMessageSizeCalculator.swift

@@ -1,44 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class LocationMessageSizeCalculator: MessageSizeCalculator {
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        switch message.kind {
-        case .location(let item):
-            let maxWidth = messageContainerMaxWidth(for: message)
-            if maxWidth < item.size.width {
-                // Maintain the ratio if width is too great
-                let height = maxWidth * item.size.height / item.size.width
-                return CGSize(width: maxWidth, height: height)
-            }
-            return item.size
-        default:
-            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-        }
-    }
-}

+ 0 - 62
deltachat-ios/MessageKit/Layout/MediaMessageSizeCalculator.swift

@@ -1,62 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class MediaMessageSizeCalculator: MessageSizeCalculator {
-
-    private var maxMediaItemHeight: CGFloat {
-        return UIScreen.main.bounds.size.height * 0.7
-    }
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        let maxWidth = messageContainerMaxWidth(for: message)
-        let sizeForMediaItem = { (maxWidth: CGFloat, item: MediaItem) -> CGSize in
-            var imageWidth = item.size.width
-            var imageHeight = item.size.height
-            if maxWidth < item.size.width {
-                // Maintain the ratio if width is too great
-                imageHeight = maxWidth * item.size.height / item.size.width
-                imageWidth = maxWidth
-            }
-
-            if self.maxMediaItemHeight < imageHeight {
-                // Maintain the ratio if height is too great
-                imageWidth = self.maxMediaItemHeight * imageWidth / imageHeight
-                imageHeight = self.maxMediaItemHeight
-            }
-
-            return CGSize(width: imageWidth, height: imageHeight)
-        }
-        switch message.kind {
-        case .photo(let item):
-            return sizeForMediaItem(maxWidth, item)
-        case .video:
-            return CGSize(width: maxWidth, height: maxWidth)
-        default:
-            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-        }
-    }
-}

+ 0 - 292
deltachat-ios/MessageKit/Layout/MessageSizeCalculator.swift

@@ -1,292 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class MessageSizeCalculator: CellSizeCalculator {
-
-    public init(layout: MessagesCollectionViewFlowLayout? = nil) {
-        super.init()
-        
-        self.layout = layout
-    }
-
-    public var incomingAvatarSize = CGSize(width: 30, height: 30)
-    public var outgoingAvatarSize = CGSize(width: 30, height: 30)
-
-    public var incomingAvatarPosition = AvatarPosition(vertical: .cellBottom)
-    public var outgoingAvatarPosition = AvatarPosition(vertical: .cellBottom)
-
-    public var avatarLeadingTrailingPadding: CGFloat = 0
-
-    public var incomingMessagePadding = UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 30)
-    public var outgoingMessagePadding = UIEdgeInsets(top: 0, left: 30, bottom: 0, right: 4)
-
-    public var incomingCellTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
-    public var outgoingCellTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
-    
-    public var incomingCellBottomLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
-    public var outgoingCellBottomLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 42))
-
-    public var incomingMessageTopLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
-    public var outgoingMessageTopLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 42))
-
-    public var incomingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .left, textInsets: UIEdgeInsets(left: 42))
-    public var outgoingMessageBottomLabelAlignment = LabelAlignment(textAlignment: .right, textInsets: UIEdgeInsets(right: 42))
-
-    public var incomingAccessoryViewSize = CGSize.zero
-    public var outgoingAccessoryViewSize = CGSize.zero
-
-    public var incomingAccessoryViewPadding = HorizontalEdgeInsets.zero
-    public var outgoingAccessoryViewPadding = HorizontalEdgeInsets.zero
-    
-    public var incomingAccessoryViewPosition: AccessoryPosition = .messageCenter
-    public var outgoingAccessoryViewPosition: AccessoryPosition = .messageCenter
-
-    open override func configure(attributes: UICollectionViewLayoutAttributes) {
-        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
-
-        let dataSource = messagesLayout.messagesDataSource
-        let indexPath = attributes.indexPath
-        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
-
-        attributes.avatarSize = avatarSize(for: message)
-        attributes.avatarPosition = avatarPosition(for: message)
-        attributes.avatarLeadingTrailingPadding = avatarLeadingTrailingPadding
-
-        attributes.messageContainerPadding = messageContainerPadding(for: message)
-        attributes.messageContainerSize = messageContainerSize(for: message)
-        attributes.cellTopLabelSize = cellTopLabelSize(for: message, at: indexPath)
-        attributes.cellBottomLabelSize = cellBottomLabelSize(for: message, at: indexPath)
-        attributes.cellBottomLabelAlignment = cellBottomLabelAlignment(for: message)
-        attributes.messageTopLabelSize = messageTopLabelSize(for: message, at: indexPath)
-        attributes.messageTopLabelAlignment = messageTopLabelAlignment(for: message)
-
-        attributes.messageBottomLabelAlignment = messageBottomLabelAlignment(for: message)
-        attributes.messageBottomLabelSize = messageBottomLabelSize(for: message, at: indexPath)
-
-        attributes.accessoryViewSize = accessoryViewSize(for: message)
-        attributes.accessoryViewPadding = accessoryViewPadding(for: message)
-        attributes.accessoryViewPosition = accessoryViewPosition(for: message)
-    }
-
-    open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
-        let dataSource = messagesLayout.messagesDataSource
-        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
-        let itemHeight = cellContentHeight(for: message, at: indexPath)
-        return CGSize(width: messagesLayout.itemWidth, height: itemHeight)
-    }
-
-    open func cellContentHeight(for message: MessageType, at indexPath: IndexPath) -> CGFloat {
-
-        let messageContainerHeight = messageContainerSize(for: message).height
-        let cellBottomLabelHeight = cellBottomLabelSize(for: message, at: indexPath).height
-        let messageBottomLabelHeight = messageBottomLabelSize(for: message, at: indexPath).height
-        let cellTopLabelHeight = cellTopLabelSize(for: message, at: indexPath).height
-        let messageTopLabelHeight = messageTopLabelSize(for: message, at: indexPath).height
-        let messageVerticalPadding = messageContainerPadding(for: message).vertical
-        let avatarHeight = avatarSize(for: message).height
-        let avatarVerticalPosition = avatarPosition(for: message).vertical
-        let accessoryViewHeight = accessoryViewSize(for: message).height
-
-        switch avatarVerticalPosition {
-        case .messageCenter:
-            let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
-                + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight + cellBottomLabelHeight
-            let cellHeight = max(avatarHeight, totalLabelHeight)
-            return max(cellHeight, accessoryViewHeight)
-        case .messageBottom:
-            var cellHeight: CGFloat = 0
-            cellHeight += messageBottomLabelHeight
-            cellHeight += cellBottomLabelHeight
-            let labelsHeight = messageContainerHeight + messageVerticalPadding + cellTopLabelHeight + messageTopLabelHeight
-            cellHeight += max(labelsHeight, avatarHeight)
-            return max(cellHeight, accessoryViewHeight)
-        case .messageTop:
-            var cellHeight: CGFloat = 0
-            cellHeight += cellTopLabelHeight
-            cellHeight += messageTopLabelHeight
-            let labelsHeight = messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight + cellBottomLabelHeight
-            cellHeight += max(labelsHeight, avatarHeight)
-            return max(cellHeight, accessoryViewHeight)
-        case .messageLabelTop:
-            var cellHeight: CGFloat = 0
-            cellHeight += cellTopLabelHeight
-            let messageLabelsHeight = messageContainerHeight + messageBottomLabelHeight + messageVerticalPadding + messageTopLabelHeight + cellBottomLabelHeight
-            cellHeight += max(messageLabelsHeight, avatarHeight)
-            return max(cellHeight, accessoryViewHeight)
-        case .cellTop, .cellBottom:
-            let totalLabelHeight: CGFloat = cellTopLabelHeight + messageTopLabelHeight
-                + messageContainerHeight + messageVerticalPadding + messageBottomLabelHeight + cellBottomLabelHeight
-            let cellHeight = max(avatarHeight, totalLabelHeight)
-            return max(cellHeight, accessoryViewHeight)
-        }
-    }
-
-    // MARK: - Avatar
-
-    open func avatarPosition(for message: MessageType) -> AvatarPosition {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        var position = isFromCurrentSender ? outgoingAvatarPosition : incomingAvatarPosition
-
-        switch position.horizontal {
-        case .cellTrailing, .cellLeading:
-            break
-        case .natural:
-            position.horizontal = isFromCurrentSender ? .cellTrailing : .cellLeading
-        }
-        return position
-    }
-
-    open func avatarSize(for message: MessageType) -> CGSize {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingAvatarSize : incomingAvatarSize
-    }
-
-    // MARK: - Top cell Label
-
-    open func cellTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
-        let layoutDelegate = messagesLayout.messagesLayoutDelegate
-        let collectionView = messagesLayout.messagesCollectionView
-        let height = layoutDelegate.cellTopLabelHeight(for: message, at: indexPath, in: collectionView)
-        return CGSize(width: messagesLayout.itemWidth, height: height)
-    }
-
-    open func cellTopLabelAlignment(for message: MessageType) -> LabelAlignment {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingCellTopLabelAlignment : incomingCellTopLabelAlignment
-    }
-    
-    // MARK: - Top message Label
-    
-    open func messageTopLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
-        let layoutDelegate = messagesLayout.messagesLayoutDelegate
-        let collectionView = messagesLayout.messagesCollectionView
-        let height = layoutDelegate.messageTopLabelHeight(for: message, at: indexPath, in: collectionView)
-        return CGSize(width: messagesLayout.itemWidth, height: height)
-    }
-    
-    open func messageTopLabelAlignment(for message: MessageType) -> LabelAlignment {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessageTopLabelAlignment : incomingMessageTopLabelAlignment
-    }
-    
-    // MARK: - Bottom cell Label
-    
-    open func cellBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
-        let layoutDelegate = messagesLayout.messagesLayoutDelegate
-        let collectionView = messagesLayout.messagesCollectionView
-        let height = layoutDelegate.cellBottomLabelHeight(for: message, at: indexPath, in: collectionView)
-        return CGSize(width: messagesLayout.itemWidth, height: height)
-    }
-    
-    open func cellBottomLabelAlignment(for message: MessageType) -> LabelAlignment {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingCellBottomLabelAlignment : incomingCellBottomLabelAlignment
-    }
-
-    // MARK: - Bottom Message Label
-
-    open func messageBottomLabelSize(for message: MessageType, at indexPath: IndexPath) -> CGSize {
-        let layoutDelegate = messagesLayout.messagesLayoutDelegate
-        let collectionView = messagesLayout.messagesCollectionView
-        let height = layoutDelegate.messageBottomLabelHeight(for: message, at: indexPath, in: collectionView)
-        return CGSize(width: messagesLayout.itemWidth, height: height)
-    }
-
-    open func messageBottomLabelAlignment(for message: MessageType) -> LabelAlignment {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment
-    }
-
-    // MARK: - Accessory View
-
-    public func accessoryViewSize(for message: MessageType) -> CGSize {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingAccessoryViewSize : incomingAccessoryViewSize
-    }
-
-    public func accessoryViewPadding(for message: MessageType) -> HorizontalEdgeInsets {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingAccessoryViewPadding : incomingAccessoryViewPadding
-    }
-    
-    public func accessoryViewPosition(for message: MessageType) -> AccessoryPosition {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingAccessoryViewPosition : incomingAccessoryViewPosition
-    }
-
-    // MARK: - MessageContainer
-
-    open func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessagePadding : incomingMessagePadding
-    }
-
-    open func messageContainerSize(for message: MessageType) -> CGSize {
-        // Returns .zero by default
-        return .zero
-    }
-
-    open func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
-        let avatarWidth = avatarSize(for: message).width
-        let messagePadding = messageContainerPadding(for: message)
-        let accessoryWidth = accessoryViewSize(for: message).width
-        let accessoryPadding = accessoryViewPadding(for: message)
-        return messagesLayout.itemWidth - avatarWidth - messagePadding.horizontal - accessoryWidth - accessoryPadding.horizontal - avatarLeadingTrailingPadding
-    }
-
-    // MARK: - Helpers
-
-    public var messagesLayout: MessagesCollectionViewFlowLayout {
-        guard let layout = layout as? MessagesCollectionViewFlowLayout else {
-            fatalError("Layout object is missing or is not a MessagesCollectionViewFlowLayout")
-        }
-        return layout
-    }
-
-    internal func labelSize(for attributedText: NSAttributedString, considering maxWidth: CGFloat) -> CGSize {
-        let constraintBox = CGSize(width: maxWidth, height: .greatestFiniteMagnitude)
-        let rect = attributedText.boundingRect(with: constraintBox, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).integral
-
-        return rect.size
-    }
-}
-
-fileprivate extension UIEdgeInsets {
-    init(top: CGFloat = 0, bottom: CGFloat = 0, left: CGFloat = 0, right: CGFloat = 0) {
-        self.init(top: top, left: left, bottom: bottom, right: right)
-    }
-}

+ 0 - 342
deltachat-ios/MessageKit/Layout/MessagesCollectionViewFlowLayout.swift

@@ -1,342 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-import AVFoundation
-
-/// The layout object used by `MessagesCollectionView` to determine the size of all
-/// framework provided `MessageCollectionViewCell` subclasses.
-open class MessagesCollectionViewFlowLayout: UICollectionViewFlowLayout {
-
-    open override class var layoutAttributesClass: AnyClass {
-        return MessagesCollectionViewLayoutAttributes.self
-    }
-    
-    /// The `MessagesCollectionView` that owns this layout object.
-    public var messagesCollectionView: MessagesCollectionView {
-        guard let messagesCollectionView = collectionView as? MessagesCollectionView else {
-            fatalError(MessageKitError.layoutUsedOnForeignType)
-        }
-        return messagesCollectionView
-    }
-    
-    /// The `MessagesDataSource` for the layout's collection view.
-    public var messagesDataSource: MessagesDataSource {
-        guard let messagesDataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        return messagesDataSource
-    }
-    
-    /// The `MessagesLayoutDelegate` for the layout's collection view.
-    public var messagesLayoutDelegate: MessagesLayoutDelegate {
-        guard let messagesLayoutDelegate = messagesCollectionView.messagesLayoutDelegate else {
-            fatalError(MessageKitError.nilMessagesLayoutDelegate)
-        }
-        return messagesLayoutDelegate
-    }
-
-    public var itemWidth: CGFloat {
-        guard let collectionView = collectionView else { return 0 }
-        return collectionView.frame.width - sectionInset.left - sectionInset.right
-    }
-
-    public private(set) var isTypingIndicatorViewHidden: Bool = true
-
-    // MARK: - Initializers
-
-    public override init() {
-        super.init()
-        setupView()
-        setupObserver()
-    }
-
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        setupView()
-        setupObserver()
-    }
-
-    deinit {
-        NotificationCenter.default.removeObserver(self)
-    }
-    
-    // MARK: - Methods
-    
-    private func setupView() {
-        sectionInset = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
-    }
-    
-    private func setupObserver() {
-        NotificationCenter.default.addObserver(self,
-                                               selector: #selector(MessagesCollectionViewFlowLayout.handleOrientationChange(_:)),
-                                               name: UIDevice.orientationDidChangeNotification,
-                                               object: nil)
-    }
-
-    // MARK: - Typing Indicator API
-
-    /// Notifies the layout that the typing indicator will change state
-    ///
-    /// - Parameters:
-    ///   - isHidden: A Boolean value that is to be the new state of the typing indicator
-    internal func setTypingIndicatorViewHidden(_ isHidden: Bool) {
-        isTypingIndicatorViewHidden = isHidden
-    }
-
-    /// A method that by default checks if the section is the last in the
-    /// `messagesCollectionView` and that `isTypingIndicatorViewHidden`
-    /// is FALSE
-    ///
-    /// - Parameter section
-    /// - Returns: A Boolean indicating if the TypingIndicator should be presented at the given section
-    open func isSectionReservedForTypingIndicator(_ section: Int) -> Bool {
-        return !isTypingIndicatorViewHidden && section == messagesCollectionView.numberOfSections - 1
-    }
-
-    // MARK: - Attributes
-
-    open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
-        guard let attributesArray = super.layoutAttributesForElements(in: rect) as? [MessagesCollectionViewLayoutAttributes] else {
-            return nil
-        }
-        for attributes in attributesArray where attributes.representedElementCategory == .cell {
-            let cellSizeCalculator = cellSizeCalculatorForItem(at: attributes.indexPath)
-            cellSizeCalculator.configure(attributes: attributes)
-        }
-        return attributesArray
-    }
-
-    open override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
-        guard let attributes = super.layoutAttributesForItem(at: indexPath) as? MessagesCollectionViewLayoutAttributes else {
-            return nil
-        }
-        if attributes.representedElementCategory == .cell {
-            let cellSizeCalculator = cellSizeCalculatorForItem(at: attributes.indexPath)
-            cellSizeCalculator.configure(attributes: attributes)
-        }
-        return attributes
-    }
-
-    // MARK: - Layout Invalidation
-
-    open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
-        return collectionView?.bounds.width != newBounds.width
-    }
-
-    open override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
-        let context = super.invalidationContext(forBoundsChange: newBounds)
-        guard let flowLayoutContext = context as? UICollectionViewFlowLayoutInvalidationContext else { return context }
-        flowLayoutContext.invalidateFlowLayoutDelegateMetrics = shouldInvalidateLayout(forBoundsChange: newBounds)
-        return flowLayoutContext
-    }
-
-    @objc
-    private func handleOrientationChange(_ notification: Notification) {
-        invalidateLayout()
-    }
-
-    // MARK: - Cell Sizing
-
-    lazy open var textMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
-    lazy open var attributedTextMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
-    lazy open var emojiMessageSizeCalculator: TextMessageSizeCalculator = {
-        let sizeCalculator = TextMessageSizeCalculator(layout: self)
-        sizeCalculator.messageLabelFont = UIFont.systemFont(ofSize: sizeCalculator.messageLabelFont.pointSize * 2)
-        return sizeCalculator
-    }()
-    lazy open var textMediaMessageSizeCalculator = TextMediaMessageSizeCalculator(layout: self)
-    lazy open var fileMessageSizeCalculator = FileMessageSizeCalculator(layout: self)
-    lazy open var photoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
-    lazy open var videoMessageSizeCalculator = MediaMessageSizeCalculator(layout: self)
-    lazy open var locationMessageSizeCalculator = LocationMessageSizeCalculator(layout: self)
-    lazy open var audioMessageSizeCalculator = AudioMessageSizeCalculator(layout: self)
-    lazy open var contactMessageSizeCalculator = ContactMessageSizeCalculator(layout: self)
-    lazy open var typingIndicatorSizeCalculator = TypingCellSizeCalculator(layout: self)
-    lazy open var customMessageSizeCalculator = TextMessageSizeCalculator(layout: self)
-
-    /// Note:
-    /// - If you override this method, remember to call MessageLayoutDelegate's
-    /// customCellSizeCalculator(for:at:in:) method for MessageKind.custom messages, if necessary
-    /// - If you are using the typing indicator be sure to return the `typingIndicatorSizeCalculator`
-    /// when the section is reserved for it, indicated by `isSectionReservedForTypingIndicator`
-    open func cellSizeCalculatorForItem(at indexPath: IndexPath) -> CellSizeCalculator {
-        if isSectionReservedForTypingIndicator(indexPath.section) {
-            return typingIndicatorSizeCalculator
-        }
-        let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView)
-        switch message.kind {
-        case .text:
-            return textMessageSizeCalculator
-        case .attributedText:
-            return attributedTextMessageSizeCalculator
-        case .emoji:
-            return emojiMessageSizeCalculator
-        case .photo:
-            return photoMessageSizeCalculator
-        case .animatedImageText, .photoText, .videoText:
-            return textMediaMessageSizeCalculator
-        case .fileText:
-            return fileMessageSizeCalculator
-        case .video:
-            return videoMessageSizeCalculator
-        case .location:
-            return locationMessageSizeCalculator
-        case .audio:
-            return audioMessageSizeCalculator
-        case .contact:
-            return contactMessageSizeCalculator
-        case .info:
-            return customMessageSizeCalculator
-        case .custom:
-            return messagesLayoutDelegate.customCellSizeCalculator(for: message, at: indexPath, in: messagesCollectionView)
-        }
-    }
-
-    open func sizeForItem(at indexPath: IndexPath) -> CGSize {
-        let calculator = cellSizeCalculatorForItem(at: indexPath)
-        return calculator.sizeForItem(at: indexPath)
-    }
-
-    /// Set `incomingAvatarSize` of all `MessageSizeCalculator`s
-    public func setMessageIncomingAvatarSize(_ newSize: CGSize) {
-        messageSizeCalculators().forEach { $0.incomingAvatarSize = newSize }
-    }
-
-    /// Set `outgoingAvatarSize` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingAvatarSize(_ newSize: CGSize) {
-        messageSizeCalculators().forEach { $0.outgoingAvatarSize = newSize }
-    }
-
-    /// Set `incomingAvatarPosition` of all `MessageSizeCalculator`s
-    public func setMessageIncomingAvatarPosition(_ newPosition: AvatarPosition) {
-        messageSizeCalculators().forEach { $0.incomingAvatarPosition = newPosition }
-    }
-
-    /// Set `outgoingAvatarPosition` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingAvatarPosition(_ newPosition: AvatarPosition) {
-        messageSizeCalculators().forEach { $0.outgoingAvatarPosition = newPosition }
-    }
-
-    /// Set `avatarLeadingTrailingPadding` of all `MessageSizeCalculator`s
-    public func setAvatarLeadingTrailingPadding(_ newPadding: CGFloat) {
-        messageSizeCalculators().forEach { $0.avatarLeadingTrailingPadding = newPadding }
-    }
-
-    /// Set `incomingMessagePadding` of all `MessageSizeCalculator`s
-    public func setMessageIncomingMessagePadding(_ newPadding: UIEdgeInsets) {
-        messageSizeCalculators().forEach { $0.incomingMessagePadding = newPadding }
-    }
-
-    /// Set `outgoingMessagePadding` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingMessagePadding(_ newPadding: UIEdgeInsets) {
-        messageSizeCalculators().forEach { $0.outgoingMessagePadding = newPadding }
-    }
-
-    /// Set `incomingCellTopLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageIncomingCellTopLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.incomingCellTopLabelAlignment = newAlignment }
-    }
-
-    /// Set `outgoingCellTopLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingCellTopLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.outgoingCellTopLabelAlignment = newAlignment }
-    }
-
-    /// Set `incomingCellBottomLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageIncomingCellBottomLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.incomingCellBottomLabelAlignment = newAlignment }
-    }
-
-    /// Set `outgoingCellBottomLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingCellBottomLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.outgoingCellBottomLabelAlignment = newAlignment }
-    }
-
-    /// Set `incomingMessageTopLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageIncomingMessageTopLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.incomingMessageTopLabelAlignment = newAlignment }
-    }
-
-    /// Set `outgoingMessageTopLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingMessageTopLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.outgoingMessageTopLabelAlignment = newAlignment }
-    }
-
-    /// Set `incomingMessageBottomLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageIncomingMessageBottomLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.incomingMessageBottomLabelAlignment = newAlignment }
-    }
-
-    /// Set `outgoingMessageBottomLabelAlignment` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingMessageBottomLabelAlignment(_ newAlignment: LabelAlignment) {
-        messageSizeCalculators().forEach { $0.outgoingMessageBottomLabelAlignment = newAlignment }
-    }
-
-    /// Set `incomingAccessoryViewSize` of all `MessageSizeCalculator`s
-    public func setMessageIncomingAccessoryViewSize(_ newSize: CGSize) {
-        messageSizeCalculators().forEach { $0.incomingAccessoryViewSize = newSize }
-    }
-
-    /// Set `outgoingAccessoryViewSize` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingAccessoryViewSize(_ newSize: CGSize) {
-        messageSizeCalculators().forEach { $0.outgoingAccessoryViewSize = newSize }
-    }
-
-    /// Set `incomingAccessoryViewPadding` of all `MessageSizeCalculator`s
-    public func setMessageIncomingAccessoryViewPadding(_ newPadding: HorizontalEdgeInsets) {
-        messageSizeCalculators().forEach { $0.incomingAccessoryViewPadding = newPadding }
-    }
-
-    /// Set `outgoingAccessoryViewPadding` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingAccessoryViewPadding(_ newPadding: HorizontalEdgeInsets) {
-        messageSizeCalculators().forEach { $0.outgoingAccessoryViewPadding = newPadding }
-    }
-
-    /// Set `incomingAccessoryViewPosition` of all `MessageSizeCalculator`s
-    public func setMessageIncomingAccessoryViewPosition(_ newPosition: AccessoryPosition) {
-        messageSizeCalculators().forEach { $0.incomingAccessoryViewPosition = newPosition }
-    }
-
-    /// Set `outgoingAccessoryViewPosition` of all `MessageSizeCalculator`s
-    public func setMessageOutgoingAccessoryViewPosition(_ newPosition: AccessoryPosition) {
-        messageSizeCalculators().forEach { $0.outgoingAccessoryViewPosition = newPosition }
-    }
-
-    /// Get all `MessageSizeCalculator`s
-    open func messageSizeCalculators() -> [MessageSizeCalculator] {
-        return [textMessageSizeCalculator,
-                attributedTextMessageSizeCalculator,
-                emojiMessageSizeCalculator,
-                fileMessageSizeCalculator,
-                textMediaMessageSizeCalculator,
-                photoMessageSizeCalculator,
-                videoMessageSizeCalculator,
-                locationMessageSizeCalculator,
-                audioMessageSizeCalculator,
-                contactMessageSizeCalculator
-        ]
-    }
-
-}

+ 0 - 109
deltachat-ios/MessageKit/Layout/MessagesCollectionViewLayoutAttributes.swift

@@ -1,109 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// The layout attributes used by a `MessageCollectionViewCell` to layout its subviews.
-open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttributes {
-
-    // MARK: - Properties
-
-    public var avatarSize: CGSize = .zero
-    public var avatarPosition = AvatarPosition(vertical: .cellBottom)
-    public var avatarLeadingTrailingPadding: CGFloat = 0
-
-    public var messageContainerSize: CGSize = .zero
-    public var messageContainerPadding: UIEdgeInsets = .zero
-    public var messageLabelFont: UIFont = UIFont.preferredFont(forTextStyle: .body)
-    public var messageLabelInsets: UIEdgeInsets = .zero
-
-    public var cellTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
-    public var cellTopLabelSize: CGSize = .zero
-
-    public var cellBottomLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
-    public var cellBottomLabelSize: CGSize = .zero
-
-    public var messageTopLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
-    public var messageTopLabelSize: CGSize = .zero
-
-    public var messageBottomLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
-    public var messageBottomLabelSize: CGSize = .zero
-
-    public var accessoryViewSize: CGSize = .zero
-    public var accessoryViewPadding: HorizontalEdgeInsets = .zero
-    public var accessoryViewPosition: AccessoryPosition = .messageCenter
-
-    // MARK: - Methods
-
-    open override func copy(with zone: NSZone? = nil) -> Any {
-        // swiftlint:disable force_cast
-        let copy = super.copy(with: zone) as! MessagesCollectionViewLayoutAttributes
-        copy.avatarSize = avatarSize
-        copy.avatarPosition = avatarPosition
-        copy.avatarLeadingTrailingPadding = avatarLeadingTrailingPadding
-        copy.messageContainerSize = messageContainerSize
-        copy.messageContainerPadding = messageContainerPadding
-        copy.messageLabelFont = messageLabelFont
-        copy.messageLabelInsets = messageLabelInsets
-        copy.cellTopLabelAlignment = cellTopLabelAlignment
-        copy.cellTopLabelSize = cellTopLabelSize
-        copy.cellBottomLabelAlignment = cellBottomLabelAlignment
-        copy.cellBottomLabelSize = cellBottomLabelSize
-        copy.messageTopLabelAlignment = messageTopLabelAlignment
-        copy.messageTopLabelSize = messageTopLabelSize
-        copy.messageBottomLabelAlignment = messageBottomLabelAlignment
-        copy.messageBottomLabelSize = messageBottomLabelSize
-        copy.accessoryViewSize = accessoryViewSize
-        copy.accessoryViewPadding = accessoryViewPadding
-        copy.accessoryViewPosition = accessoryViewPosition
-        return copy
-        // swiftlint:enable force_cast
-    }
-
-    open override func isEqual(_ object: Any?) -> Bool {
-        // MARK: - LEAVE this as is
-        if let attributes = object as? MessagesCollectionViewLayoutAttributes {
-            return super.isEqual(object) && attributes.avatarSize == avatarSize
-                && attributes.avatarPosition == avatarPosition
-                && attributes.avatarLeadingTrailingPadding == avatarLeadingTrailingPadding
-                && attributes.messageContainerSize == messageContainerSize
-                && attributes.messageContainerPadding == messageContainerPadding
-                && attributes.messageLabelFont == messageLabelFont
-                && attributes.messageLabelInsets == messageLabelInsets
-                && attributes.cellTopLabelAlignment == cellTopLabelAlignment
-                && attributes.cellTopLabelSize == cellTopLabelSize
-                && attributes.cellBottomLabelAlignment == cellBottomLabelAlignment
-                && attributes.cellBottomLabelSize == cellBottomLabelSize
-                && attributes.messageTopLabelAlignment == messageTopLabelAlignment
-                && attributes.messageTopLabelSize == messageTopLabelSize
-                && attributes.messageBottomLabelAlignment == messageBottomLabelAlignment
-                && attributes.messageBottomLabelSize == messageBottomLabelSize
-                && attributes.accessoryViewSize == accessoryViewSize
-                && attributes.accessoryViewPadding == accessoryViewPadding
-                && attributes.accessoryViewPosition == accessoryViewPosition
-        } else {
-            return false
-        }
-    }
-}

+ 0 - 131
deltachat-ios/MessageKit/Layout/TextMediaMessageSizeCalculator.swift

@@ -1,131 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class TextMediaMessageSizeCalculator: MessageSizeCalculator {
-
-    private var maxMediaItemHeight: CGFloat {
-        return UIScreen.main.bounds.size.height * 0.7
-    }
-
-    private let minTextWidth: CGFloat = 180
-
-    public var incomingMessageLabelInsets = UIEdgeInsets(top: TextMediaMessageCell.insetTop,
-                                                         left: TextMediaMessageCell.insetHorizontalBig,
-                                                         bottom: TextMediaMessageCell.insetBottom,
-                                                         right: TextMediaMessageCell.insetHorizontalSmall)
-    public var outgoingMessageLabelInsets = UIEdgeInsets(top: TextMediaMessageCell.insetTop,
-                                                         left: TextMediaMessageCell.insetHorizontalSmall,
-                                                         bottom: TextMediaMessageCell.insetBottom,
-                                                         right: TextMediaMessageCell.insetHorizontalBig)
-
-    public var messageLabelFont = UIFont.preferredFont(forTextStyle: .body)
-
-    internal func messageLabelInsets(for message: MessageType) -> UIEdgeInsets {
-        let dataSource = messagesLayout.messagesDataSource
-        let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-        return isFromCurrentSender ? outgoingMessageLabelInsets : incomingMessageLabelInsets
-    }
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        let maxImageWidth = messageContainerMaxWidth(for: message)
-
-        let sizeForMediaItem = { (maxWidth: CGFloat, item: MediaItem) -> CGSize in
-            var maxTextWidth = maxWidth - self.messageLabelInsets(for: message).horizontal
-            var imageHeight = item.size.height
-            var imageWidth = item.size.width
-
-            if maxWidth < item.size.width {
-                // Maintain the ratio if width is too great
-                imageHeight = maxWidth * item.size.height / item.size.width
-                imageWidth = maxWidth
-            }
-
-            if self.maxMediaItemHeight < imageHeight {
-                // Maintain the ratio if height is too great
-                imageWidth = self.maxMediaItemHeight * imageWidth / imageHeight
-                imageHeight = self.maxMediaItemHeight
-                maxTextWidth = imageWidth - self.messageLabelInsets(for: message).horizontal
-
-            }
-
-            if imageWidth < self.minTextWidth {
-                // if text will be too narrow, increase again the size
-                imageHeight = self.minTextWidth * imageHeight / imageWidth
-                imageWidth = self.minTextWidth
-                maxTextWidth = imageWidth - self.messageLabelInsets(for: message).horizontal
-            }
-
-            var messageContainerSize = CGSize(width: imageWidth, height: imageHeight)
-            switch message.kind {
-            case .photoText(let mediaItem), .animatedImageText(let mediaItem):
-                if let text = mediaItem.text?[MediaItemConstants.messageText] {
-                    let textHeight = text.height(withConstrainedWidth: maxTextWidth)
-                    messageContainerSize.height += textHeight
-                    messageContainerSize.height +=  self.messageLabelInsets(for: message).vertical
-                }
-                return messageContainerSize
-            case .videoText(let mediaItem):
-                var videoContainerSize = CGSize(width: self.minTextWidth, height: self.minTextWidth)
-                if let text = mediaItem.text?[MediaItemConstants.messageText] {
-                    let textHeight = text.height(withConstrainedWidth: maxTextWidth)
-                    // static size for thumbnails
-                    videoContainerSize.height += textHeight
-                    videoContainerSize.height += self.messageLabelInsets(for: message).vertical
-                }
-                return videoContainerSize
-            default:
-                return messageContainerSize
-            }
-        }
-
-        switch message.kind {
-        case .photoText(let item), .videoText(let item), .animatedImageText(let item):
-            return sizeForMediaItem(maxImageWidth, item)
-        default:
-            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-        }
-    }
-
-    open override func configure(attributes: UICollectionViewLayoutAttributes) {
-        super.configure(attributes: attributes)
-        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
-
-        let dataSource = messagesLayout.messagesDataSource
-        let indexPath = attributes.indexPath
-        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
-
-        switch message.kind {
-        case .photoText, .videoText, .animatedImageText:
-            attributes.messageLabelInsets = messageLabelInsets(for: message)
-            attributes.messageLabelFont = messageLabelFont
-        default:
-            break
-        }
-    }
-
-
-}

+ 0 - 97
deltachat-ios/MessageKit/Layout/TextMessageSizeCalculator.swift

@@ -1,97 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class TextMessageSizeCalculator: MessageSizeCalculator {
-
-    public var incomingMessageLabelInsets = UIEdgeInsets(top: 7, left: 18, bottom: 7, right: 14)
-    public var outgoingMessageLabelInsets = UIEdgeInsets(top: 7, left: 14, bottom: 7, right: 18)
-    public var centeredMessageLabelInsets = UIEdgeInsets(top: 7, left: 16, bottom: 7, right: 16)
-
-    public var messageLabelFont = UIFont.preferredFont(forTextStyle: .body)
-
-    internal func messageLabelInsets(for message: MessageType) -> UIEdgeInsets {
-        switch message.kind {
-        case .info:
-            return centeredMessageLabelInsets
-        default:
-            let dataSource = messagesLayout.messagesDataSource
-            let isFromCurrentSender = dataSource.isFromCurrentSender(message: message)
-            return isFromCurrentSender ? outgoingMessageLabelInsets : incomingMessageLabelInsets
-        }
-    }
-
-    open override func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
-        let maxWidth = super.messageContainerMaxWidth(for: message)
-        let textInsets = messageLabelInsets(for: message)
-        return maxWidth - textInsets.horizontal
-    }
-
-    open override func messageContainerSize(for message: MessageType) -> CGSize {
-        let maxWidth = messageContainerMaxWidth(for: message)
-
-        var messageContainerSize: CGSize
-        let attributedText: NSAttributedString
-
-        switch message.kind {
-        case .attributedText(let text), .info(let text):
-            attributedText = text
-        case .text(let text), .emoji(let text):
-            attributedText = NSAttributedString(string: text, attributes: [.font: messageLabelFont])
-        default:
-            fatalError("messageContainerSize received unhandled MessageDataType: \(message.kind)")
-        }
-
-        messageContainerSize = labelSize(for: attributedText, considering: maxWidth)
-
-        let messageInsets = messageLabelInsets(for: message)
-        messageContainerSize.width += messageInsets.horizontal
-        messageContainerSize.height += messageInsets.vertical
-
-        return messageContainerSize
-    }
-
-    open override func configure(attributes: UICollectionViewLayoutAttributes) {
-        super.configure(attributes: attributes)
-        guard let attributes = attributes as? MessagesCollectionViewLayoutAttributes else { return }
-
-        let dataSource = messagesLayout.messagesDataSource
-        let indexPath = attributes.indexPath
-        let message = dataSource.messageForItem(at: indexPath, in: messagesLayout.messagesCollectionView)
-
-        attributes.messageLabelInsets = messageLabelInsets(for: message)
-        attributes.messageLabelFont = messageLabelFont
-
-        switch message.kind {
-        case .attributedText(let text):
-            guard !text.string.isEmpty else { return }
-            guard let font = text.attribute(.font, at: 0, effectiveRange: nil) as? UIFont else { return }
-            attributes.messageLabelFont = font
-        default:
-            break
-        }
-    }
-}

+ 0 - 43
deltachat-ios/MessageKit/Layout/TypingIndicatorCellSizeCalculator.swift

@@ -1,43 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class TypingCellSizeCalculator: CellSizeCalculator {
-
-    open var height: CGFloat = 62
-
-    public init(layout: MessagesCollectionViewFlowLayout? = nil) {
-        super.init()
-        self.layout = layout
-    }
-
-    open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
-        guard let layout = layout else { return .zero }
-        let collectionViewWidth = layout.collectionView?.bounds.width ?? 0
-        let contentInset = layout.collectionView?.contentInset ?? .zero
-        let inset = layout.sectionInset.horizontal + contentInset.horizontal
-        return CGSize(width: collectionViewWidth - inset, height: height)
-    }
-}

+ 0 - 48
deltachat-ios/MessageKit/Models/AccessoryPosition.swift

@@ -1,48 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// Used to determine the `Horizontal` and `Vertical` position of
-// an `AccessoryView` in a `MessageCollectionViewCell`.
-public enum AccessoryPosition {
-    
-    /// Aligns the `AccessoryView`'s top edge to the cell's top edge.
-    case cellTop
-    
-    /// Aligns the `AccessoryView`'s top edge to the `messageTopLabel`'s top edge.
-    case messageLabelTop
-    
-    /// Aligns the `AccessoryView`'s top edge to the `MessageContainerView`'s top edge.
-    case messageTop
-    
-    /// Aligns the `AccessoryView` center to the `MessageContainerView` center.
-    case messageCenter
-    
-    /// Aligns the `AccessoryView`'s bottom edge to the `MessageContainerView`s bottom edge.
-    case messageBottom
-    
-    /// Aligns the `AccessoryView`'s bottom edge to the cell's bottom edge.
-    case cellBottom
-}

+ 0 - 48
deltachat-ios/MessageKit/Models/Avatar.swift

@@ -1,48 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-/// An object used to group the information to be used by an `AvatarView`.
-public struct Avatar {
-    
-    // MARK: - Properties
-    
-    /// The image to be used for an `AvatarView`.
-    public let image: UIImage?
-    
-    /// The placeholder initials to be used in the case where no image is provided.
-    ///
-    /// The default value of this property is "?".
-    public var initials: String = "?"
-    
-    // MARK: - Initializer
-    
-    public init(image: UIImage? = nil, initials: String = "?") {
-        self.image = image
-        self.initials = initials
-    }
-    
-}

+ 0 - 98
deltachat-ios/MessageKit/Models/AvatarPosition.swift

@@ -1,98 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// Used to determine the `Horizontal` and `Vertical` position of
-// an `AvatarView` in a `MessageCollectionViewCell`.
-public struct AvatarPosition: Equatable {
-    
-    /// An enum representing the horizontal alignment of an `AvatarView`.
-    public enum Horizontal {
-        
-        /// Positions the `AvatarView` on the side closest to the cell's leading edge.
-        case cellLeading
-        
-        /// Positions the `AvatarView` on the side closest to the cell's trailing edge.
-        case cellTrailing
-        
-        /// Positions the `AvatarView` based on whether the message is from the current Sender.
-        /// The cell is positioned `.cellTrailling` if `isFromCurrentSender` is true
-        /// and `.cellLeading` if false.
-        case natural
-    }
-    
-    /// An enum representing the verical alignment for an `AvatarView`.
-    public enum Vertical {
-        
-        /// Aligns the `AvatarView`'s top edge to the cell's top edge.
-        case cellTop
-        
-        /// Aligns the `AvatarView`'s top edge to the `messageTopLabel`'s top edge.
-        case messageLabelTop
-        
-        /// Aligns the `AvatarView`'s top edge to the `MessageContainerView`'s top edge.
-        case messageTop
-        
-        /// Aligns the `AvatarView` center to the `MessageContainerView` center.
-        case messageCenter
-        
-        /// Aligns the `AvatarView`'s bottom edge to the `MessageContainerView`s bottom edge.
-        case messageBottom
-        
-        /// Aligns the `AvatarView`'s bottom edge to the cell's bottom edge.
-        case cellBottom
-        
-    }
-    
-    // MARK: - Properties
-    
-    // The vertical position
-    public var vertical: Vertical
-    
-    // The horizontal position
-    public var horizontal: Horizontal
-    
-    // MARK: - Initializers
-    
-    public init(horizontal: Horizontal, vertical: Vertical) {
-        self.horizontal = horizontal
-        self.vertical = vertical
-    }
-
-    public init(vertical: Vertical) {
-        self.init(horizontal: .natural, vertical: vertical)
-    }
-    
-}
-
-// MARK: - Equatable Conformance
-
-public extension AvatarPosition {
-
-    static func == (lhs: AvatarPosition, rhs: AvatarPosition) -> Bool {
-        return lhs.vertical == rhs.vertical && lhs.horizontal == rhs.horizontal
-    }
-
-}

+ 0 - 56
deltachat-ios/MessageKit/Models/HorizontalEdgeInsets.swift

@@ -1,56 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-/// A varient of `UIEdgeInsets` that only has horizontal inset properties
-public struct HorizontalEdgeInsets: Equatable {
-
-    public var left: CGFloat
-    public var right: CGFloat
-
-    public init(left: CGFloat, right: CGFloat) {
-        self.left = left
-        self.right = right
-    }
-
-    public static var zero: HorizontalEdgeInsets {
-        return HorizontalEdgeInsets(left: 0, right: 0)
-    }
-}
-
-public extension HorizontalEdgeInsets {
-
-    static func == (lhs: HorizontalEdgeInsets, rhs: HorizontalEdgeInsets) -> Bool {
-        return lhs.left == rhs.left && lhs.right == rhs.right
-    }
-}
-
-internal extension HorizontalEdgeInsets {
-
-    var horizontal: CGFloat {
-        return left + right
-    }
-}

+ 0 - 47
deltachat-ios/MessageKit/Models/LabelAlignment.swift

@@ -1,47 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-public struct LabelAlignment: Equatable {
-
-    public var textAlignment: NSTextAlignment
-    public var textInsets: UIEdgeInsets
-    
-    public init(textAlignment: NSTextAlignment, textInsets: UIEdgeInsets) {
-        self.textAlignment = textAlignment
-        self.textInsets = textInsets
-    }
-
-}
-
-// MARK: - Equatable Conformance
-
-public extension LabelAlignment {
-
-    static func == (lhs: LabelAlignment, rhs: LabelAlignment) -> Bool {
-        return lhs.textAlignment == rhs.textAlignment && lhs.textInsets == rhs.textInsets
-    }
-
-}

+ 0 - 64
deltachat-ios/MessageKit/Models/LocationMessageSnapshotOptions.swift

@@ -1,64 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import MapKit
-
-/// An object grouping the settings used by the `MKMapSnapshotter` through the `LocationMessageDisplayDelegate`.
-public struct LocationMessageSnapshotOptions {
-
-    /// Initialize LocationMessageSnapshotOptions with given parameters
-    ///
-    /// - Parameters:
-    ///   - showsBuildings: A Boolean value indicating whether the snapshot image should display buildings.
-    ///   - showsPointsOfInterest: A Boolean value indicating whether the snapshot image should display points of interest.
-    ///   - span: The span of the snapshot.
-    ///   - scale: The scale of the snapshot.
-    public init(showsBuildings: Bool = false, showsPointsOfInterest: Bool = false, span: MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 0), scale: CGFloat = UIScreen.main.scale) {
-        self.showsBuildings = showsBuildings
-        self.showsPointsOfInterest = showsPointsOfInterest
-        self.span = span
-        self.scale = scale
-    }
-    
-    /// A Boolean value indicating whether the snapshot image should display buildings.
-    ///
-    /// The default value of this property is `false`.
-    public var showsBuildings: Bool
-    
-    /// A Boolean value indicating whether the snapshot image should display points of interest.
-    ///
-    /// The default value of this property is `false`.
-    public var showsPointsOfInterest: Bool
-    
-    /// The span of the snapshot.
-    ///
-    /// The default value of this property uses a width of `0` and height of `0`.
-    public var span: MKCoordinateSpan
-    
-    /// The scale of the snapshot.
-    ///
-    /// The default value of this property uses the `UIScreen.main.scale`.
-    public var scale: CGFloat
-    
-}

+ 0 - 86
deltachat-ios/MessageKit/Models/MessageKind.swift

@@ -1,86 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// An enum representing the kind of message and its underlying kind.
-public enum MessageKind {
-
-    /// A standard text message.
-    ///
-    /// - Note: The font used for this message will be the value of the
-    /// `messageLabelFont` property in the `MessagesCollectionViewFlowLayout` object.
-    ///
-    /// Using `MessageKind.attributedText(NSAttributedString)` doesn't require you
-    /// to set this property and results in higher performance.
-    case text(String)
-
-    /// A message with attributed text.
-    case attributedText(NSAttributedString)
-
-    case info(NSAttributedString)
-
-    /// A photo message.
-    case photo(MediaItem)
-
-    /// A photo message with a textual description
-    case photoText(MediaItem)
-
-    /// A message containing an animated Image and an optional text
-    case animatedImageText(MediaItem)
-
-    /// A file message with an optional text
-    case fileText(MediaItem)
-
-    /// A video message.
-    case video(MediaItem)
-
-    /// A video message with a textual description
-    case videoText(MediaItem)
-
-    /// A location message.
-    case location(LocationItem)
-
-    /// An emoji message.
-    case emoji(String)
-
-    /// An audio message.
-    case audio(AudioItem)
-    
-    /// A contact message.
-    case contact(ContactItem)
-
-    /// A custom message.
-    /// - Note: Using this case requires that you implement the following methods and handle this case:
-    ///   - MessagesDataSource: customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
-    ///   - MessagesLayoutDelegate: customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator
-    case custom(Any?)
-
-    // MARK: - Not supported yet
-
-//    case system(String)
-//    
-//    case placeholder
-
-}

+ 0 - 66
deltachat-ios/MessageKit/Models/MessageKitDateFormatter.swift

@@ -1,66 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-open class MessageKitDateFormatter {
-
-    // MARK: - Properties
-
-    public static let shared = MessageKitDateFormatter()
-
-    private let formatter = DateFormatter()
-
-    // MARK: - Initializer
-
-    private init() {}
-
-    // MARK: - Methods
-
-    public func string(from date: Date) -> String {
-        configureDateFormatter(for: date)
-        return formatter.string(from: date)
-    }
-
-    public func attributedString(from date: Date, with attributes: [NSAttributedString.Key: Any]) -> NSAttributedString {
-        let dateString = string(from: date)
-        return NSAttributedString(string: dateString, attributes: attributes)
-    }
-
-    open func configureDateFormatter(for date: Date) {
-        switch true {
-        case Calendar.current.isDateInToday(date) || Calendar.current.isDateInYesterday(date):
-            formatter.doesRelativeDateFormatting = true
-            formatter.dateStyle = .short
-            formatter.timeStyle = .short
-        case Calendar.current.isDate(date, equalTo: Date(), toGranularity: .weekOfYear):
-            formatter.dateFormat = "EEEE h:mm a"
-        case Calendar.current.isDate(date, equalTo: Date(), toGranularity: .year):
-            formatter.dateFormat = "E, d MMM, h:mm a"
-        default:
-            formatter.dateFormat = "MMM d, yyyy, h:mm a"
-        }
-    }
-    
-}

+ 0 - 38
deltachat-ios/MessageKit/Models/MessageKitError.swift

@@ -1,38 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-internal enum MessageKitError {
-    internal static let avatarPositionUnresolved = "AvatarPosition Horizontal.natural needs to be resolved."
-    internal static let nilMessagesDataSource = "MessagesDataSource has not been set."
-    internal static let nilMessagesDisplayDelegate = "MessagesDisplayDelegate has not been set."
-    internal static let nilMessagesLayoutDelegate = "MessagesLayoutDelegate has not been set."
-    internal static let notMessagesCollectionView = "The collectionView is not a MessagesCollectionView."
-    internal static let layoutUsedOnForeignType = "MessagesCollectionViewFlowLayout is being used on a foreign type."
-    internal static let unrecognizedSectionKind = "Received unrecognized element kind:"
-    internal static let unrecognizedCheckingResult = "Received an unrecognized NSTextCheckingResult.CheckingType"
-    internal static let couldNotLoadAssetsBundle = "MessageKit: Could not load the assets bundle"
-    internal static let couldNotCreateAssetsPath = "MessageKit: Could not create path to the assets bundle."
-    internal static let customDataUnresolvedCell = "Did not return a cell for MessageKind.custom(Any)."
-    internal static let customDataUnresolvedSize = "Did not return a size for MessageKind.custom(Any)."
-}

+ 0 - 151
deltachat-ios/MessageKit/Models/MessageStyle.swift

@@ -1,151 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-public enum MessageStyle {
-
-    // MARK: - TailCorner
-
-    public enum TailCorner: String {
-
-        case topLeft
-        case bottomLeft
-        case topRight
-        case bottomRight
-
-        internal var imageOrientation: UIImage.Orientation {
-            switch self {
-            case .bottomRight: return .up
-            case .bottomLeft: return .upMirrored
-            case .topLeft: return .down
-            case .topRight: return .downMirrored
-            }
-        }
-    }
-
-    // MARK: - TailStyle
-
-    public enum TailStyle {
-
-        case curved
-        case pointedEdge
-
-        internal var imageNameSuffix: String {
-            switch self {
-            case .curved:
-                return "_tail_v2"
-            case .pointedEdge:
-                return "_tail_v1"
-            }
-        }
-    }
-
-    // MARK: - MessageStyle
-
-    case none
-    case bubble
-    case bubbleOutline(UIColor)
-    case bubbleTail(TailCorner, TailStyle)
-    case bubbleTailOutline(UIColor, TailCorner, TailStyle)
-    case custom((MessageContainerView) -> Void)
-
-    // MARK: - Public
-
-    public var image: UIImage? {
-        
-        guard let imageCacheKey = imageCacheKey, let path = imagePath else { return nil }
-
-        let cache = MessageStyle.bubbleImageCache
-
-        if let cachedImage = cache.object(forKey: imageCacheKey as NSString) {
-            return cachedImage
-        }
-        guard var image = UIImage(contentsOfFile: path) else { return nil }
-        
-        switch self {
-        case .none, .custom:
-            return nil
-        case .bubble, .bubbleOutline:
-            break
-        case .bubbleTail(let corner, _), .bubbleTailOutline(_, let corner, _):
-            guard let cgImage = image.cgImage else { return nil }
-            image = UIImage(cgImage: cgImage, scale: image.scale, orientation: corner.imageOrientation)
-        }
-        
-        let stretchedImage = stretch(image)
-        cache.setObject(stretchedImage, forKey: imageCacheKey as NSString)
-        return stretchedImage
-    }
-
-    // MARK: - Internal
-    
-    internal static let bubbleImageCache: NSCache<NSString, UIImage> = {
-        let cache = NSCache<NSString, UIImage>()
-        cache.name = "com.messagekit.MessageKit.bubbleImageCache"
-        return cache
-    }()
-    
-    // MARK: - Private
-    
-    private var imageCacheKey: String? {
-        guard let imageName = imageName else { return nil }
-        
-        switch self {
-        case .bubble, .bubbleOutline:
-            return imageName
-        case .bubbleTail(let corner, _), .bubbleTailOutline(_, let corner, _):
-            return imageName + "_" + corner.rawValue
-        default:
-            return nil
-        }
-    }
-
-    private var imageName: String? {
-        switch self {
-        case .bubble:
-            return "bubble_full"
-        case .bubbleOutline:
-            return "bubble_outlined"
-        case .bubbleTail(_, let tailStyle):
-            return "bubble_full" + tailStyle.imageNameSuffix
-        case .bubbleTailOutline(_, _, let tailStyle):
-            return "bubble_outlined" + tailStyle.imageNameSuffix
-        case .none, .custom:
-            return nil
-        }
-    }
-
-    private var imagePath: String? {
-        guard let imageName = imageName else { return nil }
-        let assetBundle = Bundle.messageKitAssetBundle()
-        return assetBundle.path(forResource: imageName, ofType: "png", inDirectory: "Images")
-    }
-
-    private func stretch(_ image: UIImage) -> UIImage {
-        let center = CGPoint(x: image.size.width / 2, y: image.size.height / 2)
-        let capInsets = UIEdgeInsets(top: center.y, left: center.x, bottom: center.y, right: center.x)
-        return image.resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
-    }
-}

+ 0 - 81
deltachat-ios/MessageKit/Models/NSConstraintLayoutSet.swift

@@ -1,81 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-internal class NSLayoutConstraintSet {
-    
-    internal var top: NSLayoutConstraint?
-    internal var bottom: NSLayoutConstraint?
-    internal var left: NSLayoutConstraint?
-    internal var right: NSLayoutConstraint?
-    internal var centerX: NSLayoutConstraint?
-    internal var centerY: NSLayoutConstraint?
-    internal var width: NSLayoutConstraint?
-    internal var height: NSLayoutConstraint?
-    
-    internal init(top: NSLayoutConstraint? = nil, bottom: NSLayoutConstraint? = nil,
-                  left: NSLayoutConstraint? = nil, right: NSLayoutConstraint? = nil,
-                  centerX: NSLayoutConstraint? = nil, centerY: NSLayoutConstraint? = nil,
-                  width: NSLayoutConstraint? = nil, height: NSLayoutConstraint? = nil) {
-        self.top = top
-        self.bottom = bottom
-        self.left = left
-        self.right = right
-        self.centerX = centerX
-        self.centerY = centerY
-        self.width = width
-        self.height = height
-    }
-
-    /// All of the currently configured constraints
-    private var availableConstraints: [NSLayoutConstraint] {
-        let constraints = [top, bottom, left, right, centerX, centerY, width, height]
-        var available: [NSLayoutConstraint] = []
-        for constraint in constraints {
-            if let value = constraint {
-                available.append(value)
-            }
-        }
-        return available
-    }
-    
-    /// Activates all of the non-nil constraints
-    ///
-    /// - Returns: Self
-    @discardableResult
-    internal func activate() -> Self {
-        NSLayoutConstraint.activate(availableConstraints)
-        return self
-    }
-    
-    /// Deactivates all of the non-nil constraints
-    ///
-    /// - Returns: Self
-    @discardableResult
-    internal func deactivate() -> Self {
-        NSLayoutConstraint.deactivate(availableConstraints)
-        return self
-    }
-}

+ 0 - 57
deltachat-ios/MessageKit/Models/Sender.swift

@@ -1,57 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// An object that groups the metadata of a messages sender.
-@available(*, deprecated: 3.0.0, message: "`Sender` has been replaced with the `SenderType` protocol in 3.0.0")
-public struct Sender: SenderType {
-
-    /// MARK: - Properties
-
-    /// The unique String identifier for the sender.
-    ///
-    /// Note: This value must be unique across all senders.
-    public let senderId: String
-
-    @available(*, deprecated: 3.0.0, message: "`id` has been renamed `senderId` as defined in the `SenderType` protocol")
-    public var id: String {
-        return senderId
-    }
-
-    /// The display name of a sender.
-    public let displayName: String
-
-    // MARK: - Intializers
-
-    public init(senderId: String, displayName: String) {
-        self.senderId = senderId
-        self.displayName = displayName
-    }
-
-    @available(*, deprecated: 3.0.0, message: "`id` has been renamed `senderId` as defined in the `SenderType` protocol")
-    public init(id: String, displayName: String) {
-        self.init(senderId: id, displayName: displayName)
-    }
-}

+ 0 - 42
deltachat-ios/MessageKit/Protocols/AudioItem.swift

@@ -1,42 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import class AVFoundation.AVAudioPlayer
-import UIKit
-
-/// A protocol used to represent the data for an audio message.
-public protocol AudioItem {
-
-    /// The url where the audio file is located.
-    var url: URL { get }
-
-    /// The audio file duration in seconds.
-    var duration: Float { get }
-
-    /// The size of the audio item.
-    var size: CGSize { get }
-
-    /// Additional text
-    var text: NSAttributedString? { get }
-}

+ 0 - 41
deltachat-ios/MessageKit/Protocols/ContactItem.swift

@@ -1,41 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2018 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// A protocol used to represent the data for a contact message.
-public protocol ContactItem {
-    
-    /// contact displayed name
-    var displayName: String { get }
-    
-    /// initials from contact first and last name
-    var initials: String { get }
-    
-    /// contact phone numbers
-    var phoneNumbers: [String] { get }
-    
-    /// contact emails
-    var emails: [String] { get }
-}

+ 0 - 37
deltachat-ios/MessageKit/Protocols/LocationItem.swift

@@ -1,37 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import class CoreLocation.CLLocation
-import UIKit
-
-/// A protocol used to represent the data for a location message.
-public protocol LocationItem {
-
-    /// The location.
-    var location: CLLocation { get }
-
-    /// The size of the location item.
-    var size: CGSize { get }
-
-}

+ 0 - 50
deltachat-ios/MessageKit/Protocols/MediaItem.swift

@@ -1,50 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-/// A protocol used to represent the data for a media message.
-public protocol MediaItem {
-
-    /// The url where the media is located.
-    var url: URL? { get }
-
-    /// The image.
-    var image: UIImage? { get }
-
-    /// A placeholder image for when the image is obtained asychronously.
-    var placeholderImage: UIImage { get }
-
-    /// The size of the media item.
-    var size: CGSize { get }
-
-    var text: [NSAttributedString]? { get }
-}
-
-struct MediaItemConstants {
-    static let messageText = 0
-    static let mediaTitle = 1
-    static let mediaSubtitle = 2
-}

+ 0 - 180
deltachat-ios/MessageKit/Protocols/MessageCellDelegate.swift

@@ -1,180 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// A protocol used by `MessageContentCell` subclasses to detect taps in the cell's subviews.
-public protocol MessageCellDelegate: MessageLabelDelegate {
-
-    /// Triggered when a tap occurs in the background of the cell.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the tap occurred.
-    ///
-    /// - Note:
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapBackground(in cell: MessageCollectionViewCell)
-
-    /// Triggered when a tap occurs in the `MessageContainerView`.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the tap occurred.
-    ///
-    /// - Note:
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapMessage(in cell: MessageCollectionViewCell)
-
-    /// Triggered when a tap occurs in the `AvatarView`.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the tap occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapAvatar(in cell: MessageCollectionViewCell)
-
-    /// Triggered when a tap occurs in the cellTopLabel.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell tap the touch occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapCellTopLabel(in cell: MessageCollectionViewCell)
-    
-    /// Triggered when a tap occurs in the cellBottomLabel.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell tap the touch occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapCellBottomLabel(in cell: MessageCollectionViewCell)
-    
-    /// Triggered when a tap occurs in the messageTopLabel.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell tap the touch occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapMessageTopLabel(in cell: MessageCollectionViewCell)
-
-    /// Triggered when a tap occurs in the messageBottomLabel.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the tap occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapMessageBottomLabel(in cell: MessageCollectionViewCell)
-    
-    /// Triggered when a tap occurs in the accessoryView.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the tap occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapAccessoryView(in cell: MessageCollectionViewCell)
-
-    /// Triggered when a tap occurs on the play button from audio cell.
-    ///
-    /// - Parameters:
-    ///   - cell: The audio cell where the touch occurred.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didTapPlayButton(in cell: AudioMessageCell)
-
-    /// Triggered when audio player start playing audio.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the audio sound is playing.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didStartAudio(in cell: AudioMessageCell)
-
-    /// Triggered when audio player pause audio.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the audio sound is paused.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didPauseAudio(in cell: AudioMessageCell)
-
-    /// Triggered when audio player stoped audio.
-    ///
-    /// - Parameters:
-    ///   - cell: The cell where the audio sound is stoped.
-    ///
-    /// You can get a reference to the `MessageType` for the cell by using `UICollectionView`'s
-    /// `indexPath(for: cell)` method. Then using the returned `IndexPath` with the `MessagesDataSource`
-    /// method `messageForItem(at:indexPath:messagesCollectionView)`.
-    func didStopAudio(in cell: AudioMessageCell)
-
-}
-
-public extension MessageCellDelegate {
-
-    func didTapBackground(in cell: MessageCollectionViewCell) {}
-
-    func didTapMessage(in cell: MessageCollectionViewCell) {}
-
-    func didTapAvatar(in cell: MessageCollectionViewCell) {}
-
-    func didTapCellTopLabel(in cell: MessageCollectionViewCell) {}
-    
-    func didTapCellBottomLabel(in cell: MessageCollectionViewCell) {}
-
-    func didTapMessageTopLabel(in cell: MessageCollectionViewCell) {}
-
-    func didTapPlayButton(in cell: AudioMessageCell) {}
-
-    func didStartAudio(in cell: AudioMessageCell) {}
-
-    func didPauseAudio(in cell: AudioMessageCell) {}
-
-    func didStopAudio(in cell: AudioMessageCell) {}
-
-    func didTapMessageBottomLabel(in cell: MessageCollectionViewCell) {}
-    
-    func didTapAccessoryView(in cell: MessageCollectionViewCell) {}
-
-}

+ 0 - 43
deltachat-ios/MessageKit/Protocols/MessageType.swift

@@ -1,43 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// A standard protocol representing a message.
-/// Use this protocol to create your own message object to be used by MessageKit.
-public protocol MessageType {
-
-    /// The sender of the message.
-    var sender: SenderType { get }
-
-    /// The unique identifier for the message.
-    var messageId: String { get }
-
-    /// The date the message was sent.
-    var sentDate: Date { get }
-
-    /// The kind of message and its underlying kind.
-    var kind: MessageKind { get }
-
-}

+ 0 - 159
deltachat-ios/MessageKit/Protocols/MessagesDataSource.swift

@@ -1,159 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// An object that adopts the `MessagesDataSource` protocol is responsible for providing
-/// the data required by a `MessagesCollectionView`.
-public protocol MessagesDataSource: AnyObject {
-
-    /// The `SenderType` of new messages in the `MessagesCollectionView`.
-    func currentSender() -> SenderType
-
-    /// A helper method to determine if a given message is from the current `SenderType`.
-    ///
-    /// - Parameters:
-    ///   - message: The message to check if it was sent by the current `SenderType`.
-    ///
-    /// - Note:
-    ///   The default implementation of this method checks for equality between
-    ///   the message's `SenderType` and the current `SenderType`.
-    func isFromCurrentSender(message: MessageType) -> Bool
-
-    /// The message to be used for a `MessageCollectionViewCell` at the given `IndexPath`.
-    ///
-    /// - Parameters:
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which the message will be displayed.
-    func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType
-
-    /// The number of sections to be displayed in the `MessagesCollectionView`.
-    ///
-    /// - Parameters:
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which the messages will be displayed.
-    func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int
-
-    /// The number of cells to be displayed in the `MessagesCollectionView`.
-    ///
-    /// - Parameters:
-    ///   - section: The number of the section in which the cells will be displayed.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which the messages will be displayed.
-    /// - Note:
-    ///   The default implementation of this method returns 1. Putting each message in its own section.
-    func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int
-
-    /// The attributed text to be used for cell's top label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// The default value returned by this method is `nil`.
-    func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
-
-    /// The attributed text to be used for cell's bottom label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// The default value returned by this method is `nil`.
-    func cellBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
-
-    /// The attributed text to be used for message bubble's top label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// The default value returned by this method is `nil`.
-    func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
-
-    /// The attributed text to be used for cell's bottom label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// The default value returned by this method is `nil`.
-    func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
-    
-    /// Custom collectionView cell for message with `custom` message type.
-    ///
-    /// - Parameters:
-    ///   - message: The `custom` message type
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   This method will call fatalError() on default. You must override this method if you are using MessageKind.custom messages.
-    func customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
-
-    /// Typing indicator cell used when the indicator is set to be shown
-    ///
-    /// - Parameters:
-    ///   - indexPath: The index path to dequeue the cell at
-    ///   - messagesCollectionView: The `MessagesCollectionView` the cell is to be rendered in
-    /// - Returns: A `UICollectionViewCell` that indicates a user is typing
-    func typingIndicator(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell
-}
-
-public extension MessagesDataSource {
-
-    func isFromCurrentSender(message: MessageType) -> Bool {
-        return message.sender.senderId == currentSender().senderId
-    }
-
-    func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int {
-        return 1
-    }
-
-    func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        return nil
-    }
-
-    func cellBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        return nil
-    }
-
-    func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        return nil
-    }
-
-    func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
-        return nil
-    }
-
-    func customCell(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell {
-        fatalError(MessageKitError.customDataUnresolvedCell)
-    }
-
-    func typingIndicator(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UICollectionViewCell {
-        return messagesCollectionView.dequeueReusableCell(TypingIndicatorCell.self, for: indexPath)
-    }
-}

+ 0 - 315
deltachat-ios/MessageKit/Protocols/MessagesDisplayDelegate.swift

@@ -1,315 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import MapKit
-import UIKit
-
-/// A protocol used by the `MessagesViewController` to customize the appearance of a `MessageContentCell`.
-public protocol MessagesDisplayDelegate: AnyObject {
-
-    // MARK: - All Messages
-
-    /// Specifies the `MessageStyle` to be used for a `MessageContainerView`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is `MessageStyle.bubble`.
-    func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle
-
-    /// Specifies the background color of the `MessageContainerView`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value is `UIColor.clear` for emoji messages.
-    ///   For all other `MessageKind` cases, the color depends on the `SenderType`.
-    ///
-    ///   Current sender: Green
-    ///
-    ///   All other senders: Gray
-    func backgroundColor(for message: MessageType, at  indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
-
-    /// The section header to use for a given `IndexPath`.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this header.
-    ///   - indexPath: The `IndexPath` of the header.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this header will be displayed.
-    func messageHeaderView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView
-
-    /// The section footer to use for a given `IndexPath`.
-    ///
-    /// - Parameters:
-    ///   - indexPath: The `IndexPath` of the footer.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this footer will be displayed.
-    func messageFooterView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView
-
-    /// Used to configure the `AvatarView`‘s image in a `MessageContentCell` class.
-    ///
-    /// - Parameters:
-    ///   - avatarView: The `AvatarView` of the cell.
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default image configured by this method is `?`.
-    func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
-
-    /// Used to configure the `AccessoryView` in a `MessageContentCell` class.
-    ///
-    /// - Parameters:
-    ///   - accessoryView: The `AccessoryView` of the cell.
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default image configured by this method is `?`.
-    func configureAccessoryView(_ accessoryView: UIView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
-
-    // MARK: - Text Messages
-
-    /// Specifies the color of the text for a `TextMessageCell`.
-    ///
-    /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageKind` case of `.text` to which the color will apply.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is determined by the messages `SenderType`.
-    ///
-    ///   Current sender: UIColor.white
-    ///
-    ///   All other senders: UIColor.darkText
-    func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
-
-    /// Specifies the `DetectorType`s to check for the `MessageType`'s text against.
-    ///
-    /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageKind` case of `.text` or `.attributedText` to which the detectors will apply.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   This method returns an empty array by default.
-    func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType]
-
-    /// Specifies the attributes for a given `DetectorType`
-    ///
-    /// - Parameters:
-    ///   - detector: The `DetectorType` for the applied attributes.
-    ///   - message: A `MessageType` with a `MessageKind` case of `.text` or `.attributedText` to which the detectors will apply.
-    ///   - indexPath: The `IndexPath` of the cell.
-    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedString.Key: Any]
-
-    // MARK: - Location Messages
-
-    /// Used to configure a `LocationMessageSnapshotOptions` instance to customize the map image on the given location message.
-    ///
-    /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageKind` case of `.location`.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` requesting the information.
-    /// - Returns: The LocationMessageSnapshotOptions instance with the options to customize map style.
-    func snapshotOptionsForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LocationMessageSnapshotOptions
-
-    /// Used to configure the annoation view of the map image on the given location message.
-    ///
-    /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageKind` case of `.location`.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` requesting the information.
-    /// - Returns: The `MKAnnotationView` to use as the annotation view.
-    func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView?
-
-    /// Ask the delegate for a custom animation block to run when whe map screenshot is ready to be displaied in the given location message.
-    /// The animation block is called with the `UIImageView` to be animated.
-    ///
-    /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageKind` case of `.location`.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` requesting the information.
-    /// - Returns: The animation block to use to apply the location image.
-    func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)?
-
-    // MARK: - Media Messages
-
-    /// Used to configure the `UIImageView` of a `MediaMessageCell.
-    ///
-    /// - Parameters:
-    ///   - imageView: The `UIImageView` of the cell.
-    ///   - message: The `MessageType` that will be displayed by this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    func configureMediaMessageImageView(_ imageView: UIImageView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
-
-    // MARK: - Audio Message
-    
-    /// Used to configure the audio cell UI:
-    ///     1. play button selected state;
-    ///     2. progresssView progress;
-    ///     3. durationLabel text;
-    ///
-    /// - Parameters:
-    ///   - cell: The `AudioMessageCell` that needs to be configure.
-    ///   - message: The `MessageType` that configures the cell.
-    ///
-    /// - Note:
-    ///   This protocol method is called by MessageKit every time an audio cell needs to be configure
-    func configureAudioCell(_ cell: AudioMessageCell, message: MessageType)
-
-    /// Specifies the tint color of play button and progress bar for an `AudioMessageCell`.
-    ///
-    /// - Parameters:
-    ///   - message: A `MessageType` with a `MessageKind` case of `.audio` to which the color will apply.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is UIColor.sendButtonBlue
-    func audioTintColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor
-
-    /// Used to format the audio sound duration in a readable string
-    ///
-    /// - Parameters:
-    ///   - duration: The audio sound duration is seconds.
-    ///   - audioCell: The `AudioMessageCell` that ask for formated duration.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value is computed like fallow:
-    ///     1. return the time as 0:ss if duration is up to 59 seconds                         (e.g. 0:03     means 0 minutes and 3 seconds)
-    ///     2. return the time as m:ss if duration is greater than 59 and lower than 3600      (e.g. 12:23    means 12 mintues and 23 seconds)
-    ///     3. return the time as h:mm:ss for anything longer that 3600 seconds                (e.g. 1:19:08  means 1 hour 19 minutes and 8 seconds)
-    func audioProgressTextFormat(_ duration: Float, for audioCell: AudioMessageCell, in messageCollectionView: MessagesCollectionView) -> String
-
-}
-
-public extension MessagesDisplayDelegate {
-
-    // MARK: - All Messages Defaults
-
-    func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle {
-        return .bubble
-    }
-
-    func backgroundColor(for message: MessageType, at  indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
-
-        switch message.kind {
-        case .emoji:
-            return .clear
-        default:
-            guard let dataSource = messagesCollectionView.messagesDataSource else { return .white }
-            return dataSource.isFromCurrentSender(message: message) ? .outgoingGreen : .incomingGray
-        }
-    }
-    
-    func messageHeaderView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView {
-        return messagesCollectionView.dequeueReusableHeaderView(MessageReusableView.self, for: indexPath)
-    }
-
-    func messageFooterView(for indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageReusableView {
-        return messagesCollectionView.dequeueReusableFooterView(MessageReusableView.self, for: indexPath)
-    }
-
-    func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
-        avatarView.initials = "?"
-    }
-
-    func configureAccessoryView(_ accessoryView: UIView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {}
-
-    // MARK: - Text Messages Defaults
-
-    func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        return dataSource.isFromCurrentSender(message: message) ? .white : .darkText
-    }
-
-    func enabledDetectors(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> [DetectorType] {
-        return []
-    }
-
-    func detectorAttributes(for detector: DetectorType, and message: MessageType, at indexPath: IndexPath) -> [NSAttributedString.Key: Any] {
-        return MessageLabel.defaultAttributes
-    }
-
-    // MARK: - Location Messages Defaults
-
-    func snapshotOptionsForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LocationMessageSnapshotOptions {
-        return LocationMessageSnapshotOptions()
-    }
-
-    func annotationViewForLocation(message: MessageType, at indexPath: IndexPath, in messageCollectionView: MessagesCollectionView) -> MKAnnotationView? {
-        return MKPinAnnotationView(annotation: nil, reuseIdentifier: nil)
-    }
-
-    func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)? {
-        return nil
-    }
-
-    // MARK: - Media Message Defaults
-
-    func configureMediaMessageImageView(_ imageView: UIImageView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
-    }
-
-    // MARK: - Audio Message Defaults
-    
-    func configureAudioCell(_ cell: AudioMessageCell, message: MessageType) {
-
-    }
-
-    func audioTintColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
-        return UIColor.sendButtonBlue
-    }
-
-    func audioProgressTextFormat(_ duration: Float, for audioCell: AudioMessageCell, in messageCollectionView: MessagesCollectionView) -> String {
-        var retunValue = "0:00"
-        // print the time as 0:ss if duration is up to 59 seconds
-        // print the time as m:ss if duration is up to 59:59 seconds
-        // print the time as h:mm:ss for anything longer
-        if duration < 60 {
-            retunValue = String(format: "0:%.02d", Int(duration.rounded(.up)))
-        } else if duration < 3600 {
-            retunValue = String(format: "%.02d:%.02d", Int(duration/60), Int(duration) % 60)
-        } else {
-            let hours = Int(duration/3600)
-            let remainingMinutsInSeconds = Int(duration) - hours*3600
-            retunValue = String(format: "%.02d:%.02d:%.02d", hours, Int(remainingMinutsInSeconds/60), Int(remainingMinutsInSeconds) % 60)
-        }
-        return retunValue
-    }
-
-}

+ 0 - 164
deltachat-ios/MessageKit/Protocols/MessagesLayoutDelegate.swift

@@ -1,164 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-/// A protocol used by the `MessagesCollectionViewFlowLayout` object to determine
-/// the size and layout of a `MessageCollectionViewCell` and its contents.
-public protocol MessagesLayoutDelegate: AnyObject {
-
-    /// Specifies the size to use for a header view.
-    ///
-    /// - Parameters:
-    ///   - section: The section number of the header.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this header will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is a size of `GGSize.zero`.
-    func headerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize
-
-    /// Specifies the size to use for a footer view.
-    ///
-    /// - Parameters:
-    ///   - section: The section number of the footer.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this footer will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is a size of `GGSize.zero`.
-    func footerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize
-
-    /// Specifies the size to use for a typing indicator view.
-    ///
-    /// - Parameters:
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this view will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is the width of the `messagesCollectionView` and
-    ///   a height of 52.
-    func typingIndicatorViewSize(in messagesCollectionView: MessagesCollectionView) -> CGSize
-
-    /// Specifies the top inset to use for a typing indicator view.
-    ///
-    /// - Parameters:
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this view will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is a top inset of 15.
-    func typingIndicatorViewTopInset(in messagesCollectionView: MessagesCollectionView) -> CGFloat
-
-    /// Specifies the height for the `MessageContentCell`'s top label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is zero.
-    func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-    
-    /// Specifies the height for the `MessageContentCell`'s bottom label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is zero.
-    func cellBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-    
-    /// Specifies the height for the message bubble's top label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is zero.
-    func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-
-    /// Specifies the height for the `MessageContentCell`'s bottom label.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` that will be displayed for this cell.
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default value returned by this method is zero.
-    func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
-    
-    /// Custom cell size calculator for messages with MessageType.custom.
-    ///
-    /// - Parameters:
-    ///   - message: The custom message
-    ///   - indexPath: The `IndexPath` of the cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
-    ///
-    /// - Note:
-    ///   The default implementation will throw fatalError(). You must override this method if you are using messages with MessageType.custom.
-    func customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator
-}
-
-public extension MessagesLayoutDelegate {
-
-    func headerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        return .zero
-    }
-
-    func footerViewSize(for section: Int, in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        return .zero
-    }
-
-    func typingIndicatorViewSize(in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        return CGSize(width: messagesCollectionView.bounds.width, height: 48)
-    }
-
-    func typingIndicatorViewTopInset(in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return 15
-    }
-
-    func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return 0
-    }
-    
-    func cellBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return 0
-    }
-
-    func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return 0
-    }
-
-    func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        return 0
-    }
-
-    func customCellSizeCalculator(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CellSizeCalculator {
-        fatalError("Must return a CellSizeCalculator for MessageKind.custom(Any?)")
-    }
-}

+ 0 - 38
deltachat-ios/MessageKit/Protocols/SenderType.swift

@@ -1,38 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-
-/// A standard protocol representing a sender.
-/// Use this protocol to adhere a object as the sender of a MessageType
-public protocol SenderType {
-
-    /// The unique String identifier for the sender.
-    ///
-    /// Note: This value must be unique across all senders.
-    var senderId: String { get }
-
-    /// The display name of a sender.
-    var displayName: String { get }
-}

+ 0 - 55
deltachat-ios/MessageKit/Supporting/MessageInputBar.swift

@@ -1,55 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-import InputBarAccessoryView
-
-@available(*, obsoleted: 3.0.0, renamed: "InputBarAccessoryView")
-public typealias MessageInputBar = InputBarAccessoryView
-
-@available(*, obsoleted: 3.0.0, renamed: "InputBarAccessoryViewDelegate")
-public typealias MessageInputBarDelegate = InputBarAccessoryViewDelegate
-
-//public extension MessageInputBarDelegate {
-//
-//    @available(*, obsoleted: 3.0.0, message: "`MessageInputBar` has been replaced with `InputBarAccessoryView` in 3.0.0. Use `inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String)` instead.")
-//    func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) {
-//    }
-//
-//    @available(*, obsoleted: 3.0.0, message: "`MessageInputBar` has been replaced with `InputBarAccessoryView` in 3.0.0. Use `inputBar(_ inputBar: InputBarAccessoryView, textViewTextDidChangeTo text: String)` instead.")
-//    func messageInputBar(_ inputBar: MessageInputBar, textViewTextDidChangeTo text: String) {
-//    }
-//
-//    @available(*, obsoleted: 3.0.0, message: "`MessageInputBar` has been replaced with `InputBarAccessoryView` in 3.0.0. Use `inputBar(_ inputBar: InputBarAccessoryView, didChangeIntrinsicContentTo size: CGSize)` instead.")
-//    func messageInputBar(_ inputBar: MessageInputBar, didChangeIntrinsicContentTo size: CGSize) {
-//    }
-//}
-//
-//extension InputBarButtonItem {
-//
-//    @available(*, renamed: "inputBarAccessoryView")
-//    public var messageInputBar: MessageInputBar? {
-//        return inputBarAccessoryView
-//    }
-//}

+ 0 - 73
deltachat-ios/MessageKit/Supporting/MessageKit+Availability.swift

@@ -1,73 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-public extension MessagesLayoutDelegate {
-
-    func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
-        fatalError("avatarSize(for:at:in) has been removed in MessageKit 1.0.")
-    }
-
-    func avatarPosition(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> AvatarPosition {
-        fatalError("avatarPosition(for:at:in) has been removed in MessageKit 1.0.")
-    }
-
-    func messageLabelInset(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
-        fatalError("messageLabelInset(for:at:in) has been removed in MessageKit 1.0")
-    }
-
-    func messagePadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
-        fatalError("messagePadding(for:at:in) has been removed in MessageKit 1.0.")
-    }
-
-    func cellTopLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment {
-        fatalError("cellTopLabelAlignment(for:at:in) has been removed in MessageKit 1.0.")
-    }
-
-    func cellBottomLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment {
-        fatalError("cellBottomLabelAlignment(for:at:in) has been removed in MessageKit 1.0.")
-    }
-
-    func widthForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        fatalError("widthForMedia(message:at:with:in) has been removed in MessageKit 1.0.")
-    }
-
-    func heightForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        fatalError("heightForMedia(message:at:with:in) has been removed in MessageKit 1.0.")
-    }
-
-    func widthForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        fatalError("widthForLocation(message:at:with:in) has been removed in MessageKit 1.0.")
-    }
-
-   func heightForLocation(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
-        fatalError("heightForLocation(message:at:with:in) has been removed in MessageKit 1.0.")
-    }
-
-    func shouldCacheLayoutAttributes(for message: MessageType) -> Bool {
-        fatalError("shouldCacheLayoutAttributes(for:) has been removed in MessageKit 1.0.")
-    }
-}

+ 0 - 29
deltachat-ios/MessageKit/Supporting/MessageKit.h

@@ -1,29 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-#import <UIKit/UIKit.h>
-
-FOUNDATION_EXPORT double MessageKitVersionNumber;
-
-FOUNDATION_EXPORT const unsigned char MessageKitVersionString[];

+ 0 - 111
deltachat-ios/MessageKit/Views/AudioPlayerView.swift

@@ -1,111 +0,0 @@
-import Foundation
-import UIKit
-
-open class AudioPlayerView: UIView {
-    //open weak var playerDelegate: AudioPlayerDelegate?
-
-    /// The play button view to display on audio messages.
-    private lazy var playButton: UIButton = {
-        let playButton = UIButton(type: .custom)
-        let playImage = UIImage(named: "play")
-        let pauseImage = UIImage(named: "pause")
-        playButton.setImage(playImage?.withRenderingMode(.alwaysTemplate), for: .normal)
-        playButton.setImage(pauseImage?.withRenderingMode(.alwaysTemplate), for: .selected)
-        playButton.translatesAutoresizingMaskIntoConstraints = false
-        return playButton
-    }()
-
-    /// The time duration lable to display on audio messages.
-    private lazy var durationLabel: UILabel = {
-        let durationLabel = UILabel(frame: CGRect.zero)
-        durationLabel.textAlignment = .right
-        durationLabel.font = UIFont.preferredFont(forTextStyle: .body)
-        durationLabel.adjustsFontForContentSizeCategory = true
-        durationLabel.text = "0:00"
-        durationLabel.translatesAutoresizingMaskIntoConstraints = false
-        return durationLabel
-    }()
-
-    private lazy var progressView: UIProgressView = {
-        let progressView = UIProgressView(progressViewStyle: .default)
-        progressView.progress = 0.0
-        progressView.translatesAutoresizingMaskIntoConstraints = false
-        return progressView
-    }()
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        setupSubviews()
-    }
-
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        self.translatesAutoresizingMaskIntoConstraints = false
-        setupSubviews()
-    }
-
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints() {
-        playButton.constraint(equalTo: CGSize(width: 35, height: 35))
-
-        let playButtonConstraints = [playButton.constraintCenterYTo(self),
-                                     playButton.constraintAlignLeadingTo(self, paddingLeading: 12)]
-        let durationLabelConstraints = [durationLabel.constraintAlignTrailingTo(self, paddingTrailing: 12),
-                                        durationLabel.constraintCenterYTo(self)]
-        self.addConstraints(playButtonConstraints)
-        self.addConstraints(durationLabelConstraints)
-
-        progressView.addConstraints(left: playButton.rightAnchor,
-                                    right: durationLabel.leftAnchor,
-                                    centerY: self.centerYAnchor,
-                                    leftConstant: 8,
-                                    rightConstant: 8)
-    }
-
-    open func setupSubviews() {
-        self.addSubview(playButton)
-        self.addSubview(durationLabel)
-        self.addSubview(progressView)
-        setupConstraints()
-    }
-
-    open func reset() {
-        progressView.progress = 0
-        playButton.isSelected = false
-        durationLabel.text = "0:00"
-    }
-
-    open func didTapPlayButton(_ gesture: UIGestureRecognizer) -> Bool {
-        let touchLocation = gesture.location(in: self)
-        // compute play button touch area, currently play button size is (25, 25) which is hardly touchable
-        // add 10 px around current button frame and test the touch against this new frame
-        let playButtonTouchArea = CGRect(playButton.frame.origin.x - 10.0,
-                                         playButton.frame.origin.y - 10,
-                                         playButton.frame.size.width + 20,
-                                         playButton.frame.size.height + 20)
-        let translateTouchLocation = convert(touchLocation, to: self)
-        if playButtonTouchArea.contains(translateTouchLocation) {
-            return true
-        } else {
-            return false
-        }
-    }
-
-    open func setTintColor(_ color: UIColor) {
-        playButton.imageView?.tintColor = tintColor
-        durationLabel.textColor = tintColor
-        progressView.tintColor = tintColor
-    }
-
-    open func setProgress(_ progress: Float) {
-        progressView.progress = progress
-    }
-
-    open func setDuration(formattedText: String) {
-        durationLabel.text = formattedText
-    }
-
-    open func showPlayLayout(_ play: Bool) {
-        playButton.isSelected = play
-    }
-}

+ 0 - 207
deltachat-ios/MessageKit/Views/AvatarView.swift

@@ -1,207 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class AvatarView: UIImageView {
-
-    // MARK: - Properties
-    
-    open var initials: String? {
-        didSet {
-            setImageFrom(initials: initials)
-        }
-    }
-
-    open var placeholderFont: UIFont = UIFont.preferredFont(forTextStyle: .caption1) {
-        didSet {
-            setImageFrom(initials: initials)
-        }
-    }
-
-    open var placeholderTextColor: UIColor = .white {
-        didSet {
-            setImageFrom(initials: initials)
-        }
-    }
-
-    open var fontMinimumScaleFactor: CGFloat = 0.5
-
-    open var adjustsFontSizeToFitWidth = true
-
-    private var minimumFontSize: CGFloat {
-        return placeholderFont.pointSize * fontMinimumScaleFactor
-    }
-
-    private var radius: CGFloat?
-
-    // MARK: - Overridden Properties
-    open override var frame: CGRect {
-        didSet {
-            setCorner(radius: self.radius)
-        }
-    }
-
-    open override var bounds: CGRect {
-        didSet {
-            setCorner(radius: self.radius)
-        }
-    }
-
-    // MARK: - Initializers
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        prepareView()
-    }
-    
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        prepareView()
-    }
-
-    convenience public init() {
-        self.init(frame: .zero)
-        prepareView()
-    }
-    
-    private func setImageFrom(initials: String?) {
-        guard let initials = initials else { return }
-        image = getImageFrom(initials: initials)
-    }
-
-    private func getImageFrom(initials: String) -> UIImage {
-        let width = frame.width
-        let height = frame.height
-        if width == 0 || height == 0 {return UIImage()}
-        var font = placeholderFont
-
-        _ = UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, UIScreen.main.scale)
-        defer { UIGraphicsEndImageContext() }
-        let context = UIGraphicsGetCurrentContext()!
-
-        //// Text Drawing
-        let textRect = calculateTextRect(outerViewWidth: width, outerViewHeight: height)
-        let initialsText = NSAttributedString(string: initials, attributes: [.font: font])
-        if adjustsFontSizeToFitWidth,
-            initialsText.width(considering: textRect.height) > textRect.width {
-            let newFontSize = calculateFontSize(text: initials, font: font, width: textRect.width, height: textRect.height)
-            font = placeholderFont.withSize(newFontSize)
-        }
-
-        let textStyle = NSMutableParagraphStyle()
-        textStyle.alignment = .center
-        let textFontAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font,
-                                                                 NSAttributedString.Key.foregroundColor: placeholderTextColor,
-                                                                 NSAttributedString.Key.paragraphStyle: textStyle]
-
-        let textTextHeight: CGFloat = initials.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity),
-                                                            options: .usesLineFragmentOrigin,
-                                                            attributes: textFontAttributes,
-                                                            context: nil).height
-        context.saveGState()
-        context.clip(to: textRect)
-        initials.draw(in: CGRect(textRect.minX,
-                                 textRect.minY + (textRect.height - textTextHeight) / 2,
-                                 textRect.width,
-                                 textTextHeight),
-                      withAttributes: textFontAttributes)
-        context.restoreGState()
-        guard let renderedImage = UIGraphicsGetImageFromCurrentImageContext() else { assertionFailure("Could not create image from context"); return UIImage()}
-        return renderedImage
-    }
-
-    /**
-     Recursively find the biggest size to fit the text with a given width and height
-     */
-    private func calculateFontSize(text: String, font: UIFont, width: CGFloat, height: CGFloat) -> CGFloat {
-        let attributedText = NSAttributedString(string: text, attributes: [.font: font])
-        if attributedText.width(considering: height) > width {
-            let newFont = font.withSize(font.pointSize - 1)
-            if newFont.pointSize > minimumFontSize {
-                return font.pointSize
-            } else {
-                return calculateFontSize(text: text, font: newFont, width: width, height: height)
-            }
-        }
-        return font.pointSize
-    }
-
-    /**
-     Calculates the inner circle's width.
-     Note: Assumes corner radius cannot be more than width/2 (this creates circle).
-     */
-    private func calculateTextRect(outerViewWidth: CGFloat, outerViewHeight: CGFloat) -> CGRect {
-        guard outerViewWidth > 0 else {
-            return CGRect.zero
-        }
-        let shortEdge = min(outerViewHeight, outerViewWidth)
-        // Converts degree to radian degree and calculate the
-        // Assumes, it is a perfect circle based on the shorter part of ellipsoid
-        // calculate a rectangle
-        let w = shortEdge * sin(CGFloat(45).degreesToRadians) * 2
-        let h = shortEdge * cos(CGFloat(45).degreesToRadians) * 2
-        let startX = (outerViewWidth - w)/2
-        let startY = (outerViewHeight - h)/2
-        // In case the font exactly fits to the region, put 2 pixel both left and right
-        return CGRect(startX+2, startY, w-4, h)
-    }
-
-    // MARK: - Internal methods
-
-    internal func prepareView() {
-        backgroundColor = .gray
-        contentMode = .scaleAspectFill
-        layer.masksToBounds = true
-        clipsToBounds = true
-        setCorner(radius: nil)
-    }
-
-    // MARK: - Open setters
-    
-    open func set(avatar: Avatar) {
-        if let image = avatar.image {
-            self.image = image
-        } else {
-            initials = avatar.initials
-        }
-    }
-
-    open func setCorner(radius: CGFloat?) {
-        guard let radius = radius else {
-            //if corner radius not set default to Circle
-            let cornerRadius = min(frame.width, frame.height)
-            layer.cornerRadius = cornerRadius/2
-            return
-        }
-        self.radius = radius
-        layer.cornerRadius = radius
-    }
-
-}
-
-fileprivate extension FloatingPoint {
-    var degreesToRadians: Self { return self * .pi / 180 }
-    var radiansToDegrees: Self { return self * 180 / .pi }
-}

+ 0 - 49
deltachat-ios/MessageKit/Views/BubbleCircle.swift

@@ -1,49 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A `UIView` subclass that maintains a mask to keep it fully circular
-open class BubbleCircle: UIView {
-    
-    /// Lays out subviews and applys a circular mask to the layer
-    open override func layoutSubviews() {
-        super.layoutSubviews()
-        layer.mask = roundedMask(corners: .allCorners, radius: bounds.height / 2)
-    }
-    
-    /// Returns a rounded mask of the view
-    ///
-    /// - Parameters:
-    ///   - corners: The corners to round
-    ///   - radius: The radius of curve
-    /// - Returns: A mask
-    open func roundedMask(corners: UIRectCorner, radius: CGFloat) -> CAShapeLayer {
-        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
-        let mask = CAShapeLayer()
-        mask.path = path.cgPath
-        return mask
-    }
-    
-}

+ 0 - 142
deltachat-ios/MessageKit/Views/Cells/AnimatedImageMessageCell.swift

@@ -1,142 +0,0 @@
-import Foundation
-
-import UIKit
-import SDWebImage
-
-// A subclass of `MessageContentCell` used to display mixed media messages.
-open class AnimatedImageMessageCell: MessageContentCell {
-
-    public static let insetTop: CGFloat = 12
-    public static let insetBottom: CGFloat = 12
-    public static let insetHorizontalBig: CGFloat = 18
-    public static let insetHorizontalSmall: CGFloat = 14
-
-
-    // MARK: - Properties
-    /// The `MessageCellDelegate` for the cell.
-    open override weak var delegate: MessageCellDelegate? {
-        didSet {
-            messageLabel.delegate = delegate
-        }
-    }
-
-    /// The label used to display the message's text.
-    open var messageLabel = MessageLabel()
-
-    /// The image view display the media content.
-    open var imageView: SDAnimatedImageView = {
-        let imageView = SDAnimatedImageView()
-        imageView.contentMode = .scaleAspectFill
-        imageView.translatesAutoresizingMaskIntoConstraints = false
-        return imageView
-    }()
-
-    // MARK: - Methods
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-            messageLabel.textInsets = attributes.messageLabelInsets
-            messageLabel.messageLabelFont = attributes.messageLabelFont
-        }
-    }
-
-    func getMessageLabelHeight() -> CGFloat {
-        if let text = messageLabel.attributedText {
-            let height = (text.height(withConstrainedWidth:
-                messageContainerView.frame.width -
-                    AnimatedImageMessageCell.insetHorizontalSmall -
-                    AnimatedImageMessageCell.insetHorizontalBig))
-            return height + AnimatedImageMessageCell.insetBottom + AnimatedImageMessageCell.insetTop
-        }
-        return 0
-    }
-
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints(for messageKind: MessageKind) {
-        messageContainerView.removeConstraints(messageContainerView.constraints)
-        let imageViewHeight = messageContainerView.frame.height - getMessageLabelHeight()
-
-        let imageViewConstraints = [imageView.constraintCenterXTo(messageContainerView),
-                                    imageView.constraintAlignLeadingTo(messageContainerView),
-                                    imageView.constraintAlignTrailingTo(messageContainerView),
-                                    imageView.constraintAlignTopTo(messageContainerView),
-                                    imageView.heightAnchor.constraint(equalToConstant: imageViewHeight)
-                                    ]
-        messageContainerView.addConstraints(imageViewConstraints)
-
-        messageLabel.frame = CGRect(x: 0,
-                                    y: messageContainerView.frame.height - getMessageLabelHeight(),
-                                    width: messageContainerView.frame.width,
-                                    height: getMessageLabelHeight())
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        self.imageView.stopAnimating()
-        self.imageView.image = nil
-        self.messageLabel.attributedText = nil
-        self.messageLabel.text = nil
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(imageView)
-        messageContainerView.addSubview(messageLabel)
-    }
-
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        switch message.kind {
-        case .animatedImageText(let mediaItem):
-            configureImageView(for: mediaItem)
-            configureMessageLabel(for: mediaItem,
-                                  with: displayDelegate,
-                                  message: message,
-                                  at: indexPath,
-                                  in: messagesCollectionView)
-
-        default:
-            fatalError("Unexpected message kind in AnimatedImageMessageCell")
-        }
-
-        setupConstraints(for: message.kind)
-    }
-
-    func configureImageView(for mediaItem: MediaItem) {
-        if let url = mediaItem.url {
-            imageView.sd_setImage(with: url)
-        }
-    }
-
-    func configureMessageLabel(for mediaItem: MediaItem,
-                               with displayDelegate: MessagesDisplayDelegate,
-                               message: MessageType,
-                               at indexPath: IndexPath,
-                               in messagesCollectionView: MessagesCollectionView) {
-        let enabledDetectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView)
-        messageLabel.configure {
-           messageLabel.enabledDetectors = enabledDetectors
-           for detector in enabledDetectors {
-               let attributes = displayDelegate.detectorAttributes(for: detector, and: message, at: indexPath)
-               messageLabel.setAttributes(attributes, detector: detector)
-           }
-            messageLabel.attributedText = mediaItem.text?[MediaItemConstants.messageText]
-        }
-    }
-
-    /// Used to handle the cell's contentView's tap gesture.
-    /// Return false when the contentView does not need to handle the gesture.
-    open override func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        if !imageView.isHidden {
-            let touchPointWithoutImageHeight = CGPoint(x: touchPoint.x, y: touchPoint.y - imageView.frame.height)
-            return messageLabel.handleGesture(touchPointWithoutImageHeight)
-        }
-        return messageLabel.handleGesture(touchPoint)
-    }
-}

+ 0 - 163
deltachat-ios/MessageKit/Views/Cells/AudioMessageCell.swift

@@ -1,163 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-import AVFoundation
-
-/// A subclass of `MessageContentCell` used to display video and audio messages.
-open class AudioMessageCell: MessageContentCell {
-
-    public static let insetTop: CGFloat = 12
-    public static let insetBottom: CGFloat = 12
-    public static let insetHorizontalBig: CGFloat = 18
-    public static let insetHorizontalSmall: CGFloat = 14
-
-    // MARK: - Properties
-    /// The `MessageCellDelegate` for the cell.
-    open override weak var delegate: MessageCellDelegate? {
-        didSet {
-            messageLabel.delegate = delegate
-        }
-    }
-
-    /// The label used to display the message's text.
-    open var messageLabel = MessageLabel()
-
-    public lazy var audioPlayerView: AudioPlayerView = {
-        let audioPlayerView = AudioPlayerView()
-        audioPlayerView.translatesAutoresizingMaskIntoConstraints = false
-        return audioPlayerView
-    }()
-
-    // MARK: - Methods
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints() {
-        messageContainerView.removeConstraints(messageContainerView.constraints)
-        let audioPlayerHeight = messageContainerView.frame.height - getMessageLabelHeight()
-        let audioPlayerConstraints = [ audioPlayerView.constraintHeightTo(audioPlayerHeight),
-                                       audioPlayerView.constraintAlignLeadingTo(messageContainerView),
-                                       audioPlayerView.constraintAlignTrailingTo(messageContainerView),
-                                       audioPlayerView.constraintAlignTopTo(messageContainerView)
-        ]
-        messageContainerView.addConstraints(audioPlayerConstraints)
-
-        messageLabel.frame = CGRect(x: 0,
-                                    y: messageContainerView.frame.height - getMessageLabelHeight(),
-                                    width: messageContainerView.frame.width,
-                                    height: getMessageLabelHeight())
-    }
-
-    func getMessageLabelHeight() -> CGFloat {
-        if let text = messageLabel.attributedText {
-            let height = (text.height(withConstrainedWidth:
-                messageContainerView.frame.width -
-                    AudioMessageCell.insetHorizontalSmall -
-                    AudioMessageCell.insetHorizontalBig))
-            return height + AudioMessageCell.insetBottom + AudioMessageCell.insetTop
-        }
-        return 0
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(audioPlayerView)
-        messageContainerView.addSubview(messageLabel)
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        audioPlayerView.reset()
-        messageLabel.attributedText = nil
-    }
-
-    /// Handle tap gesture on contentView and its subviews.
-    open override func handleTapGesture(_ gesture: UIGestureRecognizer) {
-        if audioPlayerView.didTapPlayButton(gesture) {
-            delegate?.didTapPlayButton(in: self)
-        } else {
-            super.handleTapGesture(gesture)
-        }
-    }
-
-    // MARK: - Configure Cell
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-           super.apply(layoutAttributes)
-           if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-               messageLabel.textInsets = attributes.messageLabelInsets
-               messageLabel.messageLabelFont = attributes.messageLabelFont
-           }
-       }
-
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-
-        guard messagesCollectionView.messagesDataSource != nil else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        let tintColor = displayDelegate.audioTintColor(for: message, at: indexPath, in: messagesCollectionView)
-        audioPlayerView.setTintColor(tintColor)
-
-        if case let .audio(audioItem) = message.kind {
-            audioPlayerView.setDuration(formattedText: displayDelegate.audioProgressTextFormat(audioItem.duration,
-                                                                                               for: self,
-                                                                                               in: messagesCollectionView))
-            configureMessageLabel(for: audioItem,
-                                  with: displayDelegate,
-                                  message: message,
-                                  at: indexPath, in: messagesCollectionView)
-        }
-
-        setupConstraints()
-        displayDelegate.configureAudioCell(self, message: message)
-    }
-
-    func configureMessageLabel(for audioItem: AudioItem,
-                               with displayDelegate: MessagesDisplayDelegate,
-                               message: MessageType,
-                               at indexPath: IndexPath,
-                               in messagesCollectionView: MessagesCollectionView) {
-           let enabledDetectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView)
-           messageLabel.configure {
-              messageLabel.enabledDetectors = enabledDetectors
-              for detector in enabledDetectors {
-                  let attributes = displayDelegate.detectorAttributes(for: detector, and: message, at: indexPath)
-                  messageLabel.setAttributes(attributes, detector: detector)
-              }
-               messageLabel.attributedText = audioItem.text
-           }
-       }
-
-    /// Used to handle the cell's contentView's tap gesture.
-    /// Return false when the contentView does not need to handle the gesture.
-    open override func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        let touchPointWithoutAudioPlayerHeight = CGPoint(x: touchPoint.x,
-                                                         y: touchPoint.y - audioPlayerView.frame.height)
-        return messageLabel.handleGesture(touchPointWithoutAudioPlayerHeight)
-    }
-}

+ 0 - 142
deltachat-ios/MessageKit/Views/Cells/ContactMessageCell.swift

@@ -1,142 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2018 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class ContactMessageCell: MessageContentCell {
-    
-    public enum ConstraintsID: String {
-        case initialsContainerLeftConstraint
-        case disclouserRigtConstraint
-    }
-    
-    /// The view container that holds contact initials
-    public lazy var initialsContainerView: UIView = {
-        let initialsContainer = UIView(frame: CGRect.zero)
-        initialsContainer.backgroundColor = .white
-        return initialsContainer
-    }()
-    
-    /// The label that display the contact initials
-    public lazy var initialsLabel: UILabel = {
-        let initialsLabel = UILabel(frame: CGRect.zero)
-        initialsLabel.textAlignment = .center
-        initialsLabel.textColor = .darkText
-        initialsLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
-        return initialsLabel
-    }()
-    
-    /// The label that display contact name
-    public lazy var nameLabel: UILabel = {
-        let nameLabel = UILabel(frame: CGRect.zero)
-        nameLabel.numberOfLines = 0
-        return nameLabel
-    }()
-    
-    /// The disclouser image view
-    public lazy var disclosureImageView: UIImageView = {
-        let disclouserImage = UIImage(named: "disclouser")?.withRenderingMode(.alwaysTemplate)
-        let disclouser = UIImageView(image: disclouserImage)
-        return disclouser
-    }()
-    
-    // MARK: - Methods
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        guard let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes else {
-            return
-        }
-        nameLabel.font = attributes.messageLabelFont
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(initialsContainerView)
-        messageContainerView.addSubview(nameLabel)
-        messageContainerView.addSubview(disclosureImageView)
-        initialsContainerView.addSubview(initialsLabel)
-        setupConstraints()
-    }
-    
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        nameLabel.text = ""
-        initialsLabel.text = ""
-    }
-    
-    open func setupConstraints() {
-        initialsContainerView.constraint(equalTo: CGSize(width: 26, height: 26))
-        let initialsConstraints = initialsContainerView.addConstraints(left: messageContainerView.leftAnchor, centerY: messageContainerView.centerYAnchor,
-                                                        leftConstant: 5)
-        initialsConstraints.first?.identifier = ConstraintsID.initialsContainerLeftConstraint.rawValue
-        initialsContainerView.layer.cornerRadius = 13
-        initialsLabel.fillSuperview()
-        disclosureImageView.constraint(equalTo: CGSize(width: 20, height: 20))
-        let disclosureConstraints = disclosureImageView.addConstraints(right: messageContainerView.rightAnchor, centerY: messageContainerView.centerYAnchor,
-                                           rightConstant: -10)
-        disclosureConstraints.first?.identifier = ConstraintsID.disclouserRigtConstraint.rawValue
-        nameLabel.addConstraints(messageContainerView.topAnchor,
-                                 left: initialsContainerView.rightAnchor,
-                                 bottom: messageContainerView.bottomAnchor,
-                                 right: disclosureImageView.leftAnchor,
-                                 topConstant: 0,
-                                 leftConstant: 10,
-                                 bottomConstant: 0,
-                                 rightConstant: 5)
-    }
-    
-    // MARK: - Configure Cell
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-        // setup data
-        guard case let .contact(contactItem) = message.kind else { fatalError("Failed decorate audio cell") }
-        nameLabel.text = contactItem.displayName
-        initialsLabel.text = contactItem.initials
-        // setup constraints
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        let initialsContainerLeftConstraint = messageContainerView.constraints.filter { (constraint) -> Bool in
-            return constraint.identifier == ConstraintsID.initialsContainerLeftConstraint.rawValue
-        }.first
-        let disclouserRightConstraint = messageContainerView.constraints.filter { (constraint) -> Bool in
-            return constraint.identifier == ConstraintsID.disclouserRigtConstraint.rawValue
-        }.first
-        if dataSource.isFromCurrentSender(message: message) { // outgoing message
-            initialsContainerLeftConstraint?.constant = 5
-            disclouserRightConstraint?.constant = -10
-        } else { // incoming message
-            initialsContainerLeftConstraint?.constant = 10
-            disclouserRightConstraint?.constant = -5
-        }
-        // setup colors
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-        let textColor = displayDelegate.textColor(for: message, at: indexPath, in: messagesCollectionView)
-        nameLabel.textColor = textColor
-        disclosureImageView.tintColor = textColor
-    }
-    
-}

+ 0 - 141
deltachat-ios/MessageKit/Views/Cells/FileMessageCell.swift

@@ -1,141 +0,0 @@
-import UIKit
-
-// A subclass of `MessageContentCell` used to display mixed media messages.
-open class FileMessageCell: MessageContentCell {
-
-    static let insetVertical: CGFloat = 12
-    static let insetHorizontalBig: CGFloat = 18
-    static let insetHorizontalSmall: CGFloat = 14
-
-    // MARK: - Properties
-    var fileViewLeadingPadding: CGFloat = 0 {
-        didSet {
-            fileViewLeadingAlignment.constant = fileViewLeadingPadding
-        }
-    }
-
-    private lazy var fileViewLeadingAlignment: NSLayoutConstraint = {
-        return fileView.constraintAlignLeadingTo(messageContainerView, paddingLeading: 0)
-    }()
-
-    /// The `MessageCellDelegate` for the cell.
-    open override weak var delegate: MessageCellDelegate? {
-        didSet {
-            messageLabel.delegate = delegate
-        }
-    }
-
-    /// The label used to display the message's text.
-    open var messageLabel = MessageLabel()
-
-    private lazy var fileView: FileView = {
-        let marginInsets = NSDirectionalEdgeInsets(top: FileMessageCell.insetVertical,
-                                                   leading: FileMessageCell.insetHorizontalSmall,
-                                                   bottom: FileMessageCell.insetVertical,
-                                                   trailing: FileMessageCell.insetHorizontalSmall)
-        let fileView = FileView(directionalLayoutMargins: marginInsets)
-        fileView.translatesAutoresizingMaskIntoConstraints = false
-        return fileView
-    }()
-
-    // MARK: - Methods
-
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints(for messageKind: MessageKind) {
-        messageContainerView.removeConstraints(messageContainerView.constraints)
-
-        let fileViewConstraints = [fileView.constraintHeightTo(FileView.defaultHeight),
-                                    fileViewLeadingAlignment,
-                                    fileView.constraintAlignTrailingTo(messageContainerView),
-                                    fileView.constraintAlignTopTo(messageContainerView),
-                                    ]
-        messageContainerView.addConstraints(fileViewConstraints)
-
-        messageLabel.frame = CGRect(x: 0,
-                                    y: FileView.defaultHeight,
-                                    width: messageContainerView.frame.width,
-                                    height: getMessageLabelHeight())
-    }
-
-    private func getMessageLabelHeight() -> CGFloat {
-        if let text = messageLabel.attributedText, !text.string.isEmpty {
-            let height = (text.height(withConstrainedWidth:
-                messageContainerView.frame.width -
-                    FileMessageCell.insetHorizontalSmall -
-                    FileMessageCell.insetHorizontalBig))
-            return height + FileMessageCell.insetVertical
-        }
-        return 0
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(fileView)
-        messageContainerView.addSubview(messageLabel)
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        self.messageLabel.attributedText = nil
-        self.fileView.prepareForReuse()
-    }
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-            messageLabel.textInsets = attributes.messageLabelInsets
-            messageLabel.messageLabelFont = attributes.messageLabelFont
-            fileViewLeadingPadding = attributes.messageLabelInsets.left
-        }
-    }
-
-    // MARK: - Configure Cell
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        switch message.kind {
-        case .fileText(let mediaItem):
-            configureFileView(for: mediaItem)
-            configureMessageLabel(for: mediaItem,
-                                             with: displayDelegate,
-                                             message: message,
-                                             at: indexPath,
-                                             in: messagesCollectionView)
-        default:
-            fatalError("Unexpected message kind in FileMessageCell")
-        }
-        setupConstraints(for: message.kind)
-    }
-
-    private func configureFileView(for mediaItem: MediaItem) {
-        fileView.configureFor(mediaItem: mediaItem)
-    }
-
-    private func configureMessageLabel(for mediaItem: MediaItem,
-                                       with displayDelegate: MessagesDisplayDelegate,
-                                       message: MessageType,
-                                       at indexPath: IndexPath,
-                                       in messagesCollectionView: MessagesCollectionView) {
-        let enabledDetectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView)
-        messageLabel.configure {
-            messageLabel.enabledDetectors = enabledDetectors
-            for detector in enabledDetectors {
-                let attributes = displayDelegate.detectorAttributes(for: detector, and: message, at: indexPath)
-                messageLabel.setAttributes(attributes, detector: detector)
-            }
-            messageLabel.attributedText = mediaItem.text?[MediaItemConstants.messageText]
-        }
-    }
-
-    /// Used to handle the cell's contentView's tap gesture.
-    /// Return false when the contentView does not need to handle the gesture.
-    open override func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        let touchPointWithoutImageHeight = CGPoint(x: touchPoint.x,
-                                                   y: touchPoint.y - fileView.frame.height)
-        return messageLabel.handleGesture(touchPointWithoutImageHeight)
-    }
-}

+ 0 - 53
deltachat-ios/MessageKit/Views/Cells/InfoMessageCell.swift

@@ -1,53 +0,0 @@
-import UIKit
-import DcCore
-
-open class InfoMessageCell: UICollectionViewCell {
-    let label = MessageLabel()
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-        setupSubviews()
-    }
-
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-        setupSubviews()
-    }
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-            label.textInsets = attributes.messageLabelInsets
-            label.messageLabelFont = attributes.messageLabelFont
-            label.backgroundColor = DcColors.systemMessageBackgroundColor
-            let padding = (contentView.frame.width - attributes.messageContainerSize.width) / 2
-            label.frame = CGRect(origin: CGPoint(x: padding, y: .zero), size: attributes.messageContainerSize)
-        }
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        label.attributedText = nil
-        label.text = nil
-    }
-
-    open func setupSubviews() {
-        contentView.addSubview(label)
-        label.layer.cornerRadius = 16
-        label.layer.masksToBounds = true
-        label.textAlignment = .center
-    }
-
-    open func configure(with message: MessageType, at indexPath: IndexPath, and collectionView: MessagesCollectionView) {
-       label.configure {
-            switch message.kind {
-            case let .info(data):
-                label.attributedText = data
-            default:
-                break
-            }
-        }
-    }
-}

+ 0 - 111
deltachat-ios/MessageKit/Views/Cells/LocationMessageCell.swift

@@ -1,111 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-import MapKit
-
-/// A subclass of `MessageContentCell` used to display location messages.
-open class LocationMessageCell: MessageContentCell {
-
-    /// The activity indicator to be displayed while the map image is loading.
-    open var activityIndicator = UIActivityIndicatorView(style: .gray)
-
-    /// The image view holding the map image.
-    open var imageView = UIImageView()
-    
-    private weak var snapShotter: MKMapSnapshotter?
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        imageView.contentMode = .scaleAspectFill
-        messageContainerView.addSubview(imageView)
-        messageContainerView.addSubview(activityIndicator)
-        setupConstraints()
-    }
-
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints() {
-        imageView.fillSuperview()
-        activityIndicator.centerInSuperview()
-    }
-    
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        snapShotter?.cancel()
-    }
-
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-        let options = displayDelegate.snapshotOptionsForLocation(message: message, at: indexPath, in: messagesCollectionView)
-        let annotationView = displayDelegate.annotationViewForLocation(message: message, at: indexPath, in: messagesCollectionView)
-        let animationBlock = displayDelegate.animationBlockForLocation(message: message, at: indexPath, in: messagesCollectionView)
-
-        guard case let .location(locationItem) = message.kind else { fatalError("") }
-
-        activityIndicator.startAnimating()
-
-        let snapshotOptions = MKMapSnapshotter.Options()
-        snapshotOptions.region = MKCoordinateRegion(center: locationItem.location.coordinate, span: options.span)
-        snapshotOptions.showsBuildings = options.showsBuildings
-        snapshotOptions.showsPointsOfInterest = options.showsPointsOfInterest
-
-        let snapShotter = MKMapSnapshotter(options: snapshotOptions)
-        self.snapShotter = snapShotter
-        snapShotter.start { (snapshot, error) in
-            defer {
-                self.activityIndicator.stopAnimating()
-            }
-            guard let snapshot = snapshot, error == nil else {
-                //show an error image?
-                return
-            }
-
-            guard let annotationView = annotationView else {
-                self.imageView.image = snapshot.image
-                return
-            }
-
-            UIGraphicsBeginImageContextWithOptions(snapshotOptions.size, true, 0)
-
-            snapshot.image.draw(at: .zero)
-
-            var point = snapshot.point(for: locationItem.location.coordinate)
-            //Move point to reflect annotation anchor
-            point.x -= annotationView.bounds.size.width / 2
-            point.y -= annotationView.bounds.size.height / 2
-            point.x += annotationView.centerOffset.x
-            point.y += annotationView.centerOffset.y
-
-            annotationView.image?.draw(at: point)
-            let composedImage = UIGraphicsGetImageFromCurrentImageContext()
-
-            UIGraphicsEndImageContext()
-            self.imageView.image = composedImage
-            animationBlock?(self.imageView)
-        }
-    }
-}

+ 0 - 102
deltachat-ios/MessageKit/Views/Cells/MediaMessageCell.swift

@@ -1,102 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A subclass of `MessageContentCell` used to display video and audio messages.
-open class MediaMessageCell: MessageContentCell {
-
-    /// The play button view to display on video messages.
-    open lazy var playButtonView: PlayButtonView = {
-        let playButtonView = PlayButtonView()
-        return playButtonView
-    }()
-
-    /// The image view display the media content.
-    open var imageView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.contentMode = .scaleAspectFill
-        imageView.clipsToBounds = true
-        return imageView
-    }()
-
-    // MARK: - Methods
-
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints() {
-        imageView.fillSuperview()
-        playButtonView.centerInSuperview()
-        playButtonView.constraint(equalTo: CGSize(width: 50, height: 50))
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(imageView)
-        messageContainerView.addSubview(playButtonView)
-        setupConstraints()
-    }
-    
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        self.imageView.image = nil
-    }
-
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        switch message.kind {
-        case .photo(let mediaItem):
-            imageView.image = mediaItem.image ?? mediaItem.placeholderImage
-            playButtonView.isHidden = true
-        case .video(let mediaItem):
-            if let url = mediaItem.url {
-                if let image = mediaItem.image {
-                    imageView.image = image
-                } else {
-                    // no image in cache
-                    imageView.loadVideoThumbnail(from: url, placeholderImage: mediaItem.placeholderImage, completionHandler: { [weak self] thumbnail in
-                        if let image = thumbnail {
-                            self?.cache(thumbnail: image, key: url.absoluteString)
-                        }
-                    })
-                }
-            } else {
-                imageView.image = mediaItem.placeholderImage
-            }
-            playButtonView.isHidden = false
-        default:
-            break
-        }
-
-        displayDelegate.configureMediaMessageImageView(imageView, for: message, at: indexPath, in: messagesCollectionView)
-    }
-
-    private func cache(thumbnail image: UIImage, key: String) {
-        ThumbnailCache.shared.storeImage(image: image, key: key)
-    }
-}

+ 0 - 45
deltachat-ios/MessageKit/Views/Cells/MessageCollectionViewCell.swift

@@ -1,45 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A subclass of `UICollectionViewCell` to be used inside of a `MessagesCollectionView`.
-open class MessageCollectionViewCell: UICollectionViewCell {
-
-    // MARK: - Initializers
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-    }
-
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-    }
-
-    /// Handle tap gesture on contentView and its subviews.
-    open func handleTapGesture(_ gesture: UIGestureRecognizer) {
-        // Should be overridden
-    }
-
-}

+ 0 - 352
deltachat-ios/MessageKit/Views/Cells/MessageContentCell.swift

@@ -1,352 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A subclass of `MessageCollectionViewCell` used to display text, media, and location messages.
-open class MessageContentCell: MessageCollectionViewCell {
-
-    /// The image view displaying the avatar.
-    open var avatarView = AvatarView()
-
-    /// The container used for styling and holding the message's content view.
-    open var messageContainerView: MessageContainerView = {
-        let containerView = MessageContainerView()
-        containerView.clipsToBounds = true
-        containerView.layer.masksToBounds = true
-        return containerView
-    }()
-
-    /// The top label of the cell.
-    open var cellTopLabel: InsetLabel = {
-        let label = InsetLabel()
-        label.numberOfLines = 0
-        label.textAlignment = .center
-        return label
-    }()
-    
-    /// The bottom label of the cell.
-    open var cellBottomLabel: InsetLabel = {
-        let label = InsetLabel()
-        label.numberOfLines = 0
-        label.textAlignment = .center
-        return label
-    }()
-    
-    /// The top label of the messageBubble.
-    open var messageTopLabel: InsetLabel = {
-        let label = InsetLabel()
-        label.numberOfLines = 0
-        return label
-    }()
-
-    /// The bottom label of the messageBubble.
-    open var messageBottomLabel: InsetLabel = {
-        let label = InsetLabel()
-        label.numberOfLines = 0
-        return label
-    }()
-
-    // Should only add customized subviews - don't change accessoryView itself.
-    open var accessoryView: UIView = UIView()
-
-    /// The `MessageCellDelegate` for the cell.
-    open weak var delegate: MessageCellDelegate?
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-        setupSubviews()
-    }
-
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-        setupSubviews()
-    }
-
-    open func setupSubviews() {
-        contentView.addSubview(accessoryView)
-        contentView.addSubview(cellTopLabel)
-        contentView.addSubview(messageTopLabel)
-        contentView.addSubview(messageBottomLabel)
-        contentView.addSubview(cellBottomLabel)
-        contentView.addSubview(messageContainerView)
-        contentView.addSubview(avatarView)
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        cellTopLabel.text = nil
-        cellBottomLabel.text = nil
-        messageTopLabel.text = nil
-        messageBottomLabel.text = nil
-    }
-
-    // MARK: - Configuration
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        guard let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes else { return }
-        // Call this before other laying out other subviews
-        layoutMessageContainerView(with: attributes)
-        layoutMessageBottomLabel(with: attributes)
-        layoutCellBottomLabel(with: attributes)
-        layoutCellTopLabel(with: attributes)
-        layoutMessageTopLabel(with: attributes)
-        layoutAvatarView(with: attributes)
-        layoutAccessoryView(with: attributes)
-    }
-
-    /// Used to configure the cell.
-    ///
-    /// - Parameters:
-    ///   - message: The `MessageType` this cell displays.
-    ///   - indexPath: The `IndexPath` for this cell.
-    ///   - messagesCollectionView: The `MessagesCollectionView` in which this cell is contained.
-    open func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        guard let dataSource = messagesCollectionView.messagesDataSource else {
-            fatalError(MessageKitError.nilMessagesDataSource)
-        }
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        delegate = messagesCollectionView.messageCellDelegate
-
-        let messageColor = displayDelegate.backgroundColor(for: message, at: indexPath, in: messagesCollectionView)
-        let messageStyle = displayDelegate.messageStyle(for: message, at: indexPath, in: messagesCollectionView)
-
-        displayDelegate.configureAvatarView(avatarView, for: message, at: indexPath, in: messagesCollectionView)
-
-        displayDelegate.configureAccessoryView(accessoryView, for: message, at: indexPath, in: messagesCollectionView)
-
-        messageContainerView.backgroundColor = messageColor
-        messageContainerView.style = messageStyle
-
-        let topCellLabelText = dataSource.cellTopLabelAttributedText(for: message, at: indexPath)
-        let bottomCellLabelText = dataSource.cellBottomLabelAttributedText(for: message, at: indexPath)
-        let topMessageLabelText = dataSource.messageTopLabelAttributedText(for: message, at: indexPath)
-        let bottomMessageLabelText = dataSource.messageBottomLabelAttributedText(for: message, at: indexPath)
-
-        cellTopLabel.attributedText = topCellLabelText
-        cellBottomLabel.attributedText = bottomCellLabelText
-        messageTopLabel.attributedText = topMessageLabelText
-        messageBottomLabel.attributedText = bottomMessageLabelText
-    }
-
-    /// Handle tap gesture on contentView and its subviews.
-    open override func handleTapGesture(_ gesture: UIGestureRecognizer) {
-        let touchLocation = gesture.location(in: self)
-
-        switch true {
-        case messageContainerView.frame.contains(touchLocation) && !cellContentView(canHandle: convert(touchLocation, to: messageContainerView)):
-            delegate?.didTapMessage(in: self)
-        case avatarView.frame.contains(touchLocation):
-            delegate?.didTapAvatar(in: self)
-        case cellTopLabel.frame.contains(touchLocation):
-            delegate?.didTapCellTopLabel(in: self)
-        case cellBottomLabel.frame.contains(touchLocation):
-            delegate?.didTapCellBottomLabel(in: self)
-        case messageTopLabel.frame.contains(touchLocation):
-            delegate?.didTapMessageTopLabel(in: self)
-        case messageBottomLabel.frame.contains(touchLocation):
-            delegate?.didTapMessageBottomLabel(in: self)
-        case accessoryView.frame.contains(touchLocation):
-            delegate?.didTapAccessoryView(in: self)
-        default:
-            delegate?.didTapBackground(in: self)
-        }
-    }
-
-    /// Handle long press gesture, return true when gestureRecognizer's touch point in `messageContainerView`'s frame
-    open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
-        let touchPoint = gestureRecognizer.location(in: self)
-        guard gestureRecognizer.isKind(of: UILongPressGestureRecognizer.self) else { return false }
-        return messageContainerView.frame.contains(touchPoint)
-    }
-
-    /// Handle `ContentView`'s tap gesture, return false when `ContentView` doesn't needs to handle gesture
-    open func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        return false
-    }
-
-    // MARK: - Origin Calculations
-
-    /// Positions the cell's `AvatarView`.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutAvatarView(with attributes: MessagesCollectionViewLayoutAttributes) {
-        var origin: CGPoint = .zero
-        let padding = attributes.avatarLeadingTrailingPadding
-
-        switch attributes.avatarPosition.horizontal {
-        case .cellLeading:
-            origin.x = padding
-        case .cellTrailing:
-            origin.x = attributes.frame.width - attributes.avatarSize.width - padding
-        case .natural:
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-
-        switch attributes.avatarPosition.vertical {
-        case .messageLabelTop:
-            origin.y = messageTopLabel.frame.minY
-        case .messageTop: // Needs messageContainerView frame to be set
-            origin.y = messageContainerView.frame.minY
-        case .messageBottom: // Needs messageContainerView frame to be set
-            origin.y = messageContainerView.frame.maxY - attributes.avatarSize.height
-        case .messageCenter: // Needs messageContainerView frame to be set
-            origin.y = messageContainerView.frame.midY - (attributes.avatarSize.height/2)
-        case .cellBottom:
-            origin.y = attributes.frame.height - attributes.avatarSize.height
-        default:
-            break
-        }
-
-        avatarView.frame = CGRect(origin: origin, size: attributes.avatarSize)
-    }
-
-    /// Positions the cell's `MessageContainerView`.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutMessageContainerView(with attributes: MessagesCollectionViewLayoutAttributes) {
-        var origin: CGPoint = .zero
-
-        switch attributes.avatarPosition.vertical {
-        case .messageBottom:
-            origin.y = attributes.size.height -
-                attributes.messageContainerPadding.bottom -
-                attributes.cellBottomLabelSize.height -
-                attributes.messageBottomLabelSize.height -
-                attributes.messageContainerSize.height -
-                attributes.messageContainerPadding.top
-        case .messageCenter:
-            if attributes.avatarSize.height > attributes.messageContainerSize.height {
-                let messageHeight = attributes.messageContainerSize.height + attributes.messageContainerPadding.vertical
-                origin.y = (attributes.size.height / 2) - (messageHeight / 2)
-            } else {
-                fallthrough
-            }
-        default:
-            if attributes.accessoryViewSize.height > attributes.messageContainerSize.height {
-                let messageHeight = attributes.messageContainerSize.height + attributes.messageContainerPadding.vertical
-                origin.y = (attributes.size.height / 2) - (messageHeight / 2)
-            } else {
-                origin.y = attributes.cellTopLabelSize.height + attributes.messageTopLabelSize.height + attributes.messageContainerPadding.top
-            }
-        }
-
-        let avatarPadding = attributes.avatarLeadingTrailingPadding
-        switch attributes.avatarPosition.horizontal {
-        case .cellLeading:
-            origin.x = attributes.avatarSize.width + attributes.messageContainerPadding.left + avatarPadding
-        case .cellTrailing:
-            origin.x = attributes.frame.width -
-                       attributes.avatarSize.width -
-                       attributes.messageContainerSize.width -
-                       attributes.messageContainerPadding.right -
-                       avatarPadding
-        case .natural:
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-
-        messageContainerView.frame = CGRect(origin: origin, size: attributes.messageContainerSize)
-    }
-
-    /// Positions the cell's top label.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutCellTopLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
-        cellTopLabel.frame = CGRect(origin: .zero, size: attributes.cellTopLabelSize)
-    }
-    
-    /// Positions the cell's bottom label.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutCellBottomLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
-        cellBottomLabel.textAlignment = attributes.cellBottomLabelAlignment.textAlignment
-        cellBottomLabel.textInsets = attributes.cellBottomLabelAlignment.textInsets
-        
-        let y = messageBottomLabel.frame.maxY
-        let origin = CGPoint(x: 0, y: y)
-        
-        cellBottomLabel.frame = CGRect(origin: origin, size: attributes.cellBottomLabelSize)
-    }
-    
-    /// Positions the message bubble's top label.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutMessageTopLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
-        messageTopLabel.textAlignment = attributes.messageTopLabelAlignment.textAlignment
-        messageTopLabel.textInsets = attributes.messageTopLabelAlignment.textInsets
-
-        let y = messageContainerView.frame.minY - attributes.messageContainerPadding.top - attributes.messageTopLabelSize.height
-        let origin = CGPoint(x: 0, y: y)
-        
-        messageTopLabel.frame = CGRect(origin: origin, size: attributes.messageTopLabelSize)
-    }
-
-    /// Positions the message bubble's bottom label.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutMessageBottomLabel(with attributes: MessagesCollectionViewLayoutAttributes) {
-        messageBottomLabel.textAlignment = attributes.messageBottomLabelAlignment.textAlignment
-        messageBottomLabel.textInsets = attributes.messageBottomLabelAlignment.textInsets
-
-        let y = messageContainerView.frame.maxY + attributes.messageContainerPadding.bottom
-        let origin = CGPoint(x: 0, y: y)
-
-        messageBottomLabel.frame = CGRect(origin: origin, size: attributes.messageBottomLabelSize)
-    }
-
-    /// Positions the cell's accessory view.
-    /// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
-    open func layoutAccessoryView(with attributes: MessagesCollectionViewLayoutAttributes) {
-        
-        var origin: CGPoint = .zero
-        
-        // Accessory view is set at the side space of the messageContainerView
-        switch attributes.accessoryViewPosition {
-        case .messageLabelTop:
-            origin.y = messageTopLabel.frame.minY
-        case .messageTop:
-            origin.y = messageContainerView.frame.minY
-        case .messageBottom:
-            origin.y = messageContainerView.frame.maxY - attributes.accessoryViewSize.height
-        case .messageCenter:
-            origin.y = messageContainerView.frame.midY - (attributes.accessoryViewSize.height / 2)
-        case .cellBottom:
-            origin.y = attributes.frame.height - attributes.accessoryViewSize.height
-        default:
-            break
-        }
-
-        // Accessory view is always on the opposite side of avatar
-        switch attributes.avatarPosition.horizontal {
-        case .cellLeading:
-            origin.x = messageContainerView.frame.maxX + attributes.accessoryViewPadding.left
-        case .cellTrailing:
-            origin.x = messageContainerView.frame.minX - attributes.accessoryViewPadding.right - attributes.accessoryViewSize.width
-        case .natural:
-            fatalError(MessageKitError.avatarPositionUnresolved)
-        }
-
-        accessoryView.frame = CGRect(origin: origin, size: attributes.accessoryViewSize)
-    }
-}

+ 0 - 193
deltachat-ios/MessageKit/Views/Cells/TextMediaMessageCell.swift

@@ -1,193 +0,0 @@
-import UIKit
-
-// A subclass of `MessageContentCell` used to display mixed media messages.
-open class TextMediaMessageCell: MessageContentCell {
-
-    static let insetTop: CGFloat = 12
-    static let insetBottom: CGFloat = 12
-    static let insetHorizontalBig: CGFloat = 18
-    static let insetHorizontalSmall: CGFloat = 14
-
-
-    // MARK: - Properties
-    /// The `MessageCellDelegate` for the cell.
-    open override weak var delegate: MessageCellDelegate? {
-        didSet {
-            messageLabel.delegate = delegate
-        }
-    }
-
-    /// The label used to display the message's text.
-    open var messageLabel = MessageLabel()
-
-    /// The image view display the media content.
-    open var imageView: UIImageView = {
-        let imageView = UIImageView()
-        imageView.contentMode = .scaleAspectFill
-        imageView.translatesAutoresizingMaskIntoConstraints = false
-        imageView.clipsToBounds = true
-        return imageView
-    }()
-
-    /// The play button view to display on video messages.
-    open lazy var playButtonView: PlayButtonView = {
-        let playButtonView = PlayButtonView()
-        return playButtonView
-    }()
-
-    // MARK: - Methods
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-            messageLabel.textInsets = attributes.messageLabelInsets
-            messageLabel.messageLabelFont = attributes.messageLabelFont
-        }
-    }
-
-    private func getMessageLabelHeight() -> CGFloat {
-        if let text = messageLabel.attributedText {
-            let height = (text.height(withConstrainedWidth:
-                messageContainerView.frame.width -
-                    TextMediaMessageCell.insetHorizontalSmall -
-                    TextMediaMessageCell.insetHorizontalBig))
-            return height + TextMediaMessageCell.insetBottom + TextMediaMessageCell.insetTop
-        }
-        return 0
-    }
-
-    /// Responsible for setting up the constraints of the cell's subviews.
-    open func setupConstraints(for messageKind: MessageKind) {
-        messageContainerView.removeConstraints(messageContainerView.constraints)
-        let imageViewHeight = messageContainerView.frame.height - getMessageLabelHeight()
-
-        let imageViewConstraints = [imageView.constraintCenterXTo(messageContainerView),
-                                    imageView.constraintAlignLeadingTo(messageContainerView),
-                                    imageView.constraintAlignTrailingTo(messageContainerView),
-                                    imageView.constraintAlignTopTo(messageContainerView),
-                                    imageView.heightAnchor.constraint(equalToConstant: imageViewHeight)
-                                    ]
-        messageContainerView.addConstraints(imageViewConstraints)
-
-        messageLabel.frame = CGRect(x: 0,
-                                    y: messageContainerView.frame.height - getMessageLabelHeight(),
-                                    width: messageContainerView.frame.width,
-                                    height: getMessageLabelHeight())
-
-        switch messageKind {
-        case .videoText:
-            playButtonView.constraint(equalTo: CGSize(width: 50, height: 50))
-            let playButtonViewConstraints = [ playButtonView.constraintCenterXTo(imageView),
-                                              playButtonView.constraintCenterYTo(imageView)]
-            messageContainerView.addConstraints(playButtonViewConstraints)
-        default:
-            break
-        }
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        self.imageView.image = nil
-        self.messageLabel.attributedText = nil
-        self.messageLabel.text = nil
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(imageView)
-        messageContainerView.addSubview(playButtonView)
-        messageContainerView.addSubview(messageLabel)
-    }
-
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        switch message.kind {
-        case .photoText(let mediaItem), .fileText(let mediaItem):
-            configureImageView(for: mediaItem)
-            configureMessageLabel(for: mediaItem,
-                                  with: displayDelegate,
-                                  message: message,
-                                  at: indexPath,
-                                  in: messagesCollectionView)
-        case .videoText(let mediaItem):
-            configureMessageLabel(
-                for: mediaItem,
-                with: displayDelegate,
-                message: message,
-                at: indexPath,
-                in: messagesCollectionView
-            )
-            if let url = mediaItem.url {
-                if let image = mediaItem.image {
-                    imageView.image = image
-                } else {
-                    // no image in cache
-                    imageView.loadVideoThumbnail(from: url, placeholderImage: mediaItem.placeholderImage, completionHandler: { [weak self] thumbnail in
-                            if let image = thumbnail {
-                                self?.cache(thumbnail: image, key: url.absoluteString)
-                            }
-                        }
-                    )
-                }
-            } else {
-                imageView.image = mediaItem.placeholderImage
-            }
-        default:
-            fatalError("Unexpected message kind in TextMediaMessageCell")
-        }
-
-        configurePlayButtonView(for: message.kind)
-        setupConstraints(for: message.kind)
-
-        displayDelegate.configureMediaMessageImageView(imageView, for: message, at: indexPath, in: messagesCollectionView)
-    }
-
-    private func cache(thumbnail image: UIImage, key: String) {
-        ThumbnailCache.shared.storeImage(image: image, key: key)
-    }
-
-    private func configurePlayButtonView(for messageKind: MessageKind) {
-        switch messageKind {
-        case .videoText:
-            playButtonView.isHidden = false
-        default:
-            playButtonView.isHidden = true
-        }
-    }
-
-    private func configureImageView(for mediaItem: MediaItem) {
-        imageView.image = mediaItem.image ?? mediaItem.placeholderImage
-    }
-
-    private func configureMessageLabel(for mediaItem: MediaItem,
-                                       with displayDelegate: MessagesDisplayDelegate,
-                                       message: MessageType,
-                                       at indexPath: IndexPath,
-                                       in messagesCollectionView: MessagesCollectionView) {
-        let enabledDetectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView)
-        messageLabel.configure {
-            messageLabel.enabledDetectors = enabledDetectors
-            for detector in enabledDetectors {
-                let attributes = displayDelegate.detectorAttributes(for: detector, and: message, at: indexPath)
-                messageLabel.setAttributes(attributes, detector: detector)
-            }
-            messageLabel.attributedText = mediaItem.text?[MediaItemConstants.messageText]
-        }
-    }
-
-    /// Used to handle the cell's contentView's tap gesture.
-    /// Return false when the contentView does not need to handle the gesture.
-    open override func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        if !imageView.isHidden {
-            let touchPointWithoutImageHeight = CGPoint(x: touchPoint.x, y: touchPoint.y - imageView.frame.height)
-            return messageLabel.handleGesture(touchPointWithoutImageHeight)
-        }
-        return messageLabel.handleGesture(touchPoint)
-    }
-
-}

+ 0 - 101
deltachat-ios/MessageKit/Views/Cells/TextMessageCell.swift

@@ -1,101 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A subclass of `MessageContentCell` used to display text messages.
-open class TextMessageCell: MessageContentCell {
-
-    // MARK: - Properties
-
-    /// The `MessageCellDelegate` for the cell.
-    open override weak var delegate: MessageCellDelegate? {
-        didSet {
-            messageLabel.delegate = delegate
-        }
-    }
-
-    /// The label used to display the message's text.
-    open var messageLabel = MessageLabel()
-
-    // MARK: - Methods
-
-    open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
-        super.apply(layoutAttributes)
-        if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes {
-            messageLabel.textInsets = attributes.messageLabelInsets
-            messageLabel.messageLabelFont = attributes.messageLabelFont
-            messageLabel.frame = messageContainerView.bounds
-        }
-    }
-
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        messageLabel.attributedText = nil
-        messageLabel.text = nil
-    }
-
-    open override func setupSubviews() {
-        super.setupSubviews()
-        messageContainerView.addSubview(messageLabel)
-    }
-
-    open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
-        super.configure(with: message, at: indexPath, and: messagesCollectionView)
-
-        guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
-            fatalError(MessageKitError.nilMessagesDisplayDelegate)
-        }
-
-        let enabledDetectors = displayDelegate.enabledDetectors(for: message, at: indexPath, in: messagesCollectionView)
-
-        messageLabel.configure {
-            messageLabel.enabledDetectors = enabledDetectors
-            for detector in enabledDetectors {
-                let attributes = displayDelegate.detectorAttributes(for: detector, and: message, at: indexPath)
-                messageLabel.setAttributes(attributes, detector: detector)
-            }
-            switch message.kind {
-            case .text(let text), .emoji(let text):
-                let textColor = displayDelegate.textColor(for: message, at: indexPath, in: messagesCollectionView)
-                messageLabel.text = text
-                messageLabel.textColor = textColor
-                if let font = messageLabel.messageLabelFont {
-                    messageLabel.font = font
-                }
-            case .attributedText(let text):
-                messageLabel.attributedText = text
-            default:
-                break
-            }
-        }
-    }
-    
-    /// Used to handle the cell's contentView's tap gesture.
-    /// Return false when the contentView does not need to handle the gesture.
-    open override func cellContentView(canHandle touchPoint: CGPoint) -> Bool {
-        return messageLabel.handleGesture(touchPoint)
-    }
-
-}

+ 0 - 66
deltachat-ios/MessageKit/Views/Cells/TypingIndicatorCell.swift

@@ -1,66 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A subclass of `MessageCollectionViewCell` used to display the typing indicator.
-open class TypingIndicatorCell: MessageCollectionViewCell {
-    
-    // MARK: - Subviews
-
-    public var insets = UIEdgeInsets(top: 15, left: 0, bottom: 0, right: 0)
-    
-    public let typingBubble = TypingBubble()
-    
-    // MARK: - Initialization
-    
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        setupSubviews()
-    }
-    
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        setupSubviews()
-    }
-    
-    open func setupSubviews() {
-        addSubview(typingBubble)
-    }
-    
-    open override func prepareForReuse() {
-        super.prepareForReuse()
-        if typingBubble.isAnimating {
-            typingBubble.stopAnimating()
-        }
-    }
-    
-    // MARK: - Layout
-    
-    open override func layoutSubviews() {
-        super.layoutSubviews()
-        typingBubble.frame = bounds.inset(by: insets)
-    }
-    
-}

+ 0 - 89
deltachat-ios/MessageKit/Views/FileView.swift

@@ -1,89 +0,0 @@
-import UIKit
-import DcCore
-
-class FileView: UIView {
-
-    static let badgeSize: CGFloat = 48
-    static let defaultHeight: CGFloat = 78
-    static let defaultWidth: CGFloat = 250
-
-    private lazy var titleView: MessageLabel = {
-        let label = MessageLabel()
-        label.translatesAutoresizingMaskIntoConstraints = false
-        label.numberOfLines = 3
-        return label
-    }()
-
-    private lazy var subtitleView: MessageLabel = {
-        let label = MessageLabel()
-        label.numberOfLines = 1
-        label.adjustsFontSizeToFitWidth = false
-        label.lineBreakMode = .byTruncatingTail
-        label.translatesAutoresizingMaskIntoConstraints = false
-        return label
-    }()
-
-    private lazy var fileThumbnail: UIImageView = {
-        let image = UIImageView()
-        image.frame.size = CGSize(width: FileView.badgeSize, height: FileView.badgeSize)
-        image.contentMode = .scaleAspectFill
-        image.translatesAutoresizingMaskIntoConstraints = false
-        image.isAccessibilityElement = false
-        return image
-    }()
-
-    private lazy var verticalStackView: UIStackView = {
-        let stackView = UIStackView(arrangedSubviews: [titleView, subtitleView])
-        stackView.translatesAutoresizingMaskIntoConstraints = false
-        stackView.axis = .vertical
-        stackView.alignment = .leading
-        stackView.isLayoutMarginsRelativeArrangement = true
-        return stackView
-    }()
-
-    init(directionalLayoutMargins: NSDirectionalEdgeInsets) {
-        super.init(frame: .zero)
-        translatesAutoresizingMaskIntoConstraints = false
-        verticalStackView.directionalLayoutMargins = directionalLayoutMargins
-        addSubview(fileThumbnail)
-        addSubview(verticalStackView)
-        addConstraints([
-            fileThumbnail.constraintAlignLeadingTo(self),
-            fileThumbnail.constraintWidthTo(FileView.badgeSize),
-            fileThumbnail.constraintHeightTo(FileView.badgeSize),
-            fileThumbnail.constraintCenterYTo(self),
-        ])
-        addConstraints([
-            verticalStackView.constraintCenterYTo(self),
-            verticalStackView.constraintToTrailingOf(fileThumbnail),
-            verticalStackView.constraintAlignTrailingTo(self)
-        ])
-    }
-
-    func configureFor(mediaItem: MediaItem) {
-        if let url = mediaItem.url {
-            let controller = UIDocumentInteractionController(url: url)
-            fileThumbnail.image = controller.icons.first ?? mediaItem.placeholderImage
-        } else {
-            fileThumbnail.image = mediaItem.placeholderImage
-        }
-
-        if let title = mediaItem.text?[MediaItemConstants.mediaTitle] {
-            titleView.attributedText = title
-        }
-
-        if let subtitle = mediaItem.text?[MediaItemConstants.mediaSubtitle] {
-            subtitleView.attributedText = subtitle
-        }
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    func prepareForReuse() {
-        titleView.attributedText = nil
-        subtitleView.attributedText = nil
-        fileThumbnail.image = nil
-    }
-}

+ 0 - 40
deltachat-ios/MessageKit/Views/HeadersFooters/MessageReusableView.swift

@@ -1,40 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import Foundation
-import UIKit
-
-open class MessageReusableView: UICollectionReusableView {
-
-    // MARK: - Initializers
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-    }
-
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-    }
-
-}

+ 0 - 38
deltachat-ios/MessageKit/Views/InsetLabel.swift

@@ -1,38 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class InsetLabel: UILabel {
-
-    open var textInsets: UIEdgeInsets = .zero {
-        didSet { setNeedsDisplay() }
-    }
-
-    open override func drawText(in rect: CGRect) {
-        let insetRect = rect.inset(by: textInsets)
-        super.drawText(in: insetRect)
-    }
-
-}

+ 0 - 88
deltachat-ios/MessageKit/Views/MessageContainerView.swift

@@ -1,88 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class MessageContainerView: UIImageView {
-
-    // MARK: - Properties
-
-    private let imageMask = UIImageView()
-
-    open var style: MessageStyle = .none {
-        didSet {
-            applyMessageStyle()
-        }
-    }
-
-    open override var frame: CGRect {
-        didSet {
-            sizeMaskToView()
-        }
-    }
-
-    // MARK: - Methods
-
-    private func sizeMaskToView() {
-        switch style {
-        case .none, .custom:
-            break
-        case .bubble, .bubbleTail, .bubbleOutline, .bubbleTailOutline:
-            imageMask.frame = bounds
-        }
-    }
-
-    private func applyMessageStyle() {
-        switch style {
-        case .bubble, .bubbleTail:
-            imageMask.image = style.image
-            sizeMaskToView()
-            mask = imageMask
-            image = nil
-        case .bubbleOutline(let color):
-            let bubbleStyle: MessageStyle = .bubble
-            imageMask.image = bubbleStyle.image
-            sizeMaskToView()
-            mask = imageMask
-            image = style.image?.withRenderingMode(.alwaysTemplate)
-            tintColor = color
-        case .bubbleTailOutline(let color, let tail, let corner):
-            let bubbleStyle: MessageStyle = .bubbleTail(tail, corner)
-            imageMask.image = bubbleStyle.image
-            sizeMaskToView()
-            mask = imageMask
-            image = style.image?.withRenderingMode(.alwaysTemplate)
-            tintColor = color
-        case .none:
-            mask = nil
-            image = nil
-            tintColor = nil
-        case .custom(let configurationClosure):
-            mask = nil
-            image = nil
-            tintColor = nil
-            configurationClosure(self)
-        }
-    }
-}

+ 0 - 545
deltachat-ios/MessageKit/Views/MessageLabel.swift

@@ -1,545 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class MessageLabel: UILabel {
-
-    // MARK: - Private Properties
-
-    private lazy var layoutManager: NSLayoutManager = {
-        let layoutManager = NSLayoutManager()
-        layoutManager.addTextContainer(self.textContainer)
-        return layoutManager
-    }()
-
-    private lazy var textContainer: NSTextContainer = {
-        let textContainer = NSTextContainer()
-        textContainer.lineFragmentPadding = 0
-        textContainer.maximumNumberOfLines = self.numberOfLines
-        textContainer.lineBreakMode = self.lineBreakMode
-        textContainer.size = self.bounds.size
-        return textContainer
-    }()
-
-    private lazy var textStorage: NSTextStorage = {
-        let textStorage = NSTextStorage()
-        textStorage.addLayoutManager(self.layoutManager)
-        return textStorage
-    }()
-
-    internal lazy var rangesForDetectors: [DetectorType: [(NSRange, MessageTextCheckingType)]] = [:]
-    
-    private var isConfiguring: Bool = false
-
-    // MARK: - Public Properties
-
-    open weak var delegate: MessageLabelDelegate?
-
-    open var enabledDetectors: [DetectorType] = [] {
-        didSet {
-            setTextStorage(attributedText, shouldParse: true)
-        }
-    }
-
-    open override var attributedText: NSAttributedString? {
-        didSet {
-            setTextStorage(attributedText, shouldParse: true)
-        }
-    }
-
-    open override var text: String? {
-        didSet {
-            setTextStorage(attributedText, shouldParse: true)
-        }
-    }
-
-    open override var font: UIFont! {
-        didSet {
-            setTextStorage(attributedText, shouldParse: false)
-        }
-    }
-
-    open override var textColor: UIColor! {
-        didSet {
-            setTextStorage(attributedText, shouldParse: false)
-        }
-    }
-
-    open override var lineBreakMode: NSLineBreakMode {
-        didSet {
-            textContainer.lineBreakMode = lineBreakMode
-            if !isConfiguring { setNeedsDisplay() }
-        }
-    }
-
-    open override var numberOfLines: Int {
-        didSet {
-            textContainer.maximumNumberOfLines = numberOfLines
-            if !isConfiguring { setNeedsDisplay() }
-        }
-    }
-
-    open override var textAlignment: NSTextAlignment {
-        didSet {
-            setTextStorage(attributedText, shouldParse: false)
-        }
-    }
-
-    open var textInsets: UIEdgeInsets = .zero {
-        didSet {
-            if !isConfiguring { setNeedsDisplay() }
-        }
-    }
-
-    open override var intrinsicContentSize: CGSize {
-        var size = super.intrinsicContentSize
-        size.width += textInsets.horizontal
-        size.height += textInsets.vertical
-        return size
-    }
-
-    internal var messageLabelFont: UIFont?
-
-    private var attributesNeedUpdate = false
-
-    public static var defaultAttributes: [NSAttributedString.Key: Any] = {
-        return [
-            NSAttributedString.Key.foregroundColor: UIColor.darkText,
-            NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue,
-            NSAttributedString.Key.underlineColor: UIColor.darkText
-        ]
-    }()
-
-    open internal(set) var addressAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var dateAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var phoneNumberAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var urlAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var transitInformationAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var hashtagAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var mentionAttributes: [NSAttributedString.Key: Any] = defaultAttributes
-
-    open internal(set) var customAttributes: [NSRegularExpression: [NSAttributedString.Key: Any]] = [:]
-
-    public func setAttributes(_ attributes: [NSAttributedString.Key: Any], detector: DetectorType) {
-        switch detector {
-        case .phoneNumber:
-            phoneNumberAttributes = attributes
-        case .address:
-            addressAttributes = attributes
-        case .date:
-            dateAttributes = attributes
-        case .url:
-            urlAttributes = attributes
-        case .transitInformation:
-            transitInformationAttributes = attributes
-        case .mention:
-            mentionAttributes = attributes
-        case .hashtag:
-            hashtagAttributes = attributes
-        case .custom(let regex):
-            customAttributes[regex] = attributes
-        }
-        if isConfiguring {
-            attributesNeedUpdate = true
-        } else {
-            updateAttributes(for: [detector])
-        }
-    }
-
-    // MARK: - Initializers
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        setupView()
-    }
-
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        setupView()
-    }
-
-    // MARK: - Open Methods
-
-    open override func drawText(in rect: CGRect) {
-
-        let insetRect = rect.inset(by: textInsets)
-        textContainer.size = CGSize(width: insetRect.width, height: rect.height)
-
-        let origin = insetRect.origin
-        let range = layoutManager.glyphRange(for: textContainer)
-
-        layoutManager.drawBackground(forGlyphRange: range, at: origin)
-        layoutManager.drawGlyphs(forGlyphRange: range, at: origin)
-    }
-
-    // MARK: - Public Methods
-
-    public func configure(block: () -> Void) {
-        isConfiguring = true
-        block()
-        if attributesNeedUpdate {
-            updateAttributes(for: enabledDetectors)
-        }
-        attributesNeedUpdate = false
-        isConfiguring = false
-        setNeedsDisplay()
-    }
-
-    // MARK: - Private Methods
-
-    private func setTextStorage(_ newText: NSAttributedString?, shouldParse: Bool) {
-
-        guard let newText = newText, newText.length > 0 else {
-            textStorage.setAttributedString(NSAttributedString())
-            setNeedsDisplay()
-            return
-        }
-
-        let style = paragraphStyle(for: newText)
-        let range = NSRange(location: 0, length: newText.length)
-
-        let mutableText = NSMutableAttributedString(attributedString: newText)
-        mutableText.addAttribute(.paragraphStyle, value: style, range: range)
-
-        if shouldParse {
-            rangesForDetectors.removeAll()
-            let results = parse(text: mutableText)
-            setRangesForDetectors(in: results)
-        }
-
-        for (detector, rangeTuples) in rangesForDetectors {
-            if enabledDetectors.contains(detector) {
-                let attributes = detectorAttributes(for: detector)
-                rangeTuples.forEach { (range, _) in
-                    mutableText.addAttributes(attributes, range: range)
-                }
-            }
-        }
-
-        let modifiedText = NSAttributedString(attributedString: mutableText)
-        textStorage.setAttributedString(modifiedText)
-
-        if !isConfiguring { setNeedsDisplay() }
-
-    }
-
-    private func paragraphStyle(for text: NSAttributedString) -> NSParagraphStyle {
-        guard text.length > 0 else { return NSParagraphStyle() }
-
-        var range = NSRange(location: 0, length: text.length)
-        let existingStyle = text.attribute(.paragraphStyle, at: 0, effectiveRange: &range) as? NSMutableParagraphStyle
-        let style = existingStyle ?? NSMutableParagraphStyle()
-
-        style.lineBreakMode = lineBreakMode
-        style.alignment = textAlignment
-
-        return style
-    }
-
-    private func updateAttributes(for detectors: [DetectorType]) {
-
-        guard let attributedText = attributedText, attributedText.length > 0 else { return }
-        let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
-
-        for detector in detectors {
-            guard let rangeTuples = rangesForDetectors[detector] else { continue }
-
-            for (range, _)  in rangeTuples {
-                let attributes = detectorAttributes(for: detector)
-                mutableAttributedString.addAttributes(attributes, range: range)
-            }
-
-            let updatedString = NSAttributedString(attributedString: mutableAttributedString)
-            textStorage.setAttributedString(updatedString)
-        }
-    }
-
-    private func detectorAttributes(for detectorType: DetectorType) -> [NSAttributedString.Key: Any] {
-
-        switch detectorType {
-        case .address:
-            return addressAttributes
-        case .date:
-            return dateAttributes
-        case .phoneNumber:
-            return phoneNumberAttributes
-        case .url:
-            return urlAttributes
-        case .transitInformation:
-            return transitInformationAttributes
-        case .mention:
-            return mentionAttributes
-        case .hashtag:
-            return hashtagAttributes
-        case .custom(let regex):
-            return customAttributes[regex] ?? MessageLabel.defaultAttributes
-        }
-
-    }
-
-    private func detectorAttributes(for checkingResultType: NSTextCheckingResult.CheckingType) -> [NSAttributedString.Key: Any] {
-        switch checkingResultType {
-        case .address:
-            return addressAttributes
-        case .date:
-            return dateAttributes
-        case .phoneNumber:
-            return phoneNumberAttributes
-        case .link:
-            return urlAttributes
-        case .transitInformation:
-            return transitInformationAttributes
-        default:
-            fatalError(MessageKitError.unrecognizedCheckingResult)
-        }
-    }
-
-    private func setupView() {
-        numberOfLines = 0
-        lineBreakMode = .byWordWrapping
-    }
-
-    // MARK: - Parsing Text
-
-    private func parse(text: NSAttributedString) -> [NSTextCheckingResult] {
-        guard enabledDetectors.isEmpty == false else { return [] }
-        let range = NSRange(location: 0, length: text.length)
-        var matches = [NSTextCheckingResult]()
-
-        // Get matches of all .custom DetectorType and add it to matches array
-        let regexs = enabledDetectors
-            .filter { $0.isCustom }
-            .map { parseForMatches(with: $0, in: text, for: range) }
-            .joined()
-        matches.append(contentsOf: regexs)
-
-        // Get all Checking Types of detectors, except for .custom because they contain their own regex
-        let detectorCheckingTypes = enabledDetectors
-            .filter { !$0.isCustom }
-            .reduce(0) { $0 | $1.textCheckingType.rawValue }
-        if detectorCheckingTypes > 0, let detector = try? NSDataDetector(types: detectorCheckingTypes) {
-            let detectorMatches = detector.matches(in: text.string, options: [], range: range)
-            matches.append(contentsOf: detectorMatches)
-        }
-
-        guard enabledDetectors.contains(.url) else {
-            return matches
-        }
-
-        // Enumerate NSAttributedString NSLinks and append ranges
-        var results: [NSTextCheckingResult] = matches
-
-        text.enumerateAttribute(NSAttributedString.Key.link, in: range, options: []) { value, range, _ in
-            guard let url = value as? URL else { return }
-            let result = NSTextCheckingResult.linkCheckingResult(range: range, url: url)
-            results.append(result)
-        }
-
-        return results
-    }
-
-    private func parseForMatches(with detector: DetectorType, in text: NSAttributedString, for range: NSRange) -> [NSTextCheckingResult] {
-        switch detector {
-        case .custom(let regex):
-            return regex.matches(in: text.string, options: [], range: range)
-        default:
-            fatalError("You must pass a .custom DetectorType")
-        }
-    }
-
-    private func setRangesForDetectors(in checkingResults: [NSTextCheckingResult]) {
-
-        guard checkingResults.isEmpty == false else { return }
-
-        for result in checkingResults {
-
-            switch result.resultType {
-            case .address:
-                var ranges = rangesForDetectors[.address] ?? []
-                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .addressComponents(result.addressComponents))
-                ranges.append(tuple)
-                rangesForDetectors.updateValue(ranges, forKey: .address)
-            case .date:
-                var ranges = rangesForDetectors[.date] ?? []
-                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .date(result.date))
-                ranges.append(tuple)
-                rangesForDetectors.updateValue(ranges, forKey: .date)
-            case .phoneNumber:
-                var ranges = rangesForDetectors[.phoneNumber] ?? []
-                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .phoneNumber(result.phoneNumber))
-                ranges.append(tuple)
-                rangesForDetectors.updateValue(ranges, forKey: .phoneNumber)
-            case .link:
-                var ranges = rangesForDetectors[.url] ?? []
-                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .link(result.url))
-                ranges.append(tuple)
-                rangesForDetectors.updateValue(ranges, forKey: .url)
-            case .transitInformation:
-                var ranges = rangesForDetectors[.transitInformation] ?? []
-                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .transitInfoComponents(result.components))
-                ranges.append(tuple)
-                rangesForDetectors.updateValue(ranges, forKey: .transitInformation)
-            case .regularExpression:
-                guard let text = text, let regex = result.regularExpression, let range = Range(result.range, in: text) else { return }
-                let detector = DetectorType.custom(regex)
-                var ranges = rangesForDetectors[detector] ?? []
-                let tuple: (NSRange, MessageTextCheckingType) = (result.range, .custom(pattern: regex.pattern, match: String(text[range])))
-                ranges.append(tuple)
-                rangesForDetectors.updateValue(ranges, forKey: detector)
-            default:
-                fatalError("Received an unrecognized NSTextCheckingResult.CheckingType")
-            }
-
-        }
-
-    }
-
-    // MARK: - Gesture Handling
-
-    private func stringIndex(at location: CGPoint) -> Int? {
-        guard textStorage.length > 0 else { return nil }
-
-        var location = location
-
-        location.x -= textInsets.left
-        location.y -= textInsets.top
-
-        let index = layoutManager.glyphIndex(for: location, in: textContainer)
-
-        let lineRect = layoutManager.lineFragmentUsedRect(forGlyphAt: index, effectiveRange: nil)
-
-        var characterIndex: Int?
-
-        if lineRect.contains(location) {
-            characterIndex = layoutManager.characterIndexForGlyph(at: index)
-        }
-
-        return characterIndex
-
-    }
-
-  open func handleGesture(_ touchLocation: CGPoint) -> Bool {
-
-        guard let index = stringIndex(at: touchLocation) else { return false }
-
-        for (detectorType, ranges) in rangesForDetectors {
-            for (range, value) in ranges {
-                if range.contains(index) {
-                    handleGesture(for: detectorType, value: value)
-                    return true
-                }
-            }
-        }
-        return false
-    }
-
-    /// swiftlint:disable cyclomatic_complexity
-    private func handleGesture(for detectorType: DetectorType, value: MessageTextCheckingType) {
-        switch value {
-        case let .addressComponents(addressComponents):
-            var transformedAddressComponents = [String: String]()
-            guard let addressComponents = addressComponents else { return }
-            addressComponents.forEach { (key, value) in
-                transformedAddressComponents[key.rawValue] = value
-            }
-            handleAddress(transformedAddressComponents)
-        case let .phoneNumber(phoneNumber):
-            guard let phoneNumber = phoneNumber else { return }
-            handlePhoneNumber(phoneNumber)
-        case let .date(date):
-            guard let date = date else { return }
-            handleDate(date)
-        case let .link(url):
-            guard let url = url else { return }
-            handleURL(url)
-        case let .transitInfoComponents(transitInformation):
-            var transformedTransitInformation = [String: String]()
-            guard let transitInformation = transitInformation else { return }
-            transitInformation.forEach { (key, value) in
-                transformedTransitInformation[key.rawValue] = value
-            }
-            handleTransitInformation(transformedTransitInformation)
-        case let .custom(pattern, match):
-            guard let match = match else { return }
-            switch detectorType {
-            case .hashtag:
-                handleHashtag(match)
-            case .mention:
-                handleMention(match)
-            default:
-                handleCustom(pattern, match: match)
-            }
-        }
-    }
-    // swiftlint:enable cyclomatic_complexity
-
-    private func handleAddress(_ addressComponents: [String: String]) {
-        delegate?.didSelectAddress(addressComponents)
-    }
-
-    private func handleDate(_ date: Date) {
-        delegate?.didSelectDate(date)
-    }
-
-    private func handleURL(_ url: URL) {
-        delegate?.didSelectURL(url)
-    }
-
-    private func handlePhoneNumber(_ phoneNumber: String) {
-        delegate?.didSelectPhoneNumber(phoneNumber)
-    }
-
-    private func handleTransitInformation(_ components: [String: String]) {
-        delegate?.didSelectTransitInformation(components)
-    }
-
-    private func handleHashtag(_ hashtag: String) {
-        delegate?.didSelectHashtag(hashtag)
-    }
-
-    private func handleMention(_ mention: String) {
-        delegate?.didSelectMention(mention)
-    }
-
-    private func handleCustom(_ pattern: String, match: String) {
-        delegate?.didSelectCustom(pattern, match: match)
-    }
-
-}
-
-internal enum MessageTextCheckingType {
-    case addressComponents([NSTextCheckingKey: String]?)
-    case date(Date?)
-    case phoneNumber(String?)
-    case link(URL?)
-    case transitInfoComponents([NSTextCheckingKey: String]?)
-    case custom(pattern: String, match: String?)
-}

+ 0 - 202
deltachat-ios/MessageKit/Views/MessagesCollectionView.swift

@@ -1,202 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class MessagesCollectionView: UICollectionView {
-
-    // MARK: - Properties
-
-    open weak var messagesDataSource: MessagesDataSource?
-
-    open weak var messagesDisplayDelegate: MessagesDisplayDelegate?
-
-    open weak var messagesLayoutDelegate: MessagesLayoutDelegate?
-
-    open weak var messageCellDelegate: MessageCellDelegate?
-
-    open var isTypingIndicatorHidden: Bool {
-        return messagesCollectionViewFlowLayout.isTypingIndicatorViewHidden
-    }
-
-    private var indexPathForLastItem: IndexPath? {
-        let lastSection = numberOfSections - 1
-        guard lastSection >= 0, numberOfItems(inSection: lastSection) > 0 else { return nil }
-        return IndexPath(item: numberOfItems(inSection: lastSection) - 1, section: lastSection)
-    }
-
-    open var messagesCollectionViewFlowLayout: MessagesCollectionViewFlowLayout {
-        guard let layout = collectionViewLayout as? MessagesCollectionViewFlowLayout else {
-            fatalError(MessageKitError.layoutUsedOnForeignType)
-        }
-        return layout
-    }
-
-    // MARK: - Initializers
-
-    public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
-        super.init(frame: frame, collectionViewLayout: layout)
-        backgroundColor = .white
-        registerReusableViews()
-        setupGestureRecognizers()
-    }
-    
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(frame: .zero, collectionViewLayout: MessagesCollectionViewFlowLayout())
-    }
-
-    public convenience init() {
-        self.init(frame: .zero, collectionViewLayout: MessagesCollectionViewFlowLayout())
-    }
-
-    // MARK: - Methods
-    
-    private func registerReusableViews() {
-        register(TextMessageCell.self)
-        register(MediaMessageCell.self)
-        register(TextMediaMessageCell.self)
-        register(AnimatedImageMessageCell.self)
-        register(FileMessageCell.self)
-        register(LocationMessageCell.self)
-        register(AudioMessageCell.self)
-        register(ContactMessageCell.self)
-        register(TypingIndicatorCell.self)
-        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader)
-        register(MessageReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter)
-    }
-    
-    private func setupGestureRecognizers() {
-        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:)))
-        tapGesture.delaysTouchesBegan = true
-        addGestureRecognizer(tapGesture)
-    }
-    
-    @objc
-    open func handleTapGesture(_ gesture: UIGestureRecognizer) {
-        guard gesture.state == .ended else { return }
-        
-        let touchLocation = gesture.location(in: self)
-        guard let indexPath = indexPathForItem(at: touchLocation) else { return }
-        
-        let cell = cellForItem(at: indexPath) as? MessageCollectionViewCell
-        cell?.handleTapGesture(gesture)
-    }
-
-    public func scrollToBottom(animated: Bool = false) {
-        let collectionViewContentHeight = collectionViewLayout.collectionViewContentSize.height
-
-        performBatchUpdates(nil) { _ in
-            self.scrollRectToVisible(CGRect(0.0, collectionViewContentHeight - 1.0, 1.0, 1.0), animated: animated)
-        }
-    }
-    
-    public func reloadDataAndKeepOffset() {
-        // stop scrolling
-        setContentOffset(contentOffset, animated: false)
-        
-        // calculate the offset and reloadData
-        let beforeContentSize = contentSize
-        reloadData()
-        layoutIfNeeded()
-        let afterContentSize = contentSize
-        
-        // reset the contentOffset after data is updated
-        let newOffset = CGPoint(
-            x: contentOffset.x + (afterContentSize.width - beforeContentSize.width),
-            y: contentOffset.y + (afterContentSize.height - beforeContentSize.height))
-        setContentOffset(newOffset, animated: false)
-    }
-
-    // MARK: - Typing Indicator API
-
-    /// Notifies the layout that the typing indicator will change state
-    ///
-    /// - Parameters:
-    ///   - isHidden: A Boolean value that is to be the new state of the typing indicator
-    internal func setTypingIndicatorViewHidden(_ isHidden: Bool) {
-        messagesCollectionViewFlowLayout.setTypingIndicatorViewHidden(isHidden)
-    }
-    
-    /// A method that by default checks if the section is the last in the
-    /// `messagesCollectionView` and that `isTypingIndicatorViewHidden`
-    /// is FALSE
-    ///
-    /// - Parameter section
-    /// - Returns: A Boolean indicating if the TypingIndicator should be presented at the given section
-    public func isSectionReservedForTypingIndicator(_ section: Int) -> Bool {
-        return messagesCollectionViewFlowLayout.isSectionReservedForTypingIndicator(section)
-    }
-
-    // MARK: View Register/Dequeue
-
-    /// Registers a particular cell using its reuse-identifier
-    public func register<T: UICollectionViewCell>(_ cellClass: T.Type) {
-        register(cellClass, forCellWithReuseIdentifier: String(describing: T.self))
-    }
-
-    /// Registers a reusable view for a specific SectionKind
-    public func register<T: UICollectionReusableView>(_ reusableViewClass: T.Type, forSupplementaryViewOfKind kind: String) {
-        register(reusableViewClass,
-                 forSupplementaryViewOfKind: kind,
-                 withReuseIdentifier: String(describing: T.self))
-    }
-    
-    /// Registers a nib with reusable view for a specific SectionKind
-    public func register<T: UICollectionReusableView>(_ nib: UINib? = UINib(nibName: String(describing: T.self), bundle: nil), headerFooterClassOfNib headerFooterClass: T.Type, forSupplementaryViewOfKind kind: String) {
-        register(nib,
-                 forSupplementaryViewOfKind: kind,
-                 withReuseIdentifier: String(describing: T.self))        
-    }
-
-    /// Generically dequeues a cell of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
-    public func dequeueReusableCell<T: UICollectionViewCell>(_ cellClass: T.Type, for indexPath: IndexPath) -> T {
-        guard let cell = dequeueReusableCell(withReuseIdentifier: String(describing: T.self), for: indexPath) as? T else {
-            fatalError("Unable to dequeue \(String(describing: cellClass)) with reuseId of \(String(describing: T.self))")
-        }
-        return cell
-    }
-
-    /// Generically dequeues a header of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
-    public func dequeueReusableHeaderView<T: UICollectionReusableView>(_ viewClass: T.Type, for indexPath: IndexPath) -> T {
-        let view = dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader,
-                                                    withReuseIdentifier: String(describing: T.self),
-                                                    for: indexPath)
-        guard let viewType = view as? T else {
-            fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(String(describing: T.self))")
-        }
-        return viewType
-    }
-
-    /// Generically dequeues a footer of the correct type allowing you to avoid scattering your code with guard-let-else-fatal
-    public func dequeueReusableFooterView<T: UICollectionReusableView>(_ viewClass: T.Type, for indexPath: IndexPath) -> T {
-        let view = dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter,
-                                                    withReuseIdentifier: String(describing: T.self),
-                                                    for: indexPath)
-        guard let viewType = view as? T else {
-            fatalError("Unable to dequeue \(String(describing: viewClass)) with reuseId of \(String(describing: T.self))")
-        }
-        return viewType
-    }
-
-}

+ 0 - 122
deltachat-ios/MessageKit/Views/PlayButtonView.swift

@@ -1,122 +0,0 @@
-/*
- MIT License
-
- Copyright (c) 2017-2019 MessageKit
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-open class PlayButtonView: UIView {
-
-    // MARK: - Properties
-
-    public let triangleView = UIView()
-
-    private var triangleCenterXConstraint: NSLayoutConstraint?
-    private var cacheFrame: CGRect = .zero
-
-    // MARK: - Initializers
-
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-
-        setupSubviews()
-        setupConstraints()
-        setupView()
-    }
-
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        
-        setupSubviews()
-        setupConstraints()
-        setupView()
-    }
-
-    // MARK: - Methods
-    
-    open override func layoutSubviews() {
-        super.layoutSubviews()
-        
-        guard !cacheFrame.equalTo(frame) else { return }
-        cacheFrame = frame
-        
-        updateTriangleConstraints()
-        applyCornerRadius()
-        applyTriangleMask()
-    }
-
-    private func setupSubviews() {
-        addSubview(triangleView)
-    }
-    
-    private func setupView() {
-        triangleView.clipsToBounds = true
-        triangleView.backgroundColor = .black
-
-        backgroundColor = .playButtonLightGray
-    }
-
-    private func setupConstraints() {
-        triangleView.translatesAutoresizingMaskIntoConstraints = false
-
-        let centerX = triangleView.centerXAnchor.constraint(equalTo: centerXAnchor)
-        let centerY = triangleView.centerYAnchor.constraint(equalTo: centerYAnchor)
-        let width = triangleView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.5)
-        let height = triangleView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5)
-
-        triangleCenterXConstraint = centerX
-
-        NSLayoutConstraint.activate([centerX, centerY, width, height])
-    }
-
-    private func triangleMask(for frame: CGRect) -> CAShapeLayer {
-        let shapeLayer = CAShapeLayer()
-        let trianglePath = UIBezierPath()
-
-        let point1 = CGPoint(x: frame.minX, y: frame.minY)
-        let point2 = CGPoint(x: (frame.maxX/5) * 4, y: frame.maxY/2)
-        let point3 = CGPoint(x: frame.minX, y: frame.maxY)
-
-        trianglePath .move(to: point1)
-        trianglePath .addLine(to: point2)
-        trianglePath .addLine(to: point3)
-        trianglePath .close()
-
-        shapeLayer.path = trianglePath.cgPath
-
-        return shapeLayer
-    }
-
-    private func updateTriangleConstraints() {
-        triangleCenterXConstraint?.constant = frame.width/8
-    }
-
-    private func applyTriangleMask() {
-        let rect = CGRect(origin: .zero, size: triangleView.bounds.size)
-        triangleView.layer.mask = triangleMask(for: rect)
-    }
-
-    private func applyCornerRadius() {
-        layer.cornerRadius = frame.width / 2
-    }
-    
-}

+ 0 - 155
deltachat-ios/MessageKit/Views/TypingBubble.swift

@@ -1,155 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A subclass of `UIView` that mimics the iMessage typing bubble
-open class TypingBubble: UIView {
-    
-    // MARK: - Properties
-    
-    open var isPulseEnabled: Bool = true
-    
-    public private(set) var isAnimating: Bool = false
-    
-    open override var backgroundColor: UIColor? {
-        set {
-            [contentBubble, cornerBubble, tinyBubble].forEach { $0.backgroundColor = newValue }
-        }
-        get {
-            return contentBubble.backgroundColor
-        }
-    }
-    
-    private struct AnimationKeys {
-        static let pulse = "typingBubble.pulse"
-    }
-    
-    // MARK: - Subviews
-    
-    /// The indicator used to display the typing animation.
-    public let typingIndicator = TypingIndicator()
-    
-    public let contentBubble = UIView()
-    
-    public let cornerBubble = BubbleCircle()
-    
-    public let tinyBubble = BubbleCircle()
-    
-    // MARK: - Animation Layers
-    
-    open var contentPulseAnimationLayer: CABasicAnimation {
-        let animation = CABasicAnimation(keyPath: "transform.scale")
-        animation.fromValue = 1
-        animation.toValue = 1.04
-        animation.duration = 1
-        animation.repeatCount = .infinity
-        animation.autoreverses = true
-        return animation
-    }
-    
-    open var circlePulseAnimationLayer: CABasicAnimation {
-        let animation = CABasicAnimation(keyPath: "transform.scale")
-        animation.fromValue = 1
-        animation.toValue = 1.1
-        animation.duration = 0.5
-        animation.repeatCount = .infinity
-        animation.autoreverses = true
-        return animation
-    }
-    
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        setupSubviews()
-    }
-    
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        setupSubviews()
-    }
-    
-    open func setupSubviews() {
-        addSubview(tinyBubble)
-        addSubview(cornerBubble)
-        addSubview(contentBubble)
-        contentBubble.addSubview(typingIndicator)
-        backgroundColor = .incomingGray
-    }
-    
-    // MARK: - Layout
-    
-    open override func layoutSubviews() {
-        super.layoutSubviews()
-        
-        // To maintain the iMessage like bubble the width:height ratio of the frame
-        // must be close to 1.65
-        let ratio = bounds.width / bounds.height
-        let extraRightInset = bounds.width - 1.65/ratio*bounds.width
-        
-        let tinyBubbleRadius: CGFloat = bounds.height / 6
-        tinyBubble.frame = CGRect(x: 0,
-                                  y: bounds.height - tinyBubbleRadius,
-                                  width: tinyBubbleRadius,
-                                  height: tinyBubbleRadius)
-        
-        let cornerBubbleRadius = tinyBubbleRadius * 2
-        let offset: CGFloat = tinyBubbleRadius / 6
-        cornerBubble.frame = CGRect(x: tinyBubbleRadius - offset,
-                                    y: bounds.height - (1.5 * cornerBubbleRadius) + offset,
-                                    width: cornerBubbleRadius,
-                                    height: cornerBubbleRadius)
-        
-        let contentBubbleFrame = CGRect(x: tinyBubbleRadius + offset,
-                              y: 0,
-                              width: bounds.width - (tinyBubbleRadius + offset) - extraRightInset,
-                              height: bounds.height - (tinyBubbleRadius + offset))
-        let contentBubbleFrameCornerRadius = contentBubbleFrame.height / 2
-        
-        contentBubble.frame = contentBubbleFrame
-        contentBubble.layer.cornerRadius = contentBubbleFrameCornerRadius
-            
-        let insets = UIEdgeInsets(top: offset, left: contentBubbleFrameCornerRadius / 1.25, bottom: offset, right: contentBubbleFrameCornerRadius / 1.25)
-        typingIndicator.frame = contentBubble.bounds.inset(by: insets)
-    }
-    
-    // MARK: - Animation API
-    
-    open func startAnimating() {
-        defer { isAnimating = true }
-        guard !isAnimating else { return }
-        typingIndicator.startAnimating()
-        if isPulseEnabled {
-            contentBubble.layer.add(contentPulseAnimationLayer, forKey: AnimationKeys.pulse)
-            [cornerBubble, tinyBubble].forEach { $0.layer.add(circlePulseAnimationLayer, forKey: AnimationKeys.pulse) }
-        }
-    }
-    
-    open func stopAnimating() {
-        defer { isAnimating = false }
-        guard isAnimating else { return }
-        typingIndicator.stopAnimating()
-        [contentBubble, cornerBubble, tinyBubble].forEach { $0.layer.removeAnimation(forKey: AnimationKeys.pulse) }
-    }
-    
-}

+ 0 - 165
deltachat-ios/MessageKit/Views/TypingIndicator.swift

@@ -1,165 +0,0 @@
-/*
- MIT License
- 
- Copyright (c) 2017-2019 MessageKit
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
-
-import UIKit
-
-/// A `UIView` subclass that holds 3 dots which can be animated
-open class TypingIndicator: UIView {
-    
-    // MARK: - Properties
-    
-    /// The offset that each dot will transform by during the bounce animation
-    public var bounceOffset: CGFloat = 2.5
-    
-    /// A convenience accessor for the `backgroundColor` of each dot
-    open var dotColor: UIColor = UIColor.lightGray {
-        didSet {
-            dots.forEach { $0.backgroundColor = dotColor }
-        }
-    }
-    
-    /// A flag that determines if the bounce animation is added in `startAnimating()`
-    public var isBounceEnabled: Bool = false
-    
-    /// A flag that determines if the opacity animation is added in `startAnimating()`
-    public var isFadeEnabled: Bool = true
-    
-    /// A flag indicating the animation state
-    public private(set) var isAnimating: Bool = false
-    
-    /// Keys for each animation layer
-    private struct AnimationKeys {
-        static let offset = "typingIndicator.offset"
-        static let bounce = "typingIndicator.bounce"
-        static let opacity = "typingIndicator.opacity"
-    }
-    
-    /// The `CABasicAnimation` applied when `isBounceEnabled` is TRUE to move the dot to the correct
-    /// initial offset
-    open var initialOffsetAnimationLayer: CABasicAnimation {
-        let animation = CABasicAnimation(keyPath: "transform.translation.y")
-        animation.byValue = -bounceOffset
-        animation.duration = 0.5
-        animation.isRemovedOnCompletion = true
-        return animation
-    }
-    
-    /// The `CABasicAnimation` applied when `isBounceEnabled` is TRUE
-    open var bounceAnimationLayer: CABasicAnimation {
-        let animation = CABasicAnimation(keyPath: "transform.translation.y")
-        animation.toValue = -bounceOffset
-        animation.fromValue = bounceOffset
-        animation.duration = 0.5
-        animation.repeatCount = .infinity
-        animation.autoreverses = true
-        return animation
-    }
-    
-    /// The `CABasicAnimation` applied when `isFadeEnabled` is TRUE
-    open var opacityAnimationLayer: CABasicAnimation {
-        let animation = CABasicAnimation(keyPath: "opacity")
-        animation.fromValue = 1
-        animation.toValue = 0.5
-        animation.duration = 0.5
-        animation.repeatCount = .infinity
-        animation.autoreverses = true
-        return animation
-    }
-    
-    // MARK: - Subviews
-    
-    public let stackView = UIStackView()
-    
-    public let dots: [BubbleCircle] = {
-        return [BubbleCircle(), BubbleCircle(), BubbleCircle()]
-    }()
-    
-    // MARK: - Initialization
-    
-    public override init(frame: CGRect) {
-        super.init(frame: frame)
-        setupView()
-    }
-    
-    public required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        setupView()
-    }
-    
-    /// Sets up the view
-    private func setupView() {
-        dots.forEach {
-            $0.backgroundColor = dotColor
-            $0.heightAnchor.constraint(equalTo: $0.widthAnchor).isActive = true
-            stackView.addArrangedSubview($0)
-        }
-        stackView.axis = .horizontal
-        stackView.alignment = .center
-        stackView.distribution = .fillEqually
-        addSubview(stackView)
-    }
-    
-    // MARK: - Layout
-    
-    open override func layoutSubviews() {
-        super.layoutSubviews()
-        stackView.frame = bounds
-        stackView.spacing = bounds.width > 0 ? 5 : 0
-    }
-    
-    // MARK: - Animation API
-    
-    /// Sets the state of the `TypingIndicator` to animating and applies animation layers
-    open func startAnimating() {
-        defer { isAnimating = true }
-        guard !isAnimating else { return }
-        var delay: TimeInterval = 0
-        for dot in dots {
-            DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
-                guard let `self` = self else { return }
-                if self.isBounceEnabled {
-                    dot.layer.add(self.initialOffsetAnimationLayer, forKey: AnimationKeys.offset)
-                    let bounceLayer = self.bounceAnimationLayer
-                    bounceLayer.timeOffset = delay + 0.33
-                    dot.layer.add(bounceLayer, forKey: AnimationKeys.bounce)
-                }
-                if self.isFadeEnabled {
-                    dot.layer.add(self.opacityAnimationLayer, forKey: AnimationKeys.opacity)
-                }
-            }
-            delay += 0.33
-        }
-    }
-    
-    /// Sets the state of the `TypingIndicator` to not animating and removes animation layers
-    open func stopAnimating() {
-        defer { isAnimating = false }
-        guard isAnimating else { return }
-        dots.forEach {
-            $0.layer.removeAnimation(forKey: AnimationKeys.bounce)
-            $0.layer.removeAnimation(forKey: AnimationKeys.opacity)
-        }
-    }
-    
-}

+ 0 - 19
deltachat-ios/Model/Audio.swift

@@ -1,19 +0,0 @@
-import CoreLocation
-import Foundation
-import UIKit
-
-struct Audio: AudioItem {
-    var size: CGSize = CGSize(width: 250, height: 50)
-
-    var url: URL
-
-    var duration: Float
-
-    var text: NSAttributedString?
-
-    init(url: URL, duration: Float, text: NSAttributedString? = nil) {
-        self.url = url
-        self.duration = duration
-        self.text = text
-    }
-}

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

@@ -1,14 +0,0 @@
-import CoreLocation
-import Foundation
-import UIKit
-
-struct Location: LocationItem {
-    var location: CLLocation
-
-    var size: CGSize
-
-    init(location: CLLocation, size: CGSize) {
-        self.location = location
-        self.size = size
-    }
-}

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

@@ -1,29 +0,0 @@
-import CoreLocation
-import Foundation
-import UIKit
-
-struct Media: MediaItem {
-    var url: URL?
-
-    var image: UIImage?
-
-    var placeholderImage: UIImage = UIImage(color: .gray, size: CGSize(width: 250, height: 100))!
-    var text: [NSAttributedString]?
-
-    var size: CGSize {
-        if let image = image {
-            return image.size
-        } else {
-            return placeholderImage.size
-        }
-    }
-
-    init(url: URL? = nil, image: UIImage? = nil, placeholderImage: UIImage? = nil, text: [NSAttributedString]? = nil) {
-        self.url = url
-        self.image = image
-        self.text = text
-        if let placeholderImage = placeholderImage {
-            self.placeholderImage = placeholderImage
-        }
-    }
-}

+ 0 - 45
deltachat-ios/Model/Message.swift

@@ -1,45 +0,0 @@
-import CoreLocation
-import Foundation
-import UIKit
-
-struct Message: MessageType {
-    var messageId: String
-    var sender: SenderType
-    var sentDate: Date
-    var kind: MessageKind
-
-    init(kind: MessageKind, sender: Sender, messageId: String, date: Date) {
-        self.kind = kind
-        self.sender = sender
-        self.messageId = messageId
-        sentDate = date
-    }
-
-    init(text: String, sender: Sender, messageId: String, date: Date) {
-        self.init(kind: .text(text), sender: sender, messageId: messageId, date: date)
-    }
-
-    init(attributedText: NSAttributedString, sender: Sender, messageId: String, date: Date) {
-        self.init(kind: .attributedText(attributedText), sender: sender, messageId: messageId, date: date)
-    }
-
-    init(image: UIImage, sender: Sender, messageId: String, date: Date) {
-        let media = Media(image: image)
-        self.init(kind: .photo(media), sender: sender, messageId: messageId, date: date)
-    }
-
-    init(thumbnail: UIImage, sender: Sender, messageId: String, date: Date) {
-        let url = URL(fileURLWithPath: "")
-        let media = Media(url: url, image: thumbnail)
-        self.init(kind: .video(media), sender: sender, messageId: messageId, date: date)
-    }
-
-    init(location: CLLocation, sender: Sender, messageId: String, date: Date) {
-        let locationItem = Location(location: location, size: CGSize(width: 100, height: 50))
-        self.init(kind: .location(locationItem), sender: sender, messageId: messageId, date: date)
-    }
-
-    init(emoji: String, sender: Sender, messageId: String, date: Date) {
-        self.init(kind: .emoji(emoji), sender: sender, messageId: messageId, date: date)
-    }
-}

+ 2 - 2
deltachat-ios/View/Cell/FileTableViewCell.swift

@@ -67,7 +67,7 @@ class FileTableViewCell: UITableViewCell {
 
     // MARK: - update
     func update(msg: DcMsg) {
-        switch msg.kind {
+       /* switch msg.kind {
         case .fileText(let mediaItem):
             if let url = mediaItem.url {
                 generateThumbnailFor(url: url, placeholder: mediaItem.placeholderImage)
@@ -79,7 +79,7 @@ class FileTableViewCell: UITableViewCell {
                 return
             }
             generateThumbnailFor(url: url, placeholder: nil)
-        }
+        }*/
         title.text = msg.filename
         subtitle.text = msg.getPrettyFileSize()
     }

+ 2 - 2
deltachat-ios/View/Cell/GalleryCell.swift

@@ -15,8 +15,8 @@ class GalleryCell: UICollectionViewCell {
         return view
     }()
 
-    private lazy var playButtonView: PlayButtonView = {
-        let playButtonView = PlayButtonView()
+    private lazy var playButtonView: NewPlayButtonView = {
+        let playButtonView = NewPlayButtonView()
         playButtonView.isHidden = true
         return playButtonView
     }()