diff --git a/Ring/Ring.xcodeproj/project.pbxproj b/Ring/Ring.xcodeproj/project.pbxproj index b47e129ab4289d7f8596c350648bc43e73409da8..5817af0d276dbba0595f7e38ad66d9dd7d079695 100644 --- a/Ring/Ring.xcodeproj/project.pbxproj +++ b/Ring/Ring.xcodeproj/project.pbxproj @@ -123,7 +123,6 @@ 0E5806F723BE4325007D1F5D /* PlayerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E5806F623BE4325007D1F5D /* PlayerView.xib */; }; 0E5A668322F0B1F100AA6820 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5A668222F0B1F100AA6820 /* ProgressView.swift */; }; 0E68571120238546008B0717 /* ConversationNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E68571020238546008B0717 /* ConversationNavigation.swift */; }; - 0E6949791FA7E71C0029B60A /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6949781FA7E71C0029B60A /* BaseViewController.swift */; }; 0E6D95982407113900996A28 /* LinkToAccountManagerViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E6D95972407113900996A28 /* LinkToAccountManagerViewController.storyboard */; }; 0E6D959A2407115800996A28 /* LinkToAccountManagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6D95992407115800996A28 /* LinkToAccountManagerViewController.swift */; }; 0E6D959C2407116E00996A28 /* LinkToAccountManagerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6D959B2407116E00996A28 /* LinkToAccountManagerViewModel.swift */; }; @@ -144,8 +143,6 @@ 0E96ED79225D06480016C07D /* GeneralSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E96ED78225D06480016C07D /* GeneralSettingsViewModel.swift */; }; 0E983E6E1FC77C3E0082103E /* ConversationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E983E6D1FC77C3E0082103E /* ConversationModel.swift */; }; 0E99F1A022417A0400CF8BD6 /* JamiURI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E99F19F22417A0400CF8BD6 /* JamiURI.swift */; }; - 0E9D84491FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */; }; - 0E9D844B1FA7DBAA00C561EB /* ContactRequestTabBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D844A1FA7DBAA00C561EB /* ContactRequestTabBarItem.swift */; }; 0EABD3852303600B00DE7ACF /* default.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0EABD3842303600B00DE7ACF /* default.wav */; }; 0EB1A5CF1F8EBE03009923E2 /* DeviceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EB1A5CE1F8EBE03009923E2 /* DeviceCell.xib */; }; 0EB1A5D11F8EBE23009923E2 /* DeviceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB1A5D01F8EBE23009923E2 /* DeviceCell.swift */; }; @@ -208,13 +205,11 @@ 1A2D18C51F29180700B2C785 /* ContactModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18BD1F29180700B2C785 /* ContactModel.swift */; }; 1A2D18C71F29180700B2C785 /* DeviceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18BF1F29180700B2C785 /* DeviceModel.swift */; }; 1A2D18D11F29182500B2C785 /* ConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18CC1F29182500B2C785 /* ConversationViewController.swift */; }; - 1A2D18D81F2918EE00B2C785 /* MeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18D71F2918EE00B2C785 /* MeDetailViewController.swift */; }; 1A2D18DD1F29192D00B2C785 /* MessableBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18DC1F29192D00B2C785 /* MessableBubble.swift */; }; 1A2D18E51F29197100B2C785 /* MessageAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18DE1F29197100B2C785 /* MessageAccessoryView.swift */; }; 1A2D18E61F29197100B2C785 /* MessageAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1A2D18DF1F29197100B2C785 /* MessageAccessoryView.xib */; }; 1A2D18EB1F29197100B2C785 /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18E41F29197100B2C785 /* MessageViewModel.swift */; }; 1A2D18ED1F2919D800B2C785 /* MeViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A2D18EC1F2919D800B2C785 /* MeViewController.storyboard */; }; - 1A2D18EF1F291A0100B2C785 /* MeDetailViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A2D18EE1F291A0100B2C785 /* MeDetailViewController.storyboard */; }; 1A2D18F51F292D7200B2C785 /* MessageCellReceived.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18F11F292D7200B2C785 /* MessageCellReceived.swift */; }; 1A2D18F61F292D7200B2C785 /* MessageCellReceived.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1A2D18F21F292D7200B2C785 /* MessageCellReceived.xib */; }; 1A2D18F71F292D7200B2C785 /* MessageCellSent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18F31F292D7200B2C785 /* MessageCellSent.swift */; }; @@ -222,7 +217,6 @@ 1A2D18FC1F292DAD00B2C785 /* ConversationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18FA1F292DAD00B2C785 /* ConversationCell.swift */; }; 1A2D18FD1F292DAD00B2C785 /* SmartListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1A2D18FB1F292DAD00B2C785 /* SmartListCell.xib */; }; 1A2D18FF1F29352D00B2C785 /* MeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D18FE1F29352D00B2C785 /* MeViewModel.swift */; }; - 1A2D19011F29353A00B2C785 /* MeDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D19001F29353A00B2C785 /* MeDetailViewModel.swift */; }; 1A3D28A71F0EB9DB00B524EE /* Bool+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A3D28A61F0EB9DB00B524EE /* Bool+String.swift */; }; 1A3D28A91F0EBF0200B524EE /* UIView+Ring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A3D28A81F0EBF0200B524EE /* UIView+Ring.swift */; }; 1A5DC01E1F355DA70075E8EF /* ContactsAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5DC01D1F355DA70075E8EF /* ContactsAdapterDelegate.swift */; }; @@ -239,7 +233,6 @@ 1A5DC03E1F35678D0075E8EF /* ContactRequestsViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A5DC03A1F35678D0075E8EF /* ContactRequestsViewController.storyboard */; }; 1A5DC03F1F35678D0075E8EF /* ContactRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5DC03B1F35678D0075E8EF /* ContactRequestsViewController.swift */; }; 1A5DC0401F35678D0075E8EF /* ContactRequestsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5DC03C1F35678D0075E8EF /* ContactRequestsViewModel.swift */; }; - 1A5DC0421F3567DF0075E8EF /* ContactRequestsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A5DC0411F3567DF0075E8EF /* ContactRequestsCoordinator.swift */; }; 1AABA7461F0FE9C000739605 /* UIColor+Ring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AABA7451F0FE9C000739605 /* UIColor+Ring.swift */; }; 1ABE07D21F0D8FE800D36361 /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ABE07D01F0D8FE800D36361 /* Images.swift */; }; 1ABE07D31F0D8FE800D36361 /* Storyboards.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ABE07D11F0D8FE800D36361 /* Storyboards.swift */; }; @@ -269,6 +262,8 @@ 268AA5C12472D42700B654A0 /* ConfirmationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268AA5C02472D42700B654A0 /* ConfirmationAlert.swift */; }; 26929FD425659E5F0052A601 /* cacert.pem in Resources */ = {isa = PBXBuildFile; fileRef = 26929FD125659E5F0052A601 /* cacert.pem */; }; 269B849626151AC10015BC72 /* libgit2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 269B849326151AC10015BC72 /* libgit2.a */; }; + 26B37339263C439B00E2EE28 /* CustomSearchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B37337263C439B00E2EE28 /* CustomSearchController.swift */; }; + 26B37342263C4B3700E2EE28 /* CustomSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B37341263C4B3700E2EE28 /* CustomSearchBar.swift */; }; 26B708FE253610B0003974F2 /* OpenURLLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B708FD253610B0003974F2 /* OpenURLLabel.swift */; }; 26CE5AB82523968500DE6F90 /* ConferenceActionsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26CE5AB72523968500DE6F90 /* ConferenceActionsMenu.swift */; }; 26DA813224B641A5006C6E23 /* ProfilesAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26DA813124B641A5006C6E23 /* ProfilesAdapter.mm */; }; @@ -531,7 +526,6 @@ 0E639459224AB32200C0890A /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; 0E63F1F3202907090001F248 /* Ring.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ring.entitlements; sourceTree = "<group>"; }; 0E68571020238546008B0717 /* ConversationNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationNavigation.swift; sourceTree = "<group>"; }; - 0E6949781FA7E71C0029B60A /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = "<group>"; }; 0E6D95972407113900996A28 /* LinkToAccountManagerViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LinkToAccountManagerViewController.storyboard; sourceTree = "<group>"; }; 0E6D95992407115800996A28 /* LinkToAccountManagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkToAccountManagerViewController.swift; sourceTree = "<group>"; }; 0E6D959B2407116E00996A28 /* LinkToAccountManagerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkToAccountManagerViewModel.swift; sourceTree = "<group>"; }; @@ -552,8 +546,6 @@ 0E96ED78225D06480016C07D /* GeneralSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewModel.swift; sourceTree = "<group>"; }; 0E983E6D1FC77C3E0082103E /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = "<group>"; }; 0E99F19F22417A0400CF8BD6 /* JamiURI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JamiURI.swift; sourceTree = "<group>"; }; - 0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTabBarItemViewModel.swift; sourceTree = "<group>"; }; - 0E9D844A1FA7DBAA00C561EB /* ContactRequestTabBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestTabBarItem.swift; sourceTree = "<group>"; }; 0EABD3842303600B00DE7ACF /* default.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = default.wav; sourceTree = "<group>"; }; 0EB12451224AB1030025F8CA /* ContactsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsUI.framework; path = System/Library/Frameworks/ContactsUI.framework; sourceTree = SDKROOT; }; 0EB1A5CE1F8EBE03009923E2 /* DeviceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DeviceCell.xib; sourceTree = "<group>"; }; @@ -617,13 +609,11 @@ 1A2D18BD1F29180700B2C785 /* ContactModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactModel.swift; sourceTree = "<group>"; }; 1A2D18BF1F29180700B2C785 /* DeviceModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceModel.swift; sourceTree = "<group>"; }; 1A2D18CC1F29182500B2C785 /* ConversationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationViewController.swift; sourceTree = "<group>"; }; - 1A2D18D71F2918EE00B2C785 /* MeDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeDetailViewController.swift; sourceTree = "<group>"; }; 1A2D18DC1F29192D00B2C785 /* MessableBubble.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessableBubble.swift; sourceTree = "<group>"; }; 1A2D18DE1F29197100B2C785 /* MessageAccessoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageAccessoryView.swift; sourceTree = "<group>"; }; 1A2D18DF1F29197100B2C785 /* MessageAccessoryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageAccessoryView.xib; sourceTree = "<group>"; }; 1A2D18E41F29197100B2C785 /* MessageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageViewModel.swift; sourceTree = "<group>"; }; 1A2D18EC1F2919D800B2C785 /* MeViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MeViewController.storyboard; sourceTree = "<group>"; }; - 1A2D18EE1F291A0100B2C785 /* MeDetailViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MeDetailViewController.storyboard; sourceTree = "<group>"; }; 1A2D18F11F292D7200B2C785 /* MessageCellReceived.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellReceived.swift; sourceTree = "<group>"; }; 1A2D18F21F292D7200B2C785 /* MessageCellReceived.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCellReceived.xib; sourceTree = "<group>"; }; 1A2D18F31F292D7200B2C785 /* MessageCellSent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellSent.swift; sourceTree = "<group>"; }; @@ -631,7 +621,6 @@ 1A2D18FA1F292DAD00B2C785 /* ConversationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationCell.swift; sourceTree = "<group>"; }; 1A2D18FB1F292DAD00B2C785 /* SmartListCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SmartListCell.xib; sourceTree = "<group>"; }; 1A2D18FE1F29352D00B2C785 /* MeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeViewModel.swift; sourceTree = "<group>"; }; - 1A2D19001F29353A00B2C785 /* MeDetailViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeDetailViewModel.swift; sourceTree = "<group>"; }; 1A3CA32A1F102BB700283748 /* Chameleon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Chameleon.framework; path = Carthage/Build/iOS/Chameleon.framework; sourceTree = "<group>"; }; 1A3D28A61F0EB9DB00B524EE /* Bool+String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bool+String.swift"; sourceTree = "<group>"; }; 1A3D28A81F0EBF0200B524EE /* UIView+Ring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Ring.swift"; sourceTree = "<group>"; }; @@ -649,7 +638,6 @@ 1A5DC03A1F35678D0075E8EF /* ContactRequestsViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ContactRequestsViewController.storyboard; sourceTree = "<group>"; }; 1A5DC03B1F35678D0075E8EF /* ContactRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactRequestsViewController.swift; sourceTree = "<group>"; }; 1A5DC03C1F35678D0075E8EF /* ContactRequestsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactRequestsViewModel.swift; sourceTree = "<group>"; }; - 1A5DC0411F3567DF0075E8EF /* ContactRequestsCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactRequestsCoordinator.swift; sourceTree = "<group>"; }; 1AABA7451F0FE9C000739605 /* UIColor+Ring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Ring.swift"; sourceTree = "<group>"; }; 1ABE07D01F0D8FE800D36361 /* Images.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Images.swift; sourceTree = "<group>"; }; 1ABE07D11F0D8FE800D36361 /* Storyboards.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storyboards.swift; sourceTree = "<group>"; }; @@ -681,6 +669,8 @@ 268AA5C02472D42700B654A0 /* ConfirmationAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationAlert.swift; sourceTree = "<group>"; }; 26929FD125659E5F0052A601 /* cacert.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = cacert.pem; sourceTree = "<group>"; }; 269B849326151AC10015BC72 /* libgit2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgit2.a; path = ../DEPS/arm64/lib/libgit2.a; sourceTree = "<group>"; }; + 26B37337263C439B00E2EE28 /* CustomSearchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSearchController.swift; sourceTree = "<group>"; }; + 26B37341263C4B3700E2EE28 /* CustomSearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSearchBar.swift; sourceTree = "<group>"; }; 26B708FD253610B0003974F2 /* OpenURLLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenURLLabel.swift; sourceTree = "<group>"; }; 26CE5AB72523968500DE6F90 /* ConferenceActionsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConferenceActionsMenu.swift; sourceTree = "<group>"; }; 26DA813024B641A5006C6E23 /* ProfilesAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProfilesAdapter.h; sourceTree = "<group>"; }; @@ -1067,6 +1057,8 @@ 0EC7808E2424FDAE000A04C5 /* CustomActionTextView.swift */, 642AD48324EC64CE00521127 /* CopyableLabel.swift */, 26B708FD253610B0003974F2 /* OpenURLLabel.swift */, + 26B37337263C439B00E2EE28 /* CustomSearchController.swift */, + 26B37341263C4B3700E2EE28 /* CustomSearchBar.swift */, ); path = UI; sourceTree = "<group>"; @@ -1376,16 +1368,6 @@ path = GeneralSettings; sourceTree = "<group>"; }; - 0E9D84471FA7D9EC00C561EB /* TabBar */ = { - isa = PBXGroup; - children = ( - 0E9D84481FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift */, - 0E9D844A1FA7DBAA00C561EB /* ContactRequestTabBarItem.swift */, - 0E6949781FA7E71C0029B60A /* BaseViewController.swift */, - ); - path = TabBar; - sourceTree = "<group>"; - }; 0ECA567F243394660055D31E /* MigrateAccount */ = { isa = PBXGroup; children = ( @@ -1436,7 +1418,6 @@ 0E3BD4222044770000A50DDF /* Contact */, 5CE66F721FBF765D00EE9291 /* InitialLoading */, 0E4909711FEAC822005CAA50 /* Calls */, - 0E9D84471FA7D9EC00C561EB /* TabBar */, 0EDE34C51F868D2D00FFA15C /* Shared */, 1A0C4EBD1F1D48DD00550433 /* Walkthrough */, 1A2D18A71F290FAA00B2C785 /* Conversations */, @@ -1542,7 +1523,6 @@ children = ( 0ED2B6F81F96A048001572F0 /* LinknewDevice */, 1A2D18D91F2918F300B2C785 /* Me */, - 1A2D18AF1F29158700B2C785 /* Detail */, 1A2D18AB1F29149D00B2C785 /* MeCoordinator.swift */, ); name = Me; @@ -1579,16 +1559,6 @@ path = Conversation; sourceTree = "<group>"; }; - 1A2D18AF1F29158700B2C785 /* Detail */ = { - isa = PBXGroup; - children = ( - 1A2D18EE1F291A0100B2C785 /* MeDetailViewController.storyboard */, - 1A2D18D71F2918EE00B2C785 /* MeDetailViewController.swift */, - 1A2D19001F29353A00B2C785 /* MeDetailViewModel.swift */, - ); - path = Detail; - sourceTree = "<group>"; - }; 1A2D18B81F2916BA00B2C785 /* Models */ = { isa = PBXGroup; children = ( @@ -1663,7 +1633,6 @@ 1A5DC0331F3567080075E8EF /* ContactRequests */ = { isa = PBXGroup; children = ( - 1A5DC0411F3567DF0075E8EF /* ContactRequestsCoordinator.swift */, 1A5DC0341F3567360075E8EF /* Cells */, 1A5DC03A1F35678D0075E8EF /* ContactRequestsViewController.storyboard */, 1A5DC03B1F35678D0075E8EF /* ContactRequestsViewController.swift */, @@ -2041,7 +2010,6 @@ 0E3BD4242044776300A50DDF /* ContactViewController.storyboard in Resources */, 1A2D18F61F292D7200B2C785 /* MessageCellReceived.xib in Resources */, 0ED2B6FA1F96A075001572F0 /* LinkNewDeviceViewController.storyboard in Resources */, - 1A2D18EF1F291A0100B2C785 /* MeDetailViewController.storyboard in Resources */, 623660AA20092081002598C1 /* src in Resources */, 263B715C246D96E5007044C4 /* IncognitoSmartListCell.xib in Resources */, 1A2D18B11F2915B600B2C785 /* SmartlistViewController.storyboard in Resources */, @@ -2219,7 +2187,6 @@ 1A2D18A11F27A6D600B2C785 /* LinkDeviceViewController.swift in Sources */, 0E5806F523BE4307007D1F5D /* PlayerViewModel.swift in Sources */, 1A0C4EDC1F1D4B7E00550433 /* WelcomeViewController.swift in Sources */, - 1A2D18D81F2918EE00B2C785 /* MeDetailViewController.swift in Sources */, 02B22E091DF7585F000358C9 /* DaemonService.swift in Sources */, 5CE66F761FBF769B00EE9291 /* InitialLoadingViewController.swift in Sources */, 66ACB430214AE28C00A94162 /* ScanViewController.swift in Sources */, @@ -2242,6 +2209,7 @@ 1A20418B1F1EA58A00C08435 /* ViewModelBased.swift in Sources */, 1A5DC01E1F355DA70075E8EF /* ContactsAdapterDelegate.swift in Sources */, 0E983E6E1FC77C3E0082103E /* ConversationModel.swift in Sources */, + 26B37342263C4B3700E2EE28 /* CustomSearchBar.swift in Sources */, 0E3BD4362044B39F00A50DDF /* ProfileHeaderView.swift in Sources */, 1A20418D1F1EABCC00C08435 /* StateableResponsive.swift in Sources */, 1A0C4EE51F1D67DF00550433 /* WalkthroughCoordinator.swift in Sources */, @@ -2274,7 +2242,6 @@ 0ED2B6FC1F96A158001572F0 /* LinkNewDeviceViewController.swift in Sources */, 1ABE07E21F0D924700D36361 /* Strings.swift in Sources */, 0E6F544D223BFE3E00ECC3CE /* DisposableCell.swift in Sources */, - 0E9D84491FA7DA6A00C561EB /* ChatTabBarItemViewModel.swift in Sources */, 621231FB1F8D6FEE009B86F0 /* MessageCell.swift in Sources */, 2662FC7D246B78E800FA7782 /* IncognitoSmartListViewController.swift in Sources */, 56AC650E1E85694D00EA1AA9 /* DesignableTextField.swift in Sources */, @@ -2308,7 +2275,6 @@ 0EDCC8601F98150500B121D7 /* UIView+Rx.swift in Sources */, 0E36979D20322D75009A68CA /* BlockListViewModel.swift in Sources */, 1A2D18C21F29180700B2C785 /* AccountCredentialsModel.swift in Sources */, - 0E9D844B1FA7DBAA00C561EB /* ContactRequestTabBarItem.swift in Sources */, 1A2D18FF1F29352D00B2C785 /* MeViewModel.swift in Sources */, 62A88D391F6C323500F8AB18 /* PresenceAdapter.mm in Sources */, 1A2D18B71F29164700B2C785 /* SmartlistViewModel.swift in Sources */, @@ -2331,7 +2297,6 @@ 0EB1A5D11F8EBE23009923E2 /* DeviceCell.swift in Sources */, 26074FDB24F7FFC100374570 /* PreviewContollerModel.swift in Sources */, 4430A66F236CBC6900747177 /* ContactPickerViewController.swift in Sources */, - 0E6949791FA7E71C0029B60A /* BaseViewController.swift in Sources */, 0EC7808F2424FDAE000A04C5 /* CustomActionTextView.swift in Sources */, 56C715FF1F0D36C600770048 /* ContactsAdapter.mm in Sources */, 1A5DC0281F3564AA0075E8EF /* MessageModel.swift in Sources */, @@ -2355,6 +2320,7 @@ 627F11F120348FBF006560B5 /* AvatarView.swift in Sources */, 1A20417A1F1E547F00C08435 /* Stateable.swift in Sources */, 1A2D18F51F292D7200B2C785 /* MessageCellReceived.swift in Sources */, + 26B37339263C439B00E2EE28 /* CustomSearchController.swift in Sources */, 56BBC9BC1ED7161200CDAF8B /* Date+Helpers.swift in Sources */, 564C44621E943DE6000F92B1 /* NameService.swift in Sources */, 1A5DC02C1F3565250075E8EF /* MeViewController.swift in Sources */, @@ -2377,13 +2343,11 @@ 0E320D52224ADF930070B515 /* DialpadViewController.swift in Sources */, 0E49096E1FEAC0DE005CAA50 /* CallsService.swift in Sources */, 0273C2FF1E0C438F00CF00BA /* AccountAdapterDelegate.swift in Sources */, - 1A2D19011F29353A00B2C785 /* MeDetailViewModel.swift in Sources */, 1A2D18A41F27EF5200B2C785 /* AppCoordinator.swift in Sources */, 1A2D18C31F29180700B2C785 /* AccountModel.swift in Sources */, 62A88D371F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift in Sources */, 1A2D18EB1F29197100B2C785 /* MessageViewModel.swift in Sources */, 02B22DFF1DF755DB000358C9 /* AccountsService.swift in Sources */, - 1A5DC0421F3567DF0075E8EF /* ContactRequestsCoordinator.swift in Sources */, 62E55B6F1F793ADE00D3FEF4 /* AvatarsColors.swift in Sources */, 645BDD8124B74BCB009129B1 /* LocationSharingService.swift in Sources */, 1A5DC0401F35678D0075E8EF /* ContactRequestsViewModel.swift in Sources */, diff --git a/Ring/Ring/Constants/Generated/Images.swift b/Ring/Ring/Constants/Generated/Images.swift index adc0e747356c78e476ef5c9790f57ca1b30ba0e9..bce5d020b72df8ddf43d028ab2cc361d2308e7c3 100644 --- a/Ring/Ring/Constants/Generated/Images.swift +++ b/Ring/Ring/Constants/Generated/Images.swift @@ -66,6 +66,7 @@ internal enum Asset { internal static let phoneBook = ImageAsset(name: "phone_book") internal static let qrCode = ImageAsset(name: "qr_code") internal static let qrCodeScan = ImageAsset(name: "qr_code_scan") + internal static let remove = ImageAsset(name: "remove") internal static let revokeDevice = ImageAsset(name: "revoke_device") internal static let ringLogo = ImageAsset(name: "ring_logo") internal static let rowSelected = ColorAsset(name: "row_selected") diff --git a/Ring/Ring/Constants/Generated/Storyboards.swift b/Ring/Ring/Constants/Generated/Storyboards.swift index c54ec237047273e5b06ae8ca59ce1b34ffe8a596..d4e061bfc96e7182f1ed66372d9bae2eed606884 100644 --- a/Ring/Ring/Constants/Generated/Storyboards.swift +++ b/Ring/Ring/Constants/Generated/Storyboards.swift @@ -107,11 +107,6 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType<Ring.LinkNewDeviceViewController>(storyboard: LinkNewDeviceViewController.self) } - internal enum MeDetailViewController: StoryboardType { - internal static let storyboardName = "MeDetailViewController" - - internal static let initialScene = InitialSceneType<Ring.MeDetailViewController>(storyboard: MeDetailViewController.self) - } internal enum MeViewController: StoryboardType { internal static let storyboardName = "MeViewController" diff --git a/Ring/Ring/Constants/Generated/Strings.swift b/Ring/Ring/Constants/Generated/Strings.swift index e38caff060104aa48948109fa4fccba6ee8efdf5..c798ff57049b56ef8ebe3ee0938561b41207efce 100644 --- a/Ring/Ring/Constants/Generated/Strings.swift +++ b/Ring/Ring/Constants/Generated/Strings.swift @@ -431,7 +431,7 @@ internal enum L10n { } internal enum GeneralSettings { - /// General settings + /// Advanced settings internal static let title = L10n.tr("Localizable", "generalSettings.title") /// Enable video acceleration internal static let videoAcceleration = L10n.tr("Localizable", "generalSettings.videoAcceleration") @@ -459,13 +459,11 @@ internal enum L10n { internal enum Global { /// Close internal static let close = L10n.tr("Localizable", "global.close") - /// Invitations - internal static let contactRequestsTabBarTitle = L10n.tr("Localizable", "global.contactRequestsTabBarTitle") /// Forward internal static let forward = L10n.tr("Localizable", "global.forward") /// Conversations internal static let homeTabBarTitle = L10n.tr("Localizable", "global.homeTabBarTitle") - /// Account + /// Account Settings internal static let meTabBarTitle = L10n.tr("Localizable", "global.meTabBarTitle") /// Ok internal static let ok = L10n.tr("Localizable", "global.ok") @@ -583,14 +581,22 @@ internal enum L10n { } internal enum Smartlist { + /// About Jami + internal static let aboutJami = L10n.tr("Localizable", "smartlist.aboutJami") + /// Account Settings + internal static let accountSettings = L10n.tr("Localizable", "smartlist.accountSettings") /// Accounts internal static let accountsTitle = L10n.tr("Localizable", "smartlist.accountsTitle") /// + Add Account internal static let addAccountButton = L10n.tr("Localizable", "smartlist.addAccountButton") + /// Advanced Settings + internal static let advancedSettings = L10n.tr("Localizable", "smartlist.advancedSettings") /// Be sure cellular access is granted in your settings internal static let cellularAccess = L10n.tr("Localizable", "smartlist.cellularAccess") /// Conversations internal static let conversations = L10n.tr("Localizable", "smartlist.conversations") + /// Invitations + internal static let invitations = L10n.tr("Localizable", "smartlist.invitations") /// No conversations internal static let noConversation = L10n.tr("Localizable", "smartlist.noConversation") /// No network connectivity @@ -599,8 +605,10 @@ internal enum L10n { internal static let noNumber = L10n.tr("Localizable", "smartlist.noNumber") /// No results internal static let noResults = L10n.tr("Localizable", "smartlist.noResults") - /// Search Result + /// Public Directory internal static let results = L10n.tr("Localizable", "smartlist.results") + /// Search for new or existing contact... + internal static let searchBar = L10n.tr("Localizable", "smartlist.searchBar") /// Enter name... internal static let searchBarPlaceholder = L10n.tr("Localizable", "smartlist.searchBarPlaceholder") /// Searching... diff --git a/Ring/Ring/Contact/ContactViewController.storyboard b/Ring/Ring/Contact/ContactViewController.storyboard index 9bdf7803793b894bfc8848fe5e100ba67682d9ff..d85e78cbff1642f7143a95235ad730b313cd4dac 100644 --- a/Ring/Ring/Contact/ContactViewController.storyboard +++ b/Ring/Ring/Contact/ContactViewController.storyboard @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="4oO-a5-k5Y"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="4oO-a5-k5Y"> <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> @@ -16,9 +17,14 @@ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Yoa-iA-qFT"> + <rect key="frame" x="0.0" y="-100" width="375" height="767"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + </view> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="150" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Cjc-Dl-AsW"> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <color key="sectionIndexBackgroundColor" systemColor="systemBackgroundColor"/> <prototypes> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="default" indentationWidth="0.0" reuseIdentifier="ProfileInfoCell" rowHeight="60" id="fHK-Bg-4wI"> <rect key="frame" x="0.0" y="28" width="375" height="60"/> @@ -45,14 +51,18 @@ </prototypes> </tableView> </subviews> + <viewLayoutGuide key="safeArea" id="cTQ-BN-ANe"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <constraints> <constraint firstAttribute="trailing" secondItem="Cjc-Dl-AsW" secondAttribute="trailing" id="4gc-KZ-hMj"/> <constraint firstItem="Cjc-Dl-AsW" firstAttribute="top" secondItem="l1v-RV-Jo2" secondAttribute="top" id="FCK-2Z-zav"/> + <constraint firstItem="cTQ-BN-ANe" firstAttribute="trailing" secondItem="Yoa-iA-qFT" secondAttribute="trailing" id="Q4f-hl-vUO"/> <constraint firstItem="Cjc-Dl-AsW" firstAttribute="bottom" secondItem="cTQ-BN-ANe" secondAttribute="bottom" id="YSy-1B-Cde"/> <constraint firstItem="Cjc-Dl-AsW" firstAttribute="leading" secondItem="l1v-RV-Jo2" secondAttribute="leading" id="cmD-7d-ghB"/> + <constraint firstItem="Yoa-iA-qFT" firstAttribute="leading" secondItem="cTQ-BN-ANe" secondAttribute="leading" id="nTM-nf-KD4"/> + <constraint firstItem="cTQ-BN-ANe" firstAttribute="bottom" secondItem="Yoa-iA-qFT" secondAttribute="bottom" id="qjF-jg-BWS"/> + <constraint firstItem="Yoa-iA-qFT" firstAttribute="top" secondItem="l1v-RV-Jo2" secondAttribute="topMargin" constant="-100" id="x7i-xR-0h4"/> </constraints> - <viewLayoutGuide key="safeArea" id="cTQ-BN-ANe"/> </view> <extendedEdge key="edgesForExtendedLayout" bottom="YES"/> <connections> @@ -64,4 +74,9 @@ <point key="canvasLocation" x="132" y="-87.706146926536732"/> </scene> </scenes> + <resources> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> + </resources> </document> diff --git a/Ring/Ring/Contact/ContactViewModel.swift b/Ring/Ring/Contact/ContactViewModel.swift index b50197aaf394c7227e25fa5ad61be566a14cc1e2..a8d30ea840cceb70f67290b934ea5d49cfb644cb 100644 --- a/Ring/Ring/Contact/ContactViewModel.swift +++ b/Ring/Ring/Contact/ContactViewModel.swift @@ -183,6 +183,8 @@ class ContactViewModel: ViewModel, Stateable { self.conversationService .clearHistory(conversation: self.conversation, keepConversation: false) + self.stateSubject.onNext(ConversationState + .returnToSmartList) }) .disposed(by: self.disposeBag) } @@ -205,6 +207,8 @@ class ContactViewModel: ViewModel, Stateable { self.conversationService .clearHistory(conversation: self.conversation, keepConversation: false) + self.stateSubject.onNext(ConversationState + .returnToSmartList) }) .disposed(by: self.disposeBag) } diff --git a/Ring/Ring/Coordinators/AppCoordinator.swift b/Ring/Ring/Coordinators/AppCoordinator.swift index d3df5a04f92a620830f5eb9f2673615c0c29f899..0e3e69ec3f6c5a67c48778faaa71dad0710585de 100644 --- a/Ring/Ring/Coordinators/AppCoordinator.swift +++ b/Ring/Ring/Coordinators/AppCoordinator.swift @@ -33,9 +33,7 @@ public enum AppState: State { case needToOnboard(animated: Bool, isFirstAccount: Bool) case addAccount case allSet - case accountRemoved case needAccountMigration(accountId: String) - case accountModeSwitched } public enum VCType: String { @@ -66,9 +64,7 @@ final class AppCoordinator: Coordinator, StateableResponsive { // MARK: Private members private let navigationController = UINavigationController() - private let tabBarViewController = UITabBarController() - private let injectionBag: InjectionBag - private var mainInterfaceReady = false + let injectionBag: InjectionBag /// Initializer /// @@ -77,7 +73,6 @@ final class AppCoordinator: Coordinator, StateableResponsive { self.injectionBag = injectionBag self.navigationController.setNavigationBarHidden(true, animated: false) - self.prepareMainInterface() self.stateSubject .subscribe(onNext: { [weak self] (state) in @@ -91,12 +86,8 @@ final class AppCoordinator: Coordinator, StateableResponsive { self.showMainInterface() case .addAccount: self.showWalkthrough(animated: false, isAccountFirst: false) - case .accountRemoved: - self.accountRemoved() case .needAccountMigration(let accountId): self.migrateAccount(accountId: accountId) - case .accountModeSwitched: - self.switchAccountMode() } }) .disposed(by: self.disposeBag) @@ -110,14 +101,6 @@ final class AppCoordinator: Coordinator, StateableResponsive { self.dispatchApplication() } - func accountRemoved() { - self.tabBarViewController.selectedIndex = 0 - } - func switchAccountMode() { - self.childCoordinators[0].start() - self.tabBarViewController.selectedIndex = 0 - } - func migrateAccount(accountId: String) { let migratonController = MigrateAccountViewController.instantiate(with: self.injectionBag) migratonController.viewModel.accountToMigrate = accountId @@ -169,56 +152,32 @@ final class AppCoordinator: Coordinator, StateableResponsive { walkthroughCoordinator?.stateSubject.dispose() self?.removeChildCoordinator(childCoordinator: walkthroughCoordinator) self?.dispatchApplication() - self?.tabBarViewController.selectedIndex = 0 }) .disposed(by: self.disposeBag) } - /// Prepares the main interface, should only be executed once - private func prepareMainInterface() { - guard self.mainInterfaceReady == false else { - return - } + /// Presents the main interface + private func showMainInterface () { + if !self.childCoordinators.isEmpty, + self.childCoordinators[0] as? ConversationsCoordinator != nil { + return + } let conversationsCoordinator = ConversationsCoordinator(with: self.injectionBag) conversationsCoordinator.parentCoordinator = self - let contactRequestsCoordinator = ContactRequestsCoordinator(with: self.injectionBag) - contactRequestsCoordinator.parentCoordinator = self - let meCoordinator = MeCoordinator(with: self.injectionBag) - meCoordinator.parentCoordinator = self - self.tabBarViewController.tabBar.tintColor = UIColor.jamiMain - self.tabBarViewController.view.backgroundColor = UIColor.white - - self.tabBarViewController.viewControllers = [conversationsCoordinator.rootViewController, - contactRequestsCoordinator.rootViewController, - meCoordinator.rootViewController] - - self.addChildCoordinator(childCoordinator: conversationsCoordinator) - self.addChildCoordinator(childCoordinator: contactRequestsCoordinator) - self.addChildCoordinator(childCoordinator: meCoordinator) - + conversationsCoordinator.setNavigationController(controller: self.navigationController) conversationsCoordinator.start() - contactRequestsCoordinator.start() - meCoordinator.start() - - self.mainInterfaceReady = true - } - - /// Presents the main interface - private func showMainInterface () { - self.navigationController.setViewControllers([self.tabBarViewController], animated: true) + self.addChildCoordinator(childCoordinator: conversationsCoordinator) } func openConversation (participantID: String) { - self.tabBarViewController.selectedIndex = 0 if let conversationCoordinator = self.childCoordinators[0] as? ConversationsCoordinator { - conversationCoordinator.puchConversation(participantId: participantID) + conversationCoordinator.pushConversation(participantId: participantID) } } func startCall(participant: String, name: String, isVideo: Bool) { DispatchQueue.main.async { - self.tabBarViewController.selectedIndex = 0 for child in self.childCoordinators { if let childCoordinattor = child as? ConversationsCoordinator { if isVideo { diff --git a/Ring/Ring/Extensions/UIViewController+Ring.swift b/Ring/Ring/Extensions/UIViewController+Ring.swift index 989a73f3b0e581d9b687cf4f359ff6bbb7dffff8..8b75b9816da1aef11fa2376e7e0bb3fc982a3aac 100644 --- a/Ring/Ring/Extensions/UIViewController+Ring.swift +++ b/Ring/Ring/Extensions/UIViewController+Ring.swift @@ -132,14 +132,19 @@ extension UIViewController { self.navigationController?.navigationBar.barStyle = .default self.navigationController?.navigationBar.isTranslucent = true self.navigationController?.navigationBar.layer.shadowColor = UIColor.jamiNavigationBarShadow.cgColor - self.navigationController?.navigationBar.layer.shadowOffset = CGSize(width: 0.0, height: 1.5) - self.navigationController?.navigationBar.layer.shadowOpacity = 0.2 - self.navigationController?.navigationBar.layer.shadowRadius = 3 + self.navigationController?.navigationBar.layer.shadowOffset = CGSize(width: 0.0, height: 0.5) + self.navigationController?.navigationBar.layer.shadowOpacity = 0.1 + self.navigationController?.navigationBar.layer.shadowRadius = 2 self.navigationController?.navigationBar.layer.masksToBounds = false self.navigationController?.navigationBar.shadowImage = UIImage() let textAttributes = [NSAttributedString.Key.foregroundColor: UIColor.jamiMain] self.navigationController?.navigationBar.titleTextAttributes = textAttributes self.navigationController?.navigationBar.tintColor = UIColor.jamiMain + if #available(iOS 13.0, *) { + self.navigationController?.navigationBar.barTintColor = UIColor.systemBackground + } else { + self.navigationController?.navigationBar.barTintColor = UIColor.white + } } func configureWalkrhroughNavigationBar() { diff --git a/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.swift b/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.swift index cfd3664e726225cded1de593e28af90a1940acbf..df3e6e5ea13e8d1a992830914b4a544d580680e4 100644 --- a/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.swift +++ b/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.swift @@ -75,7 +75,7 @@ class ContactRequestCell: UITableViewCell, NibReusable { .addSubview( AvatarView(profileImageData: profileData.element?.0, username: data, - size: 40)) + size: 50)) return }) .disposed(by: self.disposeBag) diff --git a/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.xib b/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.xib index 0da957e083562313533e9235a78e23be2989f7cd..9be77b293ce7e5fa5a229a69ea6345ee0af17530 100644 --- a/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.xib +++ b/Ring/Ring/Features/ContactRequests/Cells/ContactRequestCell.xib @@ -1,119 +1,127 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> - <device id="retina4_7" orientation="portrait"> - <adaptation id="fullscreen"/> - </device> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> + <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> - <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="72" id="KZx-bh-W5G" customClass="ContactRequestCell" customModule="Ring" customModuleProvider="target"> + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="70" id="KZx-bh-W5G" customClass="ContactRequestCell" customModule="Ring" customModuleProvider="target"> <rect key="frame" x="0.0" y="0.0" width="470" height="72"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KZx-bh-W5G" id="YU4-Oq-lYT"> - <rect key="frame" x="0.0" y="0.0" width="470" height="71.5"/> + <rect key="frame" x="0.0" y="0.0" width="470" height="72"/> <autoresizingMask key="autoresizingMask"/> <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9NG-xW-Y5g" userLabel="Avatar View"> - <rect key="frame" x="16" y="16" width="40" height="40"/> - <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="aCO-e4-KsI"> + <rect key="frame" x="15" y="10" width="440" height="52"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9NG-xW-Y5g" userLabel="Avatar View"> + <rect key="frame" x="0.0" y="1" width="50" height="50"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <constraints> + <constraint firstAttribute="height" constant="50" id="2fD-fw-BFv"/> + <constraint firstAttribute="width" constant="50" id="7gu-BP-2Ld"/> + </constraints> + </view> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dla-OF-biH"> + <rect key="frame" x="65" y="15.5" width="140" height="21"/> + <constraints> + <constraint firstAttribute="height" constant="21" id="rIm-Pj-KP3"/> + </constraints> + <fontDescription key="fontDescription" type="boldSystem" pointSize="14"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="klf-Xm-XH9"> + <rect key="frame" x="330" y="11" width="110" height="30"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="feR-9F-sZM"> + <rect key="frame" x="0.0" y="0.0" width="30" height="30"/> + <constraints> + <constraint firstAttribute="width" constant="30" id="F6k-BD-rff"/> + <constraint firstAttribute="height" constant="30" id="mgC-Pn-LLR"/> + </constraints> + <color key="tintColor" red="0.0" green="0.69803921568627447" blue="0.043137254901960784" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + <state key="normal" image="done_icon"> + <color key="titleColor" red="0.0" green="0.69803921568627447" blue="0.043137254901960784" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + </state> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> + <integer key="value" value="15"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> + <color key="value" red="0.0" green="0.69803921568627447" blue="0.043137254901960784" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> + <integer key="value" value="2"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fWB-HR-tae"> + <rect key="frame" x="40" y="0.0" width="30" height="30"/> + <constraints> + <constraint firstAttribute="width" constant="30" id="BU4-ED-Mry"/> + <constraint firstAttribute="height" constant="30" id="fQt-vU-mXY"/> + </constraints> + <color key="tintColor" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> + <state key="normal" image="remove"> + <color key="titleColor" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> + </state> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> + <integer key="value" value="2"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> + <color key="value" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> + <integer key="value" value="15"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Pni-bm-rkr"> + <rect key="frame" x="80" y="0.0" width="30" height="30"/> + <constraints> + <constraint firstAttribute="height" constant="30" id="Bee-OT-mx8"/> + <constraint firstAttribute="width" constant="30" id="dsw-SF-fZe"/> + </constraints> + <color key="tintColor" red="0.94117647059999998" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> + <state key="normal" image="close_icon"> + <color key="titleColor" red="0.94117647059999998" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + </state> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> + <integer key="value" value="2"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> + <color key="value" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> + <integer key="value" value="15"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </button> + </subviews> + <constraints> + <constraint firstAttribute="width" constant="110" id="Y0h-W8-ovK"/> + </constraints> + </stackView> + </subviews> <constraints> - <constraint firstAttribute="height" constant="40" id="2fD-fw-BFv"/> - <constraint firstAttribute="width" constant="40" id="7gu-BP-2Ld"/> + <constraint firstItem="klf-Xm-XH9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Dla-OF-biH" secondAttribute="trailing" constant="20" id="Ubj-cl-vVH"/> + <constraint firstItem="Dla-OF-biH" firstAttribute="leading" secondItem="9NG-xW-Y5g" secondAttribute="trailing" constant="15" id="Xtk-Xy-82k"/> </constraints> - </view> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="feR-9F-sZM"> - <rect key="frame" x="244" y="33.5" width="70" height="30"/> - <constraints> - <constraint firstAttribute="width" constant="70" id="F6k-BD-rff"/> - <constraint firstAttribute="height" constant="30" id="mgC-Pn-LLR"/> - </constraints> - <state key="normal" title="Accept"> - <color key="titleColor" red="0.0" green="0.69803921568627447" blue="0.043137254901960784" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> - </state> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> - <integer key="value" value="15"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> - <color key="value" red="0.0" green="0.69803921568627447" blue="0.043137254901960784" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> - <integer key="value" value="2"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fWB-HR-tae"> - <rect key="frame" x="318" y="33.5" width="70" height="30"/> - <constraints> - <constraint firstAttribute="width" constant="70" id="BU4-ED-Mry"/> - <constraint firstAttribute="height" constant="30" id="fQt-vU-mXY"/> - </constraints> - <state key="normal" title="Ignore"> - <color key="titleColor" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> - </state> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> - <integer key="value" value="2"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> - <color key="value" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> - <integer key="value" value="15"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Pni-bm-rkr"> - <rect key="frame" x="392" y="33.5" width="70" height="30"/> - <constraints> - <constraint firstAttribute="height" constant="30" id="Bee-OT-mx8"/> - <constraint firstAttribute="width" constant="70" id="dsw-SF-fZe"/> - </constraints> - <state key="normal" title="Ban"> - <color key="titleColor" red="0.94117647059999998" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> - </state> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> - <integer key="value" value="2"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> - <color key="value" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> - <integer key="value" value="15"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </button> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dla-OF-biH"> - <rect key="frame" x="64" y="8.5" width="398" height="21"/> - <constraints> - <constraint firstAttribute="height" constant="21" id="rIm-Pj-KP3"/> - </constraints> - <fontDescription key="fontDescription" type="boldSystem" pointSize="14"/> - <nil key="textColor"/> - <nil key="highlightedColor"/> - </label> + </stackView> </subviews> <constraints> - <constraint firstItem="Pni-bm-rkr" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="4" id="0jS-6Q-w8N"/> - <constraint firstItem="feR-9F-sZM" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="4" id="Gba-vQ-Ebp"/> - <constraint firstAttribute="bottom" secondItem="Pni-bm-rkr" secondAttribute="bottom" constant="8" id="KNE-9A-qWk"/> - <constraint firstItem="9NG-xW-Y5g" firstAttribute="centerY" secondItem="YU4-Oq-lYT" secondAttribute="centerY" id="Ofv-lu-x2h"/> - <constraint firstItem="fWB-HR-tae" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="4" id="QMX-zx-zpZ"/> - <constraint firstItem="Pni-bm-rkr" firstAttribute="leading" secondItem="fWB-HR-tae" secondAttribute="trailing" constant="4" id="XcH-3n-PeT"/> - <constraint firstAttribute="bottom" secondItem="fWB-HR-tae" secondAttribute="bottom" constant="8" id="Z44-tV-yAn"/> - <constraint firstAttribute="bottom" secondItem="feR-9F-sZM" secondAttribute="bottom" constant="8" id="hAP-C0-nE5"/> - <constraint firstItem="Dla-OF-biH" firstAttribute="top" secondItem="YU4-Oq-lYT" secondAttribute="top" constant="8" id="hqf-Iv-xvb"/> - <constraint firstItem="fWB-HR-tae" firstAttribute="leading" secondItem="feR-9F-sZM" secondAttribute="trailing" constant="4" id="lfX-2s-AsZ"/> - <constraint firstAttribute="trailing" secondItem="Pni-bm-rkr" secondAttribute="trailing" constant="8" id="sDu-vC-6gU"/> - <constraint firstItem="Dla-OF-biH" firstAttribute="leading" secondItem="9NG-xW-Y5g" secondAttribute="trailing" constant="8" id="ttD-Zx-Fv7"/> - <constraint firstAttribute="trailing" secondItem="Dla-OF-biH" secondAttribute="trailing" constant="8" id="wFU-JT-uD3"/> - <constraint firstItem="9NG-xW-Y5g" firstAttribute="leading" secondItem="YU4-Oq-lYT" secondAttribute="leading" constant="16" id="zsy-tX-JRZ"/> + <constraint firstAttribute="bottom" secondItem="aCO-e4-KsI" secondAttribute="bottom" constant="10" id="4WN-Xl-S1O"/> + <constraint firstItem="aCO-e4-KsI" firstAttribute="top" secondItem="YU4-Oq-lYT" secondAttribute="top" constant="10" id="8hg-Un-3P0"/> + <constraint firstAttribute="trailing" secondItem="aCO-e4-KsI" secondAttribute="trailing" constant="15" id="ij4-jn-hy9"/> + <constraint firstItem="aCO-e4-KsI" firstAttribute="leading" secondItem="YU4-Oq-lYT" secondAttribute="leading" constant="15" id="swY-Vn-ot6"/> </constraints> </tableViewCellContentView> <connections> @@ -126,4 +134,9 @@ <point key="canvasLocation" x="177" y="-50"/> </tableViewCell> </objects> + <resources> + <image name="close_icon" width="24" height="24"/> + <image name="done_icon" width="24" height="24"/> + <image name="remove" width="24" height="24"/> + </resources> </document> diff --git a/Ring/Ring/Features/ContactRequests/ContactRequestsCoordinator.swift b/Ring/Ring/Features/ContactRequests/ContactRequestsCoordinator.swift deleted file mode 100644 index e85ff73ccfb562dfcac10eef5dd27a43bba4cd5e..0000000000000000000000000000000000000000 --- a/Ring/Ring/Features/ContactRequests/ContactRequestsCoordinator.swift +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. - * - * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -import Foundation -import RxSwift - -/// This Coordinator drives the Contact Requests navigation -class ContactRequestsCoordinator: Coordinator, StateableResponsive, ConversationNavigation { - - var presentingVC = [String: Bool]() - var rootViewController: UIViewController { - return self.navigationViewController - } - - var childCoordinators = [Coordinator]() - var parentCoordinator: Coordinator? - - private let navigationViewController = BaseViewController(with: TabBarItemType.contactRequest) - let injectionBag: InjectionBag - let disposeBag = DisposeBag() - - let stateSubject = PublishSubject<State>() - let contactService: ContactsService - - required init (with injectionBag: InjectionBag) { - self.injectionBag = injectionBag - self.contactService = injectionBag.contactsService - self.navigationViewController.viewModel = - ContactRequestTabBarItem(with: self.injectionBag) - self.addLockFlags() - self.callbackPlaceCall() - self.injectionBag.accountService - .currentAccountChanged - .observeOn(MainScheduler.instance) - .subscribe(onNext: {[weak self] _ in - guard let self = self else { return } - self.navigationViewController.viewModel = - ContactRequestTabBarItem(with: self.injectionBag) - }) - .disposed(by: self.disposeBag) - } - func addLockFlags() { - presentingVC[VCType.contact.rawValue] = false - presentingVC[VCType.conversation.rawValue] = false - } - func start () { - let contactRequestsViewController = ContactRequestsViewController.instantiate(with: self.injectionBag) - self.present(viewController: contactRequestsViewController, withStyle: .show, withAnimation: true, withStateable: contactRequestsViewController.viewModel) - } -} diff --git a/Ring/Ring/Features/ContactRequests/ContactRequestsViewController.swift b/Ring/Ring/Features/ContactRequests/ContactRequestsViewController.swift index 922db42133561d031326e120c72d9816f2ab097d..005d52783d39cf96945821aee455590ce72d658d 100644 --- a/Ring/Ring/Features/ContactRequests/ContactRequestsViewController.swift +++ b/Ring/Ring/Features/ContactRequests/ContactRequestsViewController.swift @@ -67,7 +67,6 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode } func applyL10n() { - self.navigationItem.title = L10n.Global.contactRequestsTabBarTitle self.noRequestsLabel.text = L10n.Invitations.noInvitations } @@ -75,6 +74,7 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode self.tableView.estimatedRowHeight = 100.0 self.tableView.rowHeight = UITableView.automaticDimension self.tableView.allowsSelection = true + self.tableView.tableFooterView = UIView() //Register cell self.tableView.register(cellType: ContactRequestCell.self) @@ -91,6 +91,7 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode cell.acceptButton.rx.tap .subscribe(onNext: { [weak self] in self?.acceptButtonTapped(withItem: item) + self?.view.isHidden = true }) .disposed(by: cell.disposeBag) @@ -99,6 +100,7 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode cell.discardButton.rx.tap .subscribe(onNext: { [weak self] in self?.discardButtonTapped(withItem: item) + self?.view.isHidden = true }) .disposed(by: cell.disposeBag) @@ -107,6 +109,7 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode cell.banButton.rx.tap .subscribe(onNext: { [weak self] in self?.banButtonTapped(withItem: item) + self?.view.isHidden = true }) .disposed(by: cell.disposeBag) } @@ -120,6 +123,16 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode .observeOn(MainScheduler.instance) .bind(to: self.noInvitationsPlaceholder.rx.isHidden) .disposed(by: self.disposeBag) + + self.viewModel + .hasInvitations + .observeOn(MainScheduler.instance) + .subscribe(onNext: {[weak self] hasInvitation in + if !hasInvitation { + self?.view.isHidden = true + } + }) + .disposed(by: self.disposeBag) } func acceptButtonTapped(withItem item: ContactRequestItem) { diff --git a/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift b/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift index 975010e0014a7da7666dd673a93ec12bee73aaed..5a94879898c834bf664bc3a2c5cbe59dae512ae6 100644 --- a/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift +++ b/Ring/Ring/Features/ContactRequests/ContactRequestsViewModel.swift @@ -54,7 +54,7 @@ class ContactRequestsViewModel: Stateable, ViewModel { self.injectionBag = injectionBag } - lazy var contactRequestItems: Observable<[ContactRequestItem]> = { + lazy var contactRequestItemsNotFiltered: Observable<[ContactRequestItem]> = { return self.contactsService.contactRequests .asObservable() .map({ [weak self] contactRequests in @@ -72,6 +72,17 @@ class ContactRequestsViewModel: Stateable, ViewModel { }) }() + let filter = BehaviorRelay(value: "") + + lazy var contactRequestItems: Observable<[ContactRequestItem]> = { + return Observable + .combineLatest(contactRequestItemsNotFiltered, filter.asObservable()) { (requests, filter) -> [ContactRequestItem] in + return requests.filter { request in + return request.userName.value.contains(filter) || request.profileName.value.contains(filter) || filter.isEmpty + } + } + }() + lazy var hasInvitations: Observable<Bool> = { return self.contactsService.contactRequests .asObservable() diff --git a/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.storyboard b/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.storyboard index d956f81378745e963c45e48a7ee40385272b5e65..f8247760ff203384758d0e9bb4b25671c88a06b1 100644 --- a/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.storyboard +++ b/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.storyboard @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="O1m-sW-gim"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="O1m-sW-gim"> <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> @@ -17,8 +18,8 @@ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="yc2-Jn-6vm"> - <rect key="frame" x="0.0" y="-50" width="375" height="717"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <rect key="frame" x="0.0" y="-100" width="375" height="767"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <prototypes> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="MessageCell" id="Cd7-Fm-IM5"> <rect key="frame" x="0.0" y="28" width="375" height="44"/> @@ -37,7 +38,7 @@ <color key="textColor" red="0.1215686275" green="0.28627450980000002" blue="0.4431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ehB-ol-cdx"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ehB-ol-cdx"> <rect key="frame" x="0.0" y="0.0" width="375" height="60"/> <constraints> <constraint firstAttribute="height" constant="60" id="e7R-TC-NQ2"/> @@ -71,6 +72,7 @@ <blurEffect style="regular"/> </visualEffectView> </subviews> + <viewLayoutGuide key="safeArea" id="mrp-Ty-hZO"/> <constraints> <constraint firstItem="ehB-ol-cdx" firstAttribute="leading" secondItem="lhx-ny-Zct" secondAttribute="leading" id="AUO-95-xlZ"/> <constraint firstItem="XRu-HM-jhQ" firstAttribute="bottom" secondItem="yc2-Jn-6vm" secondAttribute="bottom" id="D1h-vM-lOK"/> @@ -80,7 +82,7 @@ <constraint firstAttribute="trailing" secondItem="yc2-Jn-6vm" secondAttribute="trailing" id="Vbp-Qr-Bjn"/> <constraint firstItem="XRu-HM-jhQ" firstAttribute="centerX" secondItem="yc2-Jn-6vm" secondAttribute="centerX" id="Y16-31-gDX"/> <constraint firstItem="5cj-ge-3dv" firstAttribute="leading" secondItem="ehB-ol-cdx" secondAttribute="leading" id="ZMK-xT-VM8"/> - <constraint firstItem="yc2-Jn-6vm" firstAttribute="top" secondItem="mrp-Ty-hZO" secondAttribute="top" constant="-50" id="a1b-Sx-HXo"/> + <constraint firstItem="yc2-Jn-6vm" firstAttribute="top" secondItem="mrp-Ty-hZO" secondAttribute="top" constant="-100" id="a1b-Sx-HXo"/> <constraint firstItem="5cj-ge-3dv" firstAttribute="trailing" secondItem="ehB-ol-cdx" secondAttribute="trailing" id="adg-fs-d5i"/> <constraint firstItem="5cj-ge-3dv" firstAttribute="top" secondItem="ehB-ol-cdx" secondAttribute="top" id="bMn-Xz-w1J"/> <constraint firstItem="5cj-ge-3dv" firstAttribute="bottom" secondItem="ehB-ol-cdx" secondAttribute="bottom" id="bi2-5t-Ueh"/> @@ -91,7 +93,6 @@ <constraint firstItem="XRu-HM-jhQ" firstAttribute="width" secondItem="yc2-Jn-6vm" secondAttribute="width" id="vBi-yc-6H9"/> <constraint firstItem="6Wq-EJ-CAF" firstAttribute="leading" secondItem="lhx-ny-Zct" secondAttribute="leading" id="was-ym-C9C"/> </constraints> - <viewLayoutGuide key="safeArea" id="mrp-Ty-hZO"/> </view> <connections> <outlet property="callButtonHeightConstraint" destination="e7R-TC-NQ2" id="5uM-Sy-1EZ"/> @@ -106,4 +107,9 @@ <point key="canvasLocation" x="844" y="-1179.7601199400301"/> </scene> </scenes> + <resources> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> + </resources> </document> diff --git a/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift b/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift index 5c56ec1f37f38303721fc33eb3838b9e028a9e1f..98072ab55564f6aa3465371df9caf551d7023dc0 100644 --- a/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift +++ b/Ring/Ring/Features/Conversations/Conversation/ConversationViewController.swift @@ -113,6 +113,9 @@ class ConversationViewController: UIViewController, super.viewWillAppear(animated) self.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default) self.navigationController?.navigationBar.layer.shadowColor = UIColor.jamiNavigationBarShadow.cgColor + self.setupNavTitle(profileImageData: self.viewModel.profileImageData.value, + displayName: self.viewModel.displayName.value, + username: self.viewModel.userName.value) } private func importDocument() { @@ -434,7 +437,7 @@ class ConversationViewController: UIViewController, var userNameYOffset = CGFloat(9.0) var nameSize = CGFloat(18.0) let navbarFrame = self.navigationController?.navigationBar.frame - let totalHeight = ((navbarFrame?.size.height ?? 0) + (navbarFrame?.origin.y ?? 0)) / 2 + let totalHeight = (44 + (navbarFrame?.origin.y ?? 0)) / 2 // Replace "< Home" with a back arrow while we are crunching everything to the left side of the bar for now. self.navigationController?.navigationBar.backIndicatorImage = UIImage(named: "back_button") @@ -539,10 +542,6 @@ class ConversationViewController: UIViewController, }) .disposed(by: self.disposeBag) - self.setupNavTitle(profileImageData: self.viewModel.profileImageData.value, - displayName: self.viewModel.displayName.value, - username: self.viewModel.userName.value) - Observable<(Data?, String?, String)>.combineLatest(self.viewModel.profileImageData.asObservable(), self.viewModel.displayName.asObservable(), self.viewModel.userName.asObservable()) { profileImage, displayName, username in diff --git a/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift b/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift index 20f8fd5e9939b41a3396be6cde21805dea41cf95..e016d9334064c9d87de01ff2f6c69ecb40fa3ad0 100644 --- a/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift +++ b/Ring/Ring/Features/Conversations/Conversation/ConversationViewModel.swift @@ -256,6 +256,10 @@ class ConversationViewModel: Stateable, ViewModel { if self.conversation.value.messages.isEmpty { self.sendContactRequest() } + let contact = self.contactsService.contact(withUri: self.conversation.value.participantUri) + if contact == nil { + self.sendContactRequest() + } var receipientURI = self.conversation.value.participantUri if let contactURI = contactURI { receipientURI = contactURI @@ -367,6 +371,10 @@ class ConversationViewModel: Stateable, ViewModel { if self.conversation.value.messages.isEmpty { self.sendContactRequest() } + let contact = self.contactsService.contact(withUri: self.conversation.value.participantUri) + if contact == nil { + self.sendContactRequest() + } self.closeAllPlayers() self.stateSubject.onNext(ConversationState.startCall(contactRingId: self.conversation.value.hash, userName: self.displayName.value ?? self.userName.value)) } @@ -375,6 +383,10 @@ class ConversationViewModel: Stateable, ViewModel { if self.conversation.value.messages.isEmpty { self.sendContactRequest() } + let contact = self.contactsService.contact(withUri: self.conversation.value.participantUri) + if contact == nil { + self.sendContactRequest() + } self.closeAllPlayers() self.stateSubject.onNext(ConversationState.startAudioCall(contactRingId: self.conversation.value.hash, userName: self.displayName.value ?? self.userName.value)) } @@ -690,6 +702,10 @@ extension ConversationViewModel { if self.conversation.value.messages.isEmpty { self.sendContactRequest() } + let contact = self.contactsService.contact(withUri: self.conversation.value.participantUri) + if contact == nil { + self.sendContactRequest() + } guard let account = self.accountService.currentAccount else { return } self.locationSharingService.startSharingLocation(from: account.id, @@ -808,6 +824,10 @@ extension ConversationViewModel { func sendFile(filePath: String, displayName: String, localIdentifier: String? = nil, contactHash: String? = nil) { guard let accountId = accountService.currentAccount?.id else { return } + let contact = self.contactsService.contact(withUri: self.conversation.value.participantUri) + if contact == nil { + self.sendContactRequest() + } var hash = self.conversation.value.hash if let contactHash = contactHash { hash = contactHash @@ -821,6 +841,10 @@ extension ConversationViewModel { func sendAndSaveFile(displayName: String, imageData: Data, contactHash: String? = nil, conversation: String? = nil) { guard let accountId = accountService.currentAccount?.id else { return } + let contact = self.contactsService.contact(withUri: self.conversation.value.participantUri) + if contact == nil { + self.sendContactRequest() + } var hash = self.conversation.value.hash if let contactHash = contactHash { hash = contactHash diff --git a/Ring/Ring/Features/Conversations/ConversationsCoordinator.swift b/Ring/Ring/Features/Conversations/ConversationsCoordinator.swift index d6057b9150712653e9a2d27b3b9bf3b184513e00..158c84cbd415142d99a176b00121e7f29c68968a 100644 --- a/Ring/Ring/Features/Conversations/ConversationsCoordinator.swift +++ b/Ring/Ring/Features/Conversations/ConversationsCoordinator.swift @@ -33,8 +33,9 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa var childCoordinators = [Coordinator]() var parentCoordinator: Coordinator? + var smartListViewController = UIViewController() - private let navigationViewController = BaseViewController(with: TabBarItemType.chat) + private var navigationViewController = UINavigationController() let injectionBag: InjectionBag let disposeBag = DisposeBag() @@ -65,11 +66,23 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa case .showGeneralSettings: self.showGeneralSettings() case .navigateToCall(let call): - self.presentCallController(call: call) + self.navigateToCall(call: call) case .showContactPicker(let callID, let callBack): self.showContactPicker(callId: callID, contactSelectedCB: callBack) case .replaceCurrentWithConversationFor(let participantUri): self.replaceCurrentWithConversationFor(participantUri: participantUri) + case .showAccountSettings: + self.showAccountSettings() + case .accountRemoved: + self.popToSmartList() + case .needToOnboard: + self.needToOnboard() + case .accountModeChanged: + self.accountModeChanged() + case .migrateAccount(let accountId): + self.migrateAccount(accountId: accountId) + case .returnToSmartList: + self.popToSmartList() default: break } @@ -83,22 +96,38 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa self.showIncomingCall(call: call) }) .disposed(by: self.disposeBag) - self.navigationViewController.viewModel = ChatTabBarItemViewModel(with: self.injectionBag) self.callbackPlaceCall() - //for iOS version less than 10 support open call from notification - NotificationCenter.default.addObserver(self, selector: #selector(self.answerIncomingCall(_:)), name: NSNotification.Name(NotificationName.answerCallFromNotifications.rawValue), object: nil) + } - self.accountService.currentAccountChanged - .observeOn(MainScheduler.instance) - .subscribe(onNext: {[weak self] _ in - guard let self = self else { return } - self.navigationViewController.viewModel = - ChatTabBarItemViewModel(with: self.injectionBag) - }) - .disposed(by: self.disposeBag) + func needToOnboard() { + if let parent = self.parentCoordinator as? AppCoordinator { + parent.stateSubject.onNext(AppState.needToOnboard(animated: false, isFirstAccount: true)) + } + } + func accountModeChanged() { + self.start() + } + + func migrateAccount(accountId: String) { + if let parent = self.parentCoordinator as? AppCoordinator { + parent.stateSubject.onNext(AppState.needAccountMigration(accountId: accountId)) + } + } + + func showAccountSettings() { + let meCoordinator = MeCoordinator(with: self.injectionBag) + meCoordinator.parentCoordinator = self + meCoordinator.setNavigationController(controller: self.navigationViewController) + self.addChildCoordinator(childCoordinator: meCoordinator) + meCoordinator.start() + self.smartListViewController.rx.viewWillAppear + .take(1) + .subscribe(onNext: { [weak self, weak meCoordinator] (_) in + self?.removeChildCoordinator(childCoordinator: meCoordinator) + }) + .disposed(by: self.disposeBag) } - // swiftlint:disable cyclomatic_complexity func showIncomingCall(call: CallModel) { guard let account = self.accountService .getAccount(fromAccountId: call.accountId), @@ -120,28 +149,7 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa var tempBag = DisposeBag() call.callUUID = UUID() callsProvider - .reportIncomingCall(account: account, call: call) { _ in - // if starting CallKit failed fallback to jami call screen - if UIApplication.shared.applicationState != .active { - if AccountModelHelper - .init(withAccount: account).isAccountSip() || - !self.accountService.getCurrentProxyState(accountID: account.id) { - return - } - self.triggerCallNotifications(call: call) - return - } - if account.id != call.accountId { - self.accountService.currentAccount = self.accountService.getAccount(fromAccountId: call.accountId) - } - topController.dismiss(animated: false, completion: nil) - guard let parent = self.parentCoordinator as? AppCoordinator else { return } - parent.openConversation(participantID: call.participantUri) - self.present(viewController: callViewController, - withStyle: .appear, - withAnimation: false, - withStateable: callViewController.viewModel) - } + .reportIncomingCall(account: account, call: call, completion: nil) callsProvider.sharedResponseStream .filter({ serviceEvent in if serviceEvent.eventType != ServiceEventType.callProviderAnswerCall { @@ -152,13 +160,14 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa return callUUID == call.callUUID.uuidString }) .subscribe(onNext: { _ in - self.navigationViewController.popToRootViewController(animated: false) + topController.dismiss(animated: false, completion: nil) + self.popToSmartList() if account.id != call.accountId { self.accountService.currentAccount = self.accountService.getAccount(fromAccountId: call.accountId) } - topController.dismiss(animated: false, completion: nil) - guard let parent = self.parentCoordinator as? AppCoordinator else { return } - parent.openConversation(participantID: call.participantUri) + self.popToSmartList() + if let model = self.getConversationViewModel(participantUri: call.paricipantHash()) { self.showConversation(withConversationViewModel: model) + } self.present(viewController: callViewController, withStyle: .appear, withAnimation: false, @@ -209,16 +218,20 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa func showGeneralSettings() { let settingsViewController = GeneralSettingsViewController.instantiate(with: self.injectionBag) - self.present(viewController: settingsViewController, withStyle: .present, withAnimation: true, disposeBag: self.disposeBag) + self.present(viewController: settingsViewController, withStyle: .show, withAnimation: true, disposeBag: self.disposeBag) } func replaceCurrentWithConversationFor(participantUri: String) { guard let model = getConversationViewModel(participantUri: participantUri) else { return } - self.navigationViewController.popToRootViewController(animated: false) + self.popToSmartList() self.showConversation(withConversationViewModel: model) } - func puchConversation(participantId: String) { + func popToSmartList() { + navigationViewController.popToViewController(smartListViewController, animated: false) + } + + func pushConversation(participantId: String) { guard let account = accountService.currentAccount else { return } @@ -238,15 +251,27 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa } func start() { - self.navigationViewController.viewControllers.removeAll() let boothMode = self.accountService.boothMode() if boothMode { - let smartListViewController = IncognitoSmartListViewController.instantiate(with: self.injectionBag) - self.present(viewController: smartListViewController, withStyle: .show, withAnimation: true, withStateable: smartListViewController.viewModel) + let smartViewController = IncognitoSmartListViewController.instantiate(with: self.injectionBag) + self.present(viewController: smartViewController, withStyle: .show, withAnimation: true, withStateable: smartViewController.viewModel) + smartListViewController = smartViewController return } - let smartListViewController = SmartlistViewController.instantiate(with: self.injectionBag) - self.present(viewController: smartListViewController, withStyle: .show, withAnimation: true, withStateable: smartListViewController.viewModel) + let smartViewController = SmartlistViewController.instantiate(with: self.injectionBag) + let contactRequestsViewController = ContactRequestsViewController.instantiate(with: self.injectionBag) + contactRequestsViewController.viewModel.state.takeUntil(contactRequestsViewController.rx.deallocated) + .subscribe(onNext: { [weak self] (state) in + self?.stateSubject.onNext(state) + }) + .disposed(by: self.disposeBag) + smartViewController.addContactRequestVC(controller: contactRequestsViewController) + self.present(viewController: smartViewController, withStyle: .show, withAnimation: true, withStateable: smartViewController.viewModel) + smartListViewController = smartViewController + } + + func setNavigationController(controller: UINavigationController) { + navigationViewController = controller } func getConversationViewModel(participantUri: String) -> ConversationViewModel? { @@ -265,35 +290,4 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa presentingVC[VCType.contact.rawValue] = false presentingVC[VCType.conversation.rawValue] = false } - - //open call controller when button navigate to call pressed - - func triggerCallNotifications(call: CallModel) { - var data = [String: String]() - data [NotificationUserInfoKeys.name.rawValue] = call.displayName - data [NotificationUserInfoKeys.callID.rawValue] = call.callId - data [NotificationUserInfoKeys.accountID.rawValue] = call.accountId - let helper = LocalNotificationsHelper() - helper.presentCallNotification(data: data, callService: self.callService) - } - -// MARK: - iOS 9.3 - 10 - - @objc - func answerIncomingCall(_ notification: NSNotification) { - guard let callid = notification.userInfo?[NotificationUserInfoKeys.callID.rawValue] as? String, - let call = self.callService.call(callID: callid) else { - return - } - let callViewController = CallViewController.instantiate(with: self.injectionBag) - callViewController.viewModel.call = call - callViewController.viewModel.answerCall() - .subscribe(onCompleted: { [weak self] in - self?.present(viewController: callViewController, - withStyle: .present, - withAnimation: false, - withStateable: callViewController.viewModel) - }) - .disposed(by: self.disposeBag) - } } diff --git a/Ring/Ring/Features/Conversations/SmartList/Cells/ConversationCell.swift b/Ring/Ring/Features/Conversations/SmartList/Cells/ConversationCell.swift index 1083b358c937f1c0865d397838eaf295b435d891..bea6b9c769c52b48b14576f71b84b818155783f6 100644 --- a/Ring/Ring/Features/Conversations/SmartList/Cells/ConversationCell.swift +++ b/Ring/Ring/Features/Conversations/SmartList/Cells/ConversationCell.swift @@ -36,7 +36,7 @@ class ConversationCell: UITableViewCell, NibReusable { @IBOutlet weak var selectionIndicator: UIButton? @IBOutlet weak var selectionContainer: UIView? - var avatarSize: CGFloat { return 40 } + var avatarSize: CGFloat { return 50 } override func setSelected(_ selected: Bool, animated: Bool) { let initialColor = selected ? UIColor.jamiUITableViewCellSelection : UIColor.jamiUITableViewCellSelection.lighten(by: 5.0) @@ -74,7 +74,7 @@ class ConversationCell: UITableViewCell, NibReusable { self?.avatarView.subviews.forEach({ $0.removeFromSuperview() }) self?.avatarView.addSubview(AvatarView(profileImageData: profileData.element?.0, username: data, - size: self?.avatarSize ?? 40)) + size: self?.avatarSize ?? 50)) }) .disposed(by: self.disposeBag) diff --git a/Ring/Ring/Features/Conversations/SmartList/Cells/SmartListCell.xib b/Ring/Ring/Features/Conversations/SmartList/Cells/SmartListCell.xib index c822e24dc36549d4338fd9f6390481bed341d783..e688f591194c7b2cf92dfe352aaf29b4224d98a7 100644 --- a/Ring/Ring/Features/Conversations/SmartList/Cells/SmartListCell.xib +++ b/Ring/Ring/Features/Conversations/SmartList/Cells/SmartListCell.xib @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> - <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="76" id="KGk-i7-Jjw" customClass="SmartListCell" customModule="Ring" customModuleProvider="target"> + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="70" id="KGk-i7-Jjw" customClass="SmartListCell" customModule="Ring" customModuleProvider="target"> <rect key="frame" x="0.0" y="0.0" width="358" height="76"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> @@ -22,7 +22,7 @@ <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NKy-ZG-e6V"> <rect key="frame" x="-36" y="18" width="36" height="40"/> <subviews> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kb7-S0-UM0"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kb7-S0-UM0"> <rect key="frame" x="20" y="12" width="16" height="16"/> <constraints> <constraint firstAttribute="width" constant="16" id="0A8-Cc-BGp"/> @@ -47,18 +47,18 @@ </constraints> </view> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e5s-ek-YI6"> - <rect key="frame" x="0.0" y="0.0" width="70" height="76"/> + <rect key="frame" x="0.0" y="0.0" width="80" height="76"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KC4-sG-yj8" userLabel="Avatar View"> - <rect key="frame" x="20" y="18" width="40" height="40"/> + <rect key="frame" x="15" y="13" width="50" height="50"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <constraints> - <constraint firstAttribute="height" constant="40" id="IHe-eH-Wry"/> - <constraint firstAttribute="width" constant="40" id="w7u-Cr-DTg"/> + <constraint firstAttribute="height" constant="50" id="IHe-eH-Wry"/> + <constraint firstAttribute="width" constant="50" id="w7u-Cr-DTg"/> </constraints> </view> <view clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="JTE-eF-Y5s"> - <rect key="frame" x="46" y="18" width="14" height="14"/> + <rect key="frame" x="51" y="13" width="14" height="14"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="P5S-4k-0yx"> <rect key="frame" x="0.0" y="0.0" width="14" height="14"/> @@ -85,7 +85,7 @@ </userDefinedRuntimeAttributes> </view> <view clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="Fpi-20-ZYV" userLabel="Presence Indicator"> - <rect key="frame" x="46" y="44" width="14" height="14"/> + <rect key="frame" x="51" y="49" width="14" height="14"/> <color key="backgroundColor" red="0.0" green="0.90196078431372551" blue="0.46274509803921571" alpha="1" colorSpace="calibratedRGB"/> <constraints> <constraint firstAttribute="height" constant="14" id="0m2-aN-1GT"/> @@ -107,48 +107,65 @@ <constraints> <constraint firstItem="JTE-eF-Y5s" firstAttribute="top" secondItem="KC4-sG-yj8" secondAttribute="top" id="aaj-yl-r3s"/> <constraint firstItem="Fpi-20-ZYV" firstAttribute="trailing" secondItem="KC4-sG-yj8" secondAttribute="trailing" id="bmB-Ld-bTz"/> - <constraint firstAttribute="width" constant="70" id="ftJ-Ib-VTX"/> + <constraint firstAttribute="width" constant="80" id="ftJ-Ib-VTX"/> <constraint firstItem="Fpi-20-ZYV" firstAttribute="bottom" secondItem="KC4-sG-yj8" secondAttribute="bottom" id="gTn-Yt-Bxy"/> <constraint firstItem="KC4-sG-yj8" firstAttribute="centerY" secondItem="e5s-ek-YI6" secondAttribute="centerY" id="m5Q-lB-5ev"/> <constraint firstItem="JTE-eF-Y5s" firstAttribute="trailing" secondItem="KC4-sG-yj8" secondAttribute="trailing" id="oQS-k5-5a0"/> - <constraint firstItem="KC4-sG-yj8" firstAttribute="leading" secondItem="e5s-ek-YI6" secondAttribute="leading" constant="20" id="rb1-4c-M1Z"/> + <constraint firstItem="KC4-sG-yj8" firstAttribute="leading" secondItem="e5s-ek-YI6" secondAttribute="leading" constant="15" id="rb1-4c-M1Z"/> </constraints> </view> - <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="LGr-0b-otR"> - <rect key="frame" x="70" y="0.0" width="218" height="76"/> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="seF-bL-Xvj"> + <rect key="frame" x="80" y="0.0" width="278" height="76"/> <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2fJ-Wf-1e0"> - <rect key="frame" x="0.0" y="0.0" width="50" height="18"/> - <fontDescription key="fontDescription" type="boldSystem" pointSize="14"/> - <nil key="textColor"/> - <nil key="highlightedColor"/> - </label> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eug-ak-r49"> - <rect key="frame" x="0.0" y="26" width="50" height="50"/> - <fontDescription key="fontDescription" type="system" pointSize="14"/> - <nil key="textColor"/> - <nil key="highlightedColor"/> - </label> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="top" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="LGr-0b-otR"> + <rect key="frame" x="0.0" y="-14.5" width="238" height="105"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2fJ-Wf-1e0"> + <rect key="frame" x="0.0" y="0.0" width="50" height="50"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="1Lt-95-QFg"> + <rect key="frame" x="0.0" y="55" width="238" height="50"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Yv-cC-LKx"> + <rect key="frame" x="0.0" y="0.0" width="50" height="50"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="13"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eug-ak-r49"> + <rect key="frame" x="50" y="0.0" width="188" height="50"/> + <fontDescription key="fontDescription" type="system" pointSize="13"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <constraints> + <constraint firstItem="eug-ak-r49" firstAttribute="leading" secondItem="7Yv-cC-LKx" secondAttribute="trailing" constant="5" id="pWH-0V-w9u"/> + </constraints> + </stackView> + </subviews> + <constraints> + <constraint firstItem="1Lt-95-QFg" firstAttribute="leading" secondItem="LGr-0b-otR" secondAttribute="leading" id="GfR-Ju-AGa"/> + <constraint firstAttribute="trailing" secondItem="1Lt-95-QFg" secondAttribute="trailing" id="pRn-ni-QiG"/> + </constraints> + </stackView> </subviews> - </stackView> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Yv-cC-LKx"> - <rect key="frame" x="288" y="13" width="50" height="50"/> - <fontDescription key="fontDescription" type="boldSystem" pointSize="12"/> - <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> - <nil key="highlightedColor"/> - </label> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="n6U-lT-A9U"> - <rect key="frame" x="338" y="28" width="20" height="20"/> <constraints> - <constraint firstAttribute="width" constant="20" id="OYg-hn-CG7"/> - <constraint firstAttribute="height" constant="20" id="eWt-bZ-AFF"/> + <constraint firstItem="LGr-0b-otR" firstAttribute="leading" secondItem="seF-bL-Xvj" secondAttribute="leading" id="UVf-fe-O3E"/> + <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="LGr-0b-otR" secondAttribute="trailing" constant="15" id="hb9-G7-3nM"/> + <constraint firstItem="LGr-0b-otR" firstAttribute="centerY" secondItem="seF-bL-Xvj" secondAttribute="centerY" id="tXs-g1-OYR"/> </constraints> </view> </subviews> <constraints> <constraint firstAttribute="bottom" secondItem="e5s-ek-YI6" secondAttribute="bottom" id="3L1-uk-0y8"/> - <constraint firstItem="LGr-0b-otR" firstAttribute="leading" secondItem="e5s-ek-YI6" secondAttribute="trailing" id="JiP-gT-jXu"/> + <constraint firstAttribute="bottom" secondItem="seF-bL-Xvj" secondAttribute="bottom" id="AUl-bd-xJK"/> + <constraint firstItem="seF-bL-Xvj" firstAttribute="leading" secondItem="e5s-ek-YI6" secondAttribute="trailing" id="DMC-jY-dQr"/> + <constraint firstItem="seF-bL-Xvj" firstAttribute="top" secondItem="WA4-h5-JiI" secondAttribute="top" id="LJ8-9F-aLX"/> <constraint firstItem="e5s-ek-YI6" firstAttribute="top" secondItem="WA4-h5-JiI" secondAttribute="top" id="c5k-Xy-Rjw"/> + <constraint firstAttribute="trailing" secondItem="seF-bL-Xvj" secondAttribute="trailing" id="nhD-CZ-7f3"/> </constraints> </stackView> </subviews> diff --git a/Ring/Ring/Features/Conversations/SmartList/IncognitoSmartListViewController.storyboard b/Ring/Ring/Features/Conversations/SmartList/IncognitoSmartListViewController.storyboard index 091068af3ebe91343d24472309548d9a495bc0d0..033411fd6dc00d0944dc2550c0d38c48ac436a76 100644 --- a/Ring/Ring/Features/Conversations/SmartList/IncognitoSmartListViewController.storyboard +++ b/Ring/Ring/Features/Conversations/SmartList/IncognitoSmartListViewController.storyboard @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="VQC-aV-7oi"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="VQC-aV-7oi"> <device id="retina6_1" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> @@ -97,7 +98,7 @@ <subviews> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="MK3-LU-grM"> <rect key="frame" x="0.0" y="0.0" width="414" height="499"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <stackView key="tableFooterView" opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="15" id="j2Q-e4-mDm"> <rect key="frame" x="0.0" y="0.0" width="414" height="44"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> @@ -107,7 +108,7 @@ <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KVW-Ib-pta"> <rect key="frame" x="0.0" y="0.0" width="15" height="44"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> <constraint firstAttribute="width" constant="15" id="Ia9-pu-KkS"/> </constraints> @@ -143,7 +144,7 @@ </button> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="b0i-TS-FoA"> <rect key="frame" x="184.5" y="0.0" width="15" height="44"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> <constraint firstAttribute="width" constant="15" id="tMR-m6-i2R"/> </constraints> @@ -160,7 +161,7 @@ <nil key="highlightedColor"/> </label> </subviews> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> <constraint firstItem="Ub7-pM-ati" firstAttribute="top" secondItem="MK3-LU-grM" secondAttribute="top" id="BZv-Hr-4Rb"/> <constraint firstItem="MK3-LU-grM" firstAttribute="top" secondItem="Yfv-j3-kOe" secondAttribute="top" id="Huf-lP-gNy"/> @@ -168,9 +169,9 @@ <constraint firstAttribute="bottom" secondItem="MK3-LU-grM" secondAttribute="bottom" id="fTV-NI-0xg"/> </constraints> </view> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gvx-Bj-xi3"> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gvx-Bj-xi3"> <rect key="frame" x="0.0" y="791" width="414" height="41"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> <constraint firstAttribute="height" constant="41" id="YSq-hX-dDN"/> </constraints> @@ -178,7 +179,7 @@ </button> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3Uk-bD-yCE"> <rect key="frame" x="0.0" y="832" width="414" height="20"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> <constraint firstAttribute="height" constant="20" id="3Ui-l5-o0o"/> </constraints> @@ -192,6 +193,7 @@ </constraints> </stackView> </subviews> + <viewLayoutGuide key="safeArea" id="Jq5-jG-gOI"/> <constraints> <constraint firstItem="MK3-LU-grM" firstAttribute="leading" secondItem="Jq5-jG-gOI" secondAttribute="leading" id="3kE-pp-Qn5"/> <constraint firstItem="XVO-MU-jo2" firstAttribute="trailing" secondItem="Lsh-nl-RJT" secondAttribute="trailing" id="6sJ-Co-Dgz"/> @@ -200,7 +202,6 @@ <constraint firstItem="Jq5-jG-gOI" firstAttribute="top" secondItem="XVO-MU-jo2" secondAttribute="top" id="uT3-xA-kDy"/> <constraint firstItem="XVO-MU-jo2" firstAttribute="leading" secondItem="Lsh-nl-RJT" secondAttribute="leading" id="y8D-R2-hpu"/> </constraints> - <viewLayoutGuide key="safeArea" id="Jq5-jG-gOI"/> </view> <connections> <outlet property="boothSwitch" destination="gvx-Bj-xi3" id="SSi-NS-vkg"/> @@ -225,9 +226,20 @@ <point key="canvasLocation" x="137.68115942028987" y="91.741071428571431"/> </scene> </scenes> + <designables> + <designable name="5PU-M8-7lD"> + <size key="intrinsicContentSize" width="131" height="29"/> + </designable> + <designable name="Z1C-QN-Ish"> + <size key="intrinsicContentSize" width="132" height="29"/> + </designable> + </designables> <resources> <image name="call_button" width="29" height="29"/> <image name="jamiIcon" width="100" height="95"/> <image name="video_running" width="29" height="29"/> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> </resources> </document> diff --git a/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.storyboard b/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.storyboard index 5498a0efa65fb55243569afaf05b15e15992dae3..6fb52e1b56cf091e66729d2f499d30e39dc3c305 100644 --- a/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.storyboard +++ b/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.storyboard @@ -4,6 +4,7 @@ <dependencies> <deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> + <capability name="Named colors" minToolsVersion="9.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> @@ -20,232 +21,251 @@ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="HFM-G6-hMN"> - <rect key="frame" x="0.0" y="-80" width="375" height="747"/> - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - </tableView> - <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="opE-y7-3Rm"> - <rect key="frame" x="0.0" y="-80" width="375" height="747"/> - <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/> - </tableView> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HGv-QU-VSD"> - <rect key="frame" x="168" y="126" width="39.5" height="19.5"/> - <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/> - <nil key="textColor"/> - <nil key="highlightedColor"/> - </label> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EvL-Bu-O1T"> - <rect key="frame" x="0.0" y="116" width="375" height="551"/> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="fHs-UQ-egN"> + <rect key="frame" x="0.0" y="-45.5" width="375" height="712.5"/> <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No conversations" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8bB-XU-6gh"> - <rect key="frame" x="121" y="265" width="133" height="21"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - <constraints> - <constraint firstItem="8bB-XU-6gh" firstAttribute="centerY" secondItem="EvL-Bu-O1T" secondAttribute="centerY" id="1R2-tE-dtX"/> - <constraint firstItem="8bB-XU-6gh" firstAttribute="centerX" secondItem="EvL-Bu-O1T" secondAttribute="centerX" id="PCa-ph-Sbp"/> - </constraints> - </view> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e5o-cY-djH" userLabel="Network Alert View"> - <rect key="frame" x="0.0" y="60" width="375" height="56"/> - <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HKv-H1-GYI" userLabel="Alert Labels View"> - <rect key="frame" x="171" y="0.0" width="33" height="56"/> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e5o-cY-djH" userLabel="Network Alert View"> + <rect key="frame" x="0.0" y="0.0" width="375" height="56"/> <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fu7-Dr-XvA" userLabel="Network Alert Label"> - <rect key="frame" x="-2" y="10" width="37.5" height="18"/> - <fontDescription key="fontDescription" type="system" pointSize="15"/> - <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - <nil key="highlightedColor"/> - </label> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dHy-gp-i6K" userLabel="Cellular Alert Label"> - <rect key="frame" x="0.0" y="28" width="33" height="16"/> - <fontDescription key="fontDescription" type="system" pointSize="13"/> - <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - <nil key="highlightedColor"/> - </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HKv-H1-GYI" userLabel="Alert Labels View"> + <rect key="frame" x="171" y="0.0" width="33" height="56"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fu7-Dr-XvA" userLabel="Network Alert Label"> + <rect key="frame" x="-2" y="10" width="37.5" height="18"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dHy-gp-i6K" userLabel="Cellular Alert Label"> + <rect key="frame" x="0.0" y="28" width="33" height="16"/> + <fontDescription key="fontDescription" type="system" pointSize="13"/> + <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <constraints> + <constraint firstItem="Fu7-Dr-XvA" firstAttribute="top" secondItem="HKv-H1-GYI" secondAttribute="top" constant="10" id="SAj-hd-YiO"/> + <constraint firstItem="Fu7-Dr-XvA" firstAttribute="centerX" secondItem="HKv-H1-GYI" secondAttribute="centerX" id="apx-hI-eg9"/> + <constraint firstAttribute="height" constant="56" id="j6O-zU-YVL"/> + <constraint firstAttribute="width" secondItem="dHy-gp-i6K" secondAttribute="width" id="mfY-pK-Ush"/> + <constraint firstItem="dHy-gp-i6K" firstAttribute="centerX" secondItem="HKv-H1-GYI" secondAttribute="centerX" id="orq-Lq-Fmo"/> + <constraint firstItem="dHy-gp-i6K" firstAttribute="top" secondItem="Fu7-Dr-XvA" secondAttribute="bottom" id="pOy-bX-Jpj"/> + </constraints> + </view> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iaz-fd-fEz" userLabel="Settings Button"> + <rect key="frame" x="220" y="16" width="24" height="24"/> + <accessibility key="accessibilityConfiguration"> + <accessibilityTraits key="traits" button="YES" image="YES"/> + </accessibility> + <constraints> + <constraint firstAttribute="height" constant="24" id="d6g-Zu-vR7"/> + <constraint firstAttribute="width" constant="24" id="nbF-R8-5kY"/> + </constraints> + <state key="normal" image="settings_icon"/> + </button> </subviews> + <color key="backgroundColor" red="0.94117647058823528" green="0.4392156862745098" blue="0.4392156862745098" alpha="1" colorSpace="calibratedRGB"/> <constraints> - <constraint firstItem="Fu7-Dr-XvA" firstAttribute="top" secondItem="HKv-H1-GYI" secondAttribute="top" constant="10" id="SAj-hd-YiO"/> - <constraint firstItem="Fu7-Dr-XvA" firstAttribute="centerX" secondItem="HKv-H1-GYI" secondAttribute="centerX" id="apx-hI-eg9"/> - <constraint firstAttribute="height" constant="56" id="j6O-zU-YVL"/> - <constraint firstAttribute="width" secondItem="dHy-gp-i6K" secondAttribute="width" id="mfY-pK-Ush"/> - <constraint firstItem="dHy-gp-i6K" firstAttribute="centerX" secondItem="HKv-H1-GYI" secondAttribute="centerX" id="orq-Lq-Fmo"/> - <constraint firstItem="dHy-gp-i6K" firstAttribute="top" secondItem="Fu7-Dr-XvA" secondAttribute="bottom" id="pOy-bX-Jpj"/> + <constraint firstItem="iaz-fd-fEz" firstAttribute="leading" secondItem="HKv-H1-GYI" secondAttribute="trailing" constant="16" id="AFY-4C-aBu"/> + <constraint firstItem="HKv-H1-GYI" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e5o-cY-djH" secondAttribute="leading" constant="10" id="QoG-HF-kux"/> + <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="iaz-fd-fEz" secondAttribute="trailing" constant="10" id="VGV-dn-yaS"/> + <constraint firstItem="HKv-H1-GYI" firstAttribute="centerY" secondItem="e5o-cY-djH" secondAttribute="centerY" id="jtZ-C0-Lms"/> + <constraint firstAttribute="height" constant="56" id="qrO-B9-Qmw"/> + <constraint firstItem="iaz-fd-fEz" firstAttribute="centerY" secondItem="e5o-cY-djH" secondAttribute="centerY" id="xx8-oG-TVU"/> + <constraint firstItem="HKv-H1-GYI" firstAttribute="centerX" secondItem="e5o-cY-djH" secondAttribute="centerX" priority="750" id="yI5-9z-dUv"/> </constraints> </view> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iaz-fd-fEz" userLabel="Settings Button"> - <rect key="frame" x="220" y="16" width="24" height="24"/> - <accessibility key="accessibilityConfiguration"> - <accessibilityTraits key="traits" button="YES" image="YES"/> - </accessibility> - <constraints> - <constraint firstAttribute="height" constant="24" id="d6g-Zu-vR7"/> - <constraint firstAttribute="width" constant="24" id="nbF-R8-5kY"/> - </constraints> - <state key="normal" image="settings_icon"/> - </button> - </subviews> - <color key="backgroundColor" red="0.94117647058823528" green="0.4392156862745098" blue="0.4392156862745098" alpha="1" colorSpace="calibratedRGB"/> - <constraints> - <constraint firstItem="iaz-fd-fEz" firstAttribute="leading" secondItem="HKv-H1-GYI" secondAttribute="trailing" constant="16" id="AFY-4C-aBu"/> - <constraint firstItem="HKv-H1-GYI" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e5o-cY-djH" secondAttribute="leading" constant="10" id="QoG-HF-kux"/> - <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="iaz-fd-fEz" secondAttribute="trailing" constant="10" id="VGV-dn-yaS"/> - <constraint firstItem="HKv-H1-GYI" firstAttribute="centerY" secondItem="e5o-cY-djH" secondAttribute="centerY" id="jtZ-C0-Lms"/> - <constraint firstAttribute="height" constant="56" id="qrO-B9-Qmw"/> - <constraint firstItem="iaz-fd-fEz" firstAttribute="centerY" secondItem="e5o-cY-djH" secondAttribute="centerY" id="xx8-oG-TVU"/> - <constraint firstItem="HKv-H1-GYI" firstAttribute="centerX" secondItem="e5o-cY-djH" secondAttribute="centerX" priority="750" id="yI5-9z-dUv"/> - </constraints> - </view> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DKd-eF-L6f"> - <rect key="frame" x="0.0" y="-106" width="375" height="166"/> - <subviews> - <searchBar contentMode="redraw" placeholder="Enter name..." translatesAutoresizingMaskIntoConstraints="NO" id="xPr-nI-I35"> - <rect key="frame" x="11" y="110" width="314" height="56"/> - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <view alpha="0.90000000000000002" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ESS-lr-aeE"> + <rect key="frame" x="15" y="71" width="345" height="30"/> + <subviews> + <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="VCI-Uk-W6P"> + <rect key="frame" x="0.0" y="0.0" width="345" height="31"/> + <constraints> + <constraint firstAttribute="height" constant="30" id="15y-jg-SBq"/> + </constraints> + <segments> + <segment title="Conversations"/> + <segment title="Requests"/> + </segments> + </segmentedControl> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZhT-xd-SGe"> + <rect key="frame" x="100" y="7.5" width="30" height="15"/> + <color key="backgroundColor" name="row_selected"/> + <constraints> + <constraint firstAttribute="height" constant="15" id="IjU-KN-JjW"/> + </constraints> + <fontDescription key="fontDescription" type="system" pointSize="11"/> + <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/> + </userDefinedRuntimeAttributes> + </button> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7Ze-Hy-M2M"> + <rect key="frame" x="300" y="7.5" width="30" height="15"/> + <color key="backgroundColor" name="row_selected"/> + <constraints> + <constraint firstAttribute="height" constant="15" id="lrx-8A-8cK"/> + </constraints> + <fontDescription key="fontDescription" type="system" pointSize="11"/> + <color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/> + </userDefinedRuntimeAttributes> + </button> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> - <constraint firstAttribute="height" constant="56" id="4yw-AN-guZ"/> + <constraint firstItem="7Ze-Hy-M2M" firstAttribute="centerY" secondItem="ESS-lr-aeE" secondAttribute="centerY" id="2Yo-Ug-5ui"/> + <constraint firstItem="ZhT-xd-SGe" firstAttribute="leading" secondItem="ESS-lr-aeE" secondAttribute="leading" constant="100" id="5VM-pc-lgH"/> + <constraint firstAttribute="bottom" secondItem="VCI-Uk-W6P" secondAttribute="bottom" id="K2J-oQ-QF9"/> + <constraint firstAttribute="trailing" secondItem="7Ze-Hy-M2M" secondAttribute="trailing" constant="15" id="USe-XU-NwW"/> + <constraint firstItem="VCI-Uk-W6P" firstAttribute="top" secondItem="ESS-lr-aeE" secondAttribute="top" id="diC-bw-4ss"/> + <constraint firstItem="ZhT-xd-SGe" firstAttribute="centerY" secondItem="ESS-lr-aeE" secondAttribute="centerY" id="gzI-va-Ime"/> + <constraint firstItem="VCI-Uk-W6P" firstAttribute="leading" secondItem="ESS-lr-aeE" secondAttribute="leading" id="mu8-ki-TZu"/> + <constraint firstAttribute="trailing" secondItem="VCI-Uk-W6P" secondAttribute="trailing" id="qWf-8F-nJK"/> </constraints> - <color key="tintColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> - <offsetWrapper key="searchFieldBackgroundPositionAdjustment" horizontal="0.0" vertical="0.0"/> - <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" returnKeyType="done"/> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> - <real key="value" value="0.0"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> - <color key="value" red="0.92156862745098034" green="0.92156862745098034" blue="0.92156862745098034" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </searchBar> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RSG-bY-flb"> - <rect key="frame" x="325" y="118" width="40" height="40"/> - <color key="tintColor" red="0.2470588235" green="0.42745098040000001" blue="0.65490196079999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <state key="normal" image="phone_book"/> - </button> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Eta-uf-Ija"> - <rect key="frame" x="325" y="118" width="40" height="40"/> + </view> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HGv-QU-VSD"> + <rect key="frame" x="162.5" y="116" width="50" height="20"/> <constraints> - <constraint firstAttribute="width" constant="40" id="eb8-7R-X3e"/> - <constraint firstAttribute="height" constant="40" id="j8h-fg-qMp"/> + <constraint firstAttribute="height" constant="20" id="DDX-Se-AYW"/> </constraints> - <color key="tintColor" red="0.2470588235" green="0.42745098040000001" blue="0.65490196079999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <state key="normal" image="qr_code_scan"/> - </button> - </subviews> - <color key="backgroundColor" red="0.92549019607843142" green="0.92549019607843142" blue="0.92549019607843142" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <constraints> - <constraint firstItem="Eta-uf-Ija" firstAttribute="top" secondItem="RSG-bY-flb" secondAttribute="top" id="C2I-Kv-faQ"/> - <constraint firstItem="Eta-uf-Ija" firstAttribute="centerY" secondItem="xPr-nI-I35" secondAttribute="centerY" id="Epv-9a-Rkg"/> - <constraint firstAttribute="trailing" secondItem="Eta-uf-Ija" secondAttribute="trailing" constant="10" id="O7M-He-7UH"/> - <constraint firstAttribute="height" constant="166" id="P1R-qO-qwd"/> - <constraint firstItem="Eta-uf-Ija" firstAttribute="leading" secondItem="xPr-nI-I35" secondAttribute="trailing" id="SnW-M7-wRB"/> - <constraint firstItem="Eta-uf-Ija" firstAttribute="trailing" secondItem="RSG-bY-flb" secondAttribute="trailing" id="fK5-6j-fKX"/> - <constraint firstItem="Eta-uf-Ija" firstAttribute="leading" secondItem="RSG-bY-flb" secondAttribute="leading" id="ggB-jL-tbn"/> - <constraint firstItem="xPr-nI-I35" firstAttribute="leading" secondItem="DKd-eF-L6f" secondAttribute="leading" constant="11" id="m1O-ZV-Pkx"/> - <constraint firstItem="Eta-uf-Ija" firstAttribute="bottom" secondItem="RSG-bY-flb" secondAttribute="bottom" id="wOa-Ne-n5e"/> - <constraint firstAttribute="bottom" secondItem="xPr-nI-I35" secondAttribute="bottom" id="xcp-FC-G0l"/> - </constraints> - </view> - <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="79Q-fh-vhV"> - <rect key="frame" x="285" y="577" width="60" height="60"/> - <subviews> - <button opaque="NO" contentMode="scaleToFill" selected="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k8G-Me-4BI"> - <rect key="frame" x="0.0" y="0.0" width="60" height="60"/> + <fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gqr-2R-GbC"> + <rect key="frame" x="0.0" y="151" width="375" height="561.5"/> + <subviews> + <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="HFM-G6-hMN"> + <rect key="frame" x="0.0" y="0.0" width="375" height="561.5"/> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </tableView> + <tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="opE-y7-3Rm"> + <rect key="frame" x="0.0" y="0.0" width="375" height="561.5"/> + <color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/> + </tableView> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EvL-Bu-O1T"> + <rect key="frame" x="0.0" y="0.0" width="375" height="561.5"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No conversations" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8bB-XU-6gh"> + <rect key="frame" x="121.5" y="270.5" width="132.5" height="20.5"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <constraints> + <constraint firstItem="8bB-XU-6gh" firstAttribute="centerY" secondItem="EvL-Bu-O1T" secondAttribute="centerY" id="1R2-tE-dtX"/> + <constraint firstItem="8bB-XU-6gh" firstAttribute="centerX" secondItem="EvL-Bu-O1T" secondAttribute="centerX" id="PCa-ph-Sbp"/> + </constraints> + </view> + <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="79Q-fh-vhV"> + <rect key="frame" x="265" y="451.5" width="60" height="60"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" selected="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="k8G-Me-4BI"> + <rect key="frame" x="0.0" y="0.0" width="60" height="60"/> + <constraints> + <constraint firstAttribute="width" constant="60" id="Dq9-B0-nTC"/> + <constraint firstAttribute="height" constant="60" id="LCB-X4-TOf"/> + </constraints> + <color key="tintColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <size key="titleShadowOffset" width="-3" height="-3"/> + <state key="normal" image="dialpad"/> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> + <real key="value" value="30"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> + <real key="value" value="0.0"/> + </userDefinedRuntimeAttribute> + <userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/> + <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> + <color key="value" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="0.3690336044520548" colorSpace="calibratedRGB"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </button> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstAttribute="height" constant="60" id="GEI-dw-9ar"/> + <constraint firstAttribute="trailing" secondItem="k8G-Me-4BI" secondAttribute="trailing" id="a7d-Q1-Fvz"/> + <constraint firstAttribute="bottom" secondItem="k8G-Me-4BI" secondAttribute="bottom" id="bnM-1C-SSP"/> + <constraint firstItem="k8G-Me-4BI" firstAttribute="top" secondItem="79Q-fh-vhV" secondAttribute="top" id="g5a-Yt-05m"/> + <constraint firstAttribute="width" constant="60" id="hKy-2O-rN9"/> + <constraint firstItem="k8G-Me-4BI" firstAttribute="leading" secondItem="79Q-fh-vhV" secondAttribute="leading" id="pqh-Ky-LOJ"/> + </constraints> + <userDefinedRuntimeAttributes> + <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> + <real key="value" value="30"/> + </userDefinedRuntimeAttribute> + </userDefinedRuntimeAttributes> + </view> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> - <constraint firstAttribute="width" constant="60" id="Dq9-B0-nTC"/> - <constraint firstAttribute="height" constant="60" id="LCB-X4-TOf"/> + <constraint firstAttribute="trailing" secondItem="79Q-fh-vhV" secondAttribute="trailing" constant="50" id="3Cj-Ah-pWk"/> + <constraint firstAttribute="bottom" secondItem="HFM-G6-hMN" secondAttribute="bottom" id="Eig-nJ-OPf"/> + <constraint firstItem="EvL-Bu-O1T" firstAttribute="top" secondItem="HFM-G6-hMN" secondAttribute="top" id="HwS-th-5Du"/> + <constraint firstItem="EvL-Bu-O1T" firstAttribute="bottom" secondItem="HFM-G6-hMN" secondAttribute="bottom" id="Krm-YJ-Rps"/> + <constraint firstItem="opE-y7-3Rm" firstAttribute="bottom" secondItem="HFM-G6-hMN" secondAttribute="bottom" id="LnD-vv-oHS"/> + <constraint firstItem="HFM-G6-hMN" firstAttribute="leading" secondItem="gqr-2R-GbC" secondAttribute="leading" id="MUp-ck-FM6"/> + <constraint firstAttribute="trailing" secondItem="HFM-G6-hMN" secondAttribute="trailing" id="OgG-BG-rlJ"/> + <constraint firstAttribute="trailing" secondItem="EvL-Bu-O1T" secondAttribute="trailing" id="RhB-ix-Yzq"/> + <constraint firstItem="opE-y7-3Rm" firstAttribute="top" secondItem="HFM-G6-hMN" secondAttribute="top" id="Wvh-pw-hpY"/> + <constraint firstAttribute="bottom" secondItem="79Q-fh-vhV" secondAttribute="bottom" constant="50" id="gTN-u6-c4o"/> + <constraint firstItem="opE-y7-3Rm" firstAttribute="leading" secondItem="gqr-2R-GbC" secondAttribute="leading" id="jRB-q6-Xnc"/> + <constraint firstItem="HFM-G6-hMN" firstAttribute="top" secondItem="gqr-2R-GbC" secondAttribute="top" id="m5h-zl-Bru"/> + <constraint firstAttribute="trailing" secondItem="opE-y7-3Rm" secondAttribute="trailing" id="mZU-FB-mYU"/> + <constraint firstItem="EvL-Bu-O1T" firstAttribute="leading" secondItem="gqr-2R-GbC" secondAttribute="leading" id="tCT-EK-NAi"/> </constraints> - <color key="tintColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> - <size key="titleShadowOffset" width="-3" height="-3"/> - <state key="normal" image="dialpad"/> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> - <real key="value" value="30"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="number" keyPath="borderWidth"> - <real key="value" value="0.0"/> - </userDefinedRuntimeAttribute> - <userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/> - <userDefinedRuntimeAttribute type="color" keyPath="borderColor"> - <color key="value" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="0.3690336044520548" colorSpace="calibratedRGB"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </button> + </view> </subviews> - <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> - <constraint firstAttribute="height" constant="60" id="GEI-dw-9ar"/> - <constraint firstAttribute="trailing" secondItem="k8G-Me-4BI" secondAttribute="trailing" id="a7d-Q1-Fvz"/> - <constraint firstAttribute="bottom" secondItem="k8G-Me-4BI" secondAttribute="bottom" id="bnM-1C-SSP"/> - <constraint firstItem="k8G-Me-4BI" firstAttribute="top" secondItem="79Q-fh-vhV" secondAttribute="top" id="g5a-Yt-05m"/> - <constraint firstAttribute="width" constant="60" id="hKy-2O-rN9"/> - <constraint firstItem="k8G-Me-4BI" firstAttribute="leading" secondItem="79Q-fh-vhV" secondAttribute="leading" id="pqh-Ky-LOJ"/> + <constraint firstItem="HFM-G6-hMN" firstAttribute="leading" secondItem="ESS-lr-aeE" secondAttribute="leading" constant="-15" id="Voi-fF-kql"/> + <constraint firstItem="gqr-2R-GbC" firstAttribute="leading" secondItem="fHs-UQ-egN" secondAttribute="leading" id="XrR-qX-a55"/> + <constraint firstAttribute="bottom" secondItem="gqr-2R-GbC" secondAttribute="bottom" id="aiq-Bo-nds"/> + <constraint firstItem="HFM-G6-hMN" firstAttribute="trailing" secondItem="ESS-lr-aeE" secondAttribute="trailing" constant="15" id="dDg-sf-Ssc"/> + <constraint firstItem="ESS-lr-aeE" firstAttribute="centerX" secondItem="fHs-UQ-egN" secondAttribute="centerX" id="klM-7A-Isg"/> + <constraint firstAttribute="trailing" secondItem="gqr-2R-GbC" secondAttribute="trailing" id="w3Y-e4-ril"/> </constraints> - <userDefinedRuntimeAttributes> - <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> - <real key="value" value="30"/> - </userDefinedRuntimeAttribute> - </userDefinedRuntimeAttributes> - </view> + </stackView> </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> - <constraint firstItem="opE-y7-3Rm" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="0cn-0y-g9L"/> - <constraint firstItem="EvL-Bu-O1T" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="2Cw-xT-xCg"/> - <constraint firstAttribute="trailing" secondItem="HFM-G6-hMN" secondAttribute="trailing" id="7H1-ka-2Ti"/> - <constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="79Q-fh-vhV" secondAttribute="bottom" constant="30" id="8G6-0D-3ma"/> - <constraint firstItem="HFM-G6-hMN" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="8tr-Rd-1kr"/> - <constraint firstItem="DKd-eF-L6f" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="9fi-2r-wE8"/> - <constraint firstItem="HGv-QU-VSD" firstAttribute="centerX" secondItem="2dZ-8A-4nq" secondAttribute="centerX" id="A6i-gd-82k"/> - <constraint firstAttribute="trailing" secondItem="DKd-eF-L6f" secondAttribute="trailing" id="AhH-s9-pfe"/> - <constraint firstAttribute="trailing" secondItem="opE-y7-3Rm" secondAttribute="trailing" id="D0f-nM-KEs"/> - <constraint firstItem="HFM-G6-hMN" firstAttribute="top" secondItem="sbJ-yn-t3e" secondAttribute="bottom" constant="-80" id="TVk-tz-qtF"/> - <constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="EvL-Bu-O1T" secondAttribute="bottom" id="TsM-9H-eI1"/> - <constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="HFM-G6-hMN" secondAttribute="bottom" id="VfB-5H-uHq"/> - <constraint firstItem="HGv-QU-VSD" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" constant="10" id="XCA-fc-GKd"/> - <constraint firstItem="EvL-Bu-O1T" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="cCR-S3-3AW"/> - <constraint firstAttribute="trailing" secondItem="79Q-fh-vhV" secondAttribute="trailing" constant="30" id="elh-uT-3vG"/> - <constraint firstItem="DKd-eF-L6f" firstAttribute="top" secondItem="sbJ-yn-t3e" secondAttribute="bottom" constant="-106" id="gbl-PR-kL4"/> - <constraint firstAttribute="trailing" secondItem="e5o-cY-djH" secondAttribute="trailing" id="k9v-18-oxL"/> - <constraint firstItem="HFM-G6-hMN" firstAttribute="top" secondItem="opE-y7-3Rm" secondAttribute="top" id="kok-5h-ENq"/> - <constraint firstItem="e5o-cY-djH" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="mKv-lK-yDx"/> - <constraint firstAttribute="trailing" secondItem="EvL-Bu-O1T" secondAttribute="trailing" id="nSK-QH-snj"/> - <constraint firstItem="e5o-cY-djH" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="rXu-fF-ESz"/> - <constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="opE-y7-3Rm" secondAttribute="bottom" id="wun-hC-1JP"/> + <constraint firstAttribute="trailing" secondItem="fHs-UQ-egN" secondAttribute="trailing" id="IIq-iZ-FZu"/> + <constraint firstItem="fHs-UQ-egN" firstAttribute="top" secondItem="2dZ-8A-4nq" secondAttribute="top" priority="250" id="YbK-2c-8Eo"/> + <constraint firstItem="fHs-UQ-egN" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="j1V-Rc-WhK"/> + <constraint firstAttribute="bottom" secondItem="fHs-UQ-egN" secondAttribute="bottom" id="nI3-hX-UQv"/> </constraints> </view> - <extendedEdge key="edgesForExtendedLayout" bottom="YES"/> + <extendedEdge key="edgesForExtendedLayout" top="YES"/> <navigationItem key="navigationItem" id="zLl-0A-Dht"/> <connections> <outlet property="cellularAlertLabel" destination="dHy-gp-i6K" id="W9w-Mi-GTY"/> + <outlet property="containerView" destination="gqr-2R-GbC" id="xq5-ND-VjP"/> + <outlet property="conversationBadge" destination="ZhT-xd-SGe" id="bIA-to-RWj"/> + <outlet property="conversationBadgeLeadingConstraint" destination="5VM-pc-lgH" id="pin-4I-Rlk"/> + <outlet property="conversationsSegmentControl" destination="VCI-Uk-W6P" id="tKl-bm-ywS"/> <outlet property="conversationsTableView" destination="HFM-G6-hMN" id="M97-IB-NUZ"/> <outlet property="dialpadButton" destination="k8G-Me-4BI" id="Ij7-SF-nvZ"/> <outlet property="dialpadButtonShadow" destination="79Q-fh-vhV" id="VcA-wc-j6h"/> <outlet property="networkAlertLabel" destination="Fu7-Dr-XvA" id="0qV-lk-9mE"/> <outlet property="networkAlertView" destination="e5o-cY-djH" id="uV5-WT-vai"/> - <outlet property="networkAlertViewTopConstraint" destination="mKv-lK-yDx" id="bJk-Ie-hf6"/> <outlet property="noConversationLabel" destination="8bB-XU-6gh" id="n4g-mz-w7z"/> <outlet property="noConversationsView" destination="EvL-Bu-O1T" id="tVV-6a-4Xg"/> - <outlet property="phoneBookButton" destination="RSG-bY-flb" id="Yjw-Va-7c1"/> - <outlet property="qrScanButton" destination="Eta-uf-Ija" id="Hh0-vy-8EK"/> - <outlet property="scanButtonLeadingConstraint" destination="O7M-He-7UH" id="cvF-Wd-TJT"/> - <outlet property="searchBarShadow" destination="DKd-eF-L6f" id="CKZ-ws-ag1"/> - <outlet property="searchFieldTrailing" destination="AhH-s9-pfe" id="rhp-oZ-ZJo"/> + <outlet property="requestBadgeTrailingConstraint" destination="USe-XU-NwW" id="iRW-Ph-bPH"/> + <outlet property="requestsBadge" destination="7Ze-Hy-M2M" id="Re6-ef-Q8h"/> <outlet property="searchView" destination="Y4B-5f-ij4" id="FtS-9R-atZ"/> + <outlet property="segmentControlContainer" destination="ESS-lr-aeE" id="OlG-so-HqR"/> <outlet property="settingsButton" destination="iaz-fd-fEz" id="R2O-R8-BDk"/> - <outlet property="tableTopConstraint" destination="TVk-tz-qtF" id="lIj-Yu-ZL7"/> - <outlet property="tableView" destination="HFM-G6-hMN" id="Gci-vk-ijr"/> + <outlet property="viewContainer" destination="fHs-UQ-egN" id="lcd-Nd-7pC"/> </connections> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="JSt-CJ-9Vq" userLabel="First Responder" sceneMemberID="firstResponder"/> <customObject id="Y4B-5f-ij4" customClass="JamiSearchView" customModule="Ring" customModuleProvider="target"> <connections> - <outlet property="searchBar" destination="xPr-nI-I35" id="M1f-Qz-kHV"/> <outlet property="searchResultsTableView" destination="opE-y7-3Rm" id="cMo-3b-5FA"/> <outlet property="searchingLabel" destination="HGv-QU-VSD" id="WnL-0s-Szs"/> </connections> @@ -256,9 +276,10 @@ </scenes> <resources> <image name="dialpad" width="37.5" height="37.5"/> - <image name="phone_book" width="37.5" height="37.5"/> - <image name="qr_code_scan" width="32" height="32"/> <image name="settings_icon" width="24" height="24"/> + <namedColor name="row_selected"> + <color red="0.81960784313725488" green="0.82352941176470584" blue="0.82352941176470584" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </namedColor> <systemColor name="groupTableViewBackgroundColor"> <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> </systemColor> diff --git a/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.swift b/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.swift index 15c20c0924bb2c04056e34df5459977bc87d0fdd..cb6f46ceceb4bf21fd05b872a1b00715807a1baf 100644 --- a/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.swift +++ b/Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.swift @@ -31,9 +31,8 @@ import QuartzCore //Constants struct SmartlistConstants { - static let smartlistRowHeight: CGFloat = 64.0 - static let tableHeaderViewHeight: CGFloat = 142.0 - static let firstSectionHeightForHeader: CGFloat = 51.0 + static let smartlistRowHeight: CGFloat = 70.0 + static let tableHeaderViewHeight: CGFloat = 30.0 static let networkAllerHeight: CGFloat = 56.0 static let tableViewOffset: CGFloat = 80.0 @@ -45,22 +44,24 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased private let log = SwiftyBeaver.self // MARK: outlets - @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var viewContainer: UIView! @IBOutlet weak var conversationsTableView: UITableView! + @IBOutlet weak var conversationsSegmentControl: UISegmentedControl! + @IBOutlet weak var segmentControlContainer: UIView! + @IBOutlet weak var conversationBadge: UIButton! + @IBOutlet weak var requestsBadge: UIButton! + @IBOutlet weak var conversationBadgeLeadingConstraint: NSLayoutConstraint! + @IBOutlet weak var requestBadgeTrailingConstraint: NSLayoutConstraint! + + @IBOutlet weak var containerView: UIView! @IBOutlet weak var noConversationsView: UIView! @IBOutlet weak var noConversationLabel: UILabel! @IBOutlet weak var networkAlertLabel: UILabel! @IBOutlet weak var cellularAlertLabel: UILabel! @IBOutlet weak var networkAlertViewTopConstraint: NSLayoutConstraint! - @IBOutlet weak var tableTopConstraint: NSLayoutConstraint! @IBOutlet weak var settingsButton: UIButton! @IBOutlet weak var dialpadButton: UIButton! @IBOutlet weak var dialpadButtonShadow: UIView! - @IBOutlet weak var searchBarShadow: UIView! - @IBOutlet weak var qrScanButton: UIButton! - @IBOutlet weak var phoneBookButton: UIButton! - @IBOutlet weak var scanButtonLeadingConstraint: NSLayoutConstraint! - @IBOutlet weak var searchFieldTrailing: NSLayoutConstraint! @IBOutlet weak var networkAlertView: UIView! @IBOutlet weak var searchView: JamiSearchView! @@ -77,6 +78,9 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased let margin: CGFloat = 10 let size: CGFloat = 32 let triangleViewSize: CGFloat = 12 + var menu = UIView() + + var contactRequestVC: ContactRequestsViewController? // MARK: members var viewModel: SmartlistViewModel! @@ -91,10 +95,8 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased override func viewDidLoad() { super.viewDidLoad() - searchView.configure(with: viewModel.injectionBag, source: viewModel, isIncognito: false) self.setupDataSources() self.setupTableView() - self.setupSearchBar() self.setupUI() self.applyL10n() self.configureRingNavigationBar() @@ -107,43 +109,125 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased */ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(withNotification:)), name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(withNotification:)), name: UIResponder.keyboardWillHideNotification, object: nil) - self.tabBarController?.tabBar.isHidden = false - self.tabBarController?.tabBar.layer.zPosition = -0 - self.extendedLayoutIncludesOpaqueBars = true - NotificationCenter.default.rx - .notification(UIDevice.orientationDidChangeNotification) - .observeOn(MainScheduler.instance) - .subscribe(onNext: {[weak self](_) in + self.setupSearchBar() + searchView.configure(with: viewModel.injectionBag, source: viewModel, isIncognito: false) + self.setUpContactRequest() + conversationsSegmentControl.addTarget(self, action: #selector(segmentAction), for: .valueChanged) + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + // Waiting for screen size change + DispatchQueue.global(qos: .background).async { + sleep(UInt32(0.5)) + DispatchQueue.main.async { [weak self] in guard let self = self, UIDevice.current.portraitOrLandscape else { return } self.updateAccountItemSize() - }) - .disposed(by: self.disposeBag) + let messages: Int = Int(self.conversationBadge.title(for: .normal) ?? "0") ?? 0 + let requests: Int = Int(self.requestsBadge.title(for: .normal) ?? "0") ?? 0 + self.setUpSegmemtControl(messages: messages, requests: requests) + if self.menu.superview != nil { + self.showContextualMenu() + } + if #available(iOS 13.0, *) { + } else { + self.navigationController?.setNavigationBarHidden(false, animated: false) + } + self.searchController.sizeChanged(to: size.width) + } + } + super.viewWillTransition(to: size, with: coordinator) + } + @objc + func segmentAction(_ segmentedControl: UISegmentedControl) { + switch segmentedControl.selectedSegmentIndex { + case 0: + contactRequestVC?.view.isHidden = true + searchView.showSearchResult = true + case 1: + contactRequestVC?.view.isHidden = false + searchView.showSearchResult = false + default: + break + } + } + + func addContactRequestVC(controller: ContactRequestsViewController) { + contactRequestVC = controller + } + + func setUpContactRequest() { + guard let controller = contactRequestVC else { return } + addChild(controller) + + //make sure that the child view controller's view is the right size + controller.view.frame = containerView.bounds + containerView.addSubview(controller.view) + + //you must call this at the end per Apple's documentation + controller.didMove(toParent: self) + controller.view.isHidden = true + self.searchView.searchBar.rx.text.orEmpty + .debounce(Durations.textFieldThrottlingDuration.toTimeInterval(), scheduler: MainScheduler.instance) + .bind(to: (self.contactRequestVC?.viewModel.filter)!) + .disposed(by: disposeBag) } @objc func dismissKeyboard() { + menu.removeFromSuperview() accountPickerTextView.resignFirstResponder() view.removeGestureRecognizer(accountsDismissTapRecognizer) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - navigationController? - .navigationBar - .layer.shadowColor = UIColor.clear.cgColor - navigationController? - .navigationBar - .setBackgroundImage(UIImage(), - for: UIBarMetrics.default) + if #available(iOS 13.0, *) { + self.navigationController?.navigationBar.layer.shadowColor = UIColor.jamiNavigationBarShadow.cgColor + } else { + self.navigationController?.navigationBar.layer.shadowColor = UIColor.clear.cgColor + } self.navigationController?.navigationBar .titleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "HelveticaNeue-Light", size: 25)!, NSAttributedString.Key.foregroundColor: UIColor.jamiMain] self.viewModel.closeAllPlayers() - self.tabBarController?.tabBar.isHidden = false - self.tabBarController?.tabBar.layer.zPosition = -0 - self.navigationController?.setNavigationBarHidden(false, animated: animated) + } + + override func viewDidAppear(_ animated: Bool) { + if #available(iOS 13.0, *) { + } else { + self.searchController.hideButton(hide: false) + } + self.searchController.sizeChanged(to: self.view.frame.size.width) + super.viewDidAppear(animated) + viewContainer.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15).isActive = true + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.navigationController?.setNavigationBarHidden(false, animated: false) + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + if #available(iOS 13.0, *) { + } else { + self.searchController.hideButton(hide: true) + } + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + self.navigationController?.setNavigationBarHidden(false, animated: false) + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + if scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating { + if scrollView.panGestureRecognizer.translation(in: scrollView.superview).y > 0 { + self.navigationController?.setNavigationBarHidden(false, animated: true) + } else { + self.navigationController?.setNavigationBarHidden(true, animated: true) + } + } } func applyL10n() { @@ -152,8 +236,67 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased self.cellularAlertLabel.text = L10n.Smartlist.cellularAccess } + func setUpSegmemtControl(messages: Int, requests: Int) { + if requests == 0 { + segmentControlContainer.isHidden = true + conversationBadge.setTitle(String(messages), for: .normal) + requestsBadge.setTitle(String(requests), for: .normal) + return + } + segmentControlContainer.isHidden = false + let unreadMessages = messages + let unreadRequests = requests + let margin: CGFloat = 5 + + self.conversationBadge.isHidden = unreadMessages == 0 + self.requestsBadge.isHidden = unreadRequests == 0 + let titleFont = UIFont.systemFont(ofSize: 12, weight: .medium) + let attributes = [NSAttributedString.Key.font: titleFont] + let conversationTitle = L10n.Smartlist.conversations + let requestsTitle = L10n.Smartlist.invitations + conversationsSegmentControl.setTitleTextAttributes(attributes, for: .normal) + conversationsSegmentControl.setTitle(conversationTitle, forSegmentAt: 0) + conversationsSegmentControl.setTitle(requestsTitle, forSegmentAt: 1) + conversationBadge.setTitle(String(unreadMessages), for: .normal) + requestsBadge.setTitle(String(unreadRequests), for: .normal) + self.conversationBadge.sizeToFit() + self.requestsBadge.sizeToFit() + self.conversationBadge.setNeedsDisplay() + self.requestsBadge.setNeedsDisplay() + + let convBageWidth = unreadMessages == 0 ? 0 : conversationBadge.frame.width + let requestBageWidth = unreadRequests == 0 ? 0 : requestsBadge.frame.size.width + let widthConversation = conversationTitle.size(withAttributes: attributes).width + let widthRequests = requestsTitle.size(withAttributes: attributes).width + + let segmentWidth = conversationsSegmentControl.frame.size.width * 0.5 + let convContentWidth = convBageWidth + widthConversation + margin + let reqContentWidth = requestBageWidth + widthRequests + margin + conversationsSegmentControl.setContentOffset(CGSize(width: -(convBageWidth + margin) * 0.5, height: 0), forSegmentAt: 0) + conversationsSegmentControl.setContentOffset(CGSize(width: -(requestBageWidth + margin) * 0.5, height: 0), forSegmentAt: 1) + let conversationConstraint = (segmentWidth - convContentWidth) * 0.5 + widthConversation + margin + self.conversationBadgeLeadingConstraint.constant = conversationConstraint + let requestConstraint = (segmentWidth - reqContentWidth) * 0.5 + self.requestBadgeTrailingConstraint.constant = requestConstraint + } + // swiftlint:disable function_body_length func setupUI() { + conversationBadge.contentEdgeInsets = UIEdgeInsets(top: 1, left: 5, bottom: 1, right: 5) + requestsBadge.contentEdgeInsets = UIEdgeInsets(top: 1, left: 5, bottom: 2, right: 5) + if #available(iOS 13.0, *) { + conversationBadge.backgroundColor = UIColor.tertiaryLabel + requestsBadge.backgroundColor = UIColor.tertiaryLabel + } else { + conversationBadge.backgroundColor = UIColor.gray.lighten(by: 20) + requestsBadge.backgroundColor = UIColor.gray.lighten(by: 20) + conversationsSegmentControl.tintColor = UIColor.gray.lighten(by: 10) + } + self.viewModel.updateSegmentControl.subscribe { [weak self] (messages, requests) in + self?.setUpSegmemtControl(messages: messages, requests: requests) + } + .disposed(by: self.disposeBag) + view.backgroundColor = UIColor.jamiBackgroundColor conversationsTableView.backgroundColor = UIColor.jamiBackgroundColor noConversationsView.backgroundColor = UIColor.jamiBackgroundColor @@ -169,19 +312,10 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased .bind(to: self.noConversationsView.rx.isHidden) .disposed(by: disposeBag) let isHidden = self.viewModel.networkConnectionState() == .none ? false : true - self.networkAlertViewTopConstraint.constant = !isHidden ? 0.0 : -SmartlistConstants.networkAllerHeight - tableTopConstraint.constant = !isHidden ? -(SmartlistConstants.tableViewOffset - SmartlistConstants.networkAllerHeight) : -SmartlistConstants.tableViewOffset self.networkAlertView.isHidden = isHidden self.viewModel.connectionState .subscribe(onNext: { [weak self] connectionState in - let newAlertHeight = connectionState == .none ? 0.0 : -SmartlistConstants.networkAllerHeight - let newTableViewTop = connectionState == .none ? -(SmartlistConstants.tableViewOffset - SmartlistConstants.networkAllerHeight) : -SmartlistConstants.tableViewOffset let isHidden = connectionState == .none ? false : true - UIView.animate(withDuration: 0.25) { [weak self] in - self?.networkAlertViewTopConstraint.constant = CGFloat(newAlertHeight) - self?.tableTopConstraint.constant = CGFloat(newTableViewTop) - self?.view.layoutIfNeeded() - } self?.networkAlertView.isHidden = isHidden }) .disposed(by: self.disposeBag) @@ -195,27 +329,18 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased }) .disposed(by: self.disposeBag) - let imageSettings = UIImage(asset: Asset.settings) as UIImage? + let imageSettings = UIImage(asset: Asset.moreSettings) as UIImage? let generalSettingsButton = UIButton(type: UIButton.ButtonType.system) as UIButton + generalSettingsButton.frame = CGRect(x: 0, y: 0, width: 25, height: 25) + generalSettingsButton.borderWidth = 2 + generalSettingsButton.borderColor = UIColor.jamiMain generalSettingsButton.setImage(imageSettings, for: .normal) generalSettingsButton.contentMode = .scaleAspectFill let settingsButtonItem = UIBarButtonItem(customView: generalSettingsButton) + generalSettingsButton.cornerRadius = 12.5 generalSettingsButton.rx.tap.throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) .subscribe(onNext: { [weak self] in - self?.viewModel.showGeneralSettings() - }) - .disposed(by: self.disposeBag) - qrScanButton.rx.tap.throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) - .subscribe(onNext: { [weak self] in - self?.openScan() - }) - .disposed(by: self.disposeBag) - - phoneBookButton.rx.tap.throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) - .subscribe(onNext: { [weak self] in - guard let self = self else { return } - self.contactPicker.delegate = self - self.present(self.contactPicker, animated: true, completion: nil) + self?.showContextualMenu() }) .disposed(by: self.disposeBag) self.viewModel.currentAccountChanged @@ -223,27 +348,13 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased .subscribe(onNext: { [weak self] currentAccount in if let account = currentAccount { let accountSip = account.type == AccountType.sip - self?.navigationItem - .rightBarButtonItem = accountSip ? nil : settingsButtonItem self?.dialpadButtonShadow.isHidden = !accountSip - self?.phoneBookButton.isHidden = !accountSip - self?.qrScanButton.isHidden = accountSip + self?.updateSearchBar() } }) .disposed(by: disposeBag) self.navigationItem.rightBarButtonItem = settingsButtonItem - if let account = self.viewModel.currentAccount { - if account.type == AccountType.sip { - self.navigationItem.rightBarButtonItem = nil - self.qrScanButton.isHidden = true - self.phoneBookButton.isHidden = false - } else { - self.qrScanButton.isHidden = false - self.phoneBookButton.isHidden = true - } - } - //create accounts button let accountButton = UIButton(type: .custom) self.viewModel.profileImage.bind(to: accountButton.rx.image(for: .normal)) @@ -252,7 +363,7 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased accountButton.clipsToBounds = true accountButton.contentMode = .scaleAspectFill accountButton.cornerRadius = size * 0.5 - accountButton.frame = CGRect(x: 6, y: 0, width: size, height: size) + accountButton.frame = CGRect(x: 0, y: 0, width: size, height: size) accountButton.imageEdgeInsets = UIEdgeInsets(top: -4, left: -4, bottom: -4, right: -4) let screenRect = UIScreen.main.bounds let screenWidth = screenRect.size.width @@ -327,12 +438,161 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased self.conversationsTableView.tableFooterView = UIView() } - func updateAccountItemSize() { + func showContextualMenu() { + self.menu.removeFromSuperview() + self.view.addGestureRecognizer(accountsDismissTapRecognizer) + guard let frame = self.navigationController?.navigationBar.frame else { return } + let originY = frame.size.height + let originX = frame.size.width - 120 + let marginX: CGFloat = 20 + let marginY: CGFloat = 15 + let itemHeight: CGFloat = 25 + menu = UIView(frame: CGRect(x: originX, y: originY, width: 100, height: 155)) + menu.roundedCorners = true + menu.cornerRadius = 15 + // labels + let accountSettings = UILabel(frame: CGRect(x: marginX, y: 0, width: 100, height: itemHeight)) + accountSettings.font = UIFont.systemFont(ofSize: 18, weight: .regular) + accountSettings.text = L10n.Smartlist.accountSettings + accountSettings.sizeToFit() + let advancedSettings = UILabel(frame: CGRect(x: marginX, y: 0, width: 100, height: itemHeight)) + advancedSettings.font = UIFont.systemFont(ofSize: 18, weight: .regular) + advancedSettings.text = L10n.Smartlist.advancedSettings + advancedSettings.sizeToFit() + let about = UILabel(frame: CGRect(x: marginX, y: 0, width: 100, height: itemHeight)) + about.text = L10n.Smartlist.aboutJami + about.font = UIFont.systemFont(ofSize: 18, weight: .regular) + about.sizeToFit() + // calculate menu size to fit labels text + let maxWidth = max(max(accountSettings.frame.size.width, advancedSettings.frame.size.width), about.frame.size.width) + let viewWidth = maxWidth + marginX * 3 + 25 + let buttonOrigin = maxWidth + marginX * 2 + + let accountSettingsView = UIView.init(frame: CGRect(x: 0, y: marginY, width: viewWidth, height: itemHeight)) + let accountImage = UIImageView.init(frame: CGRect(x: buttonOrigin + 2, y: 2, width: 20, height: 20)) + accountImage.tintColor = UIColor.jamiMain + accountImage.image = UIImage(asset: Asset.fallbackAvatar) + accountImage.borderWidth = 1 + accountImage.borderColor = UIColor.jamiMain + accountImage.cornerRadius = 10 + accountSettingsView.addSubview(accountSettings) + accountSettingsView.addSubview(accountImage) + let accountSettingsButton = UIButton(type: .custom) + accountSettingsButton.frame = accountSettingsView.bounds + accountSettingsButton.rx.tap + .throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) + .subscribe(onNext: { [weak self] in + self?.menu.removeFromSuperview() + self?.viewModel.showAccountSettings() + }) + .disposed(by: self.disposeBag) + accountSettingsView.addSubview(accountSettingsButton) + + let advancedSettingsView = UIView.init(frame: CGRect(x: 0, y: marginY + itemHeight * 2, width: viewWidth, height: itemHeight)) + let advancedImage = UIImageView.init(frame: CGRect(x: buttonOrigin, y: 0, width: 25, height: 25)) + advancedImage.tintColor = UIColor.jamiMain + advancedImage.image = UIImage(asset: Asset.settings) + advancedSettingsView.addSubview(advancedSettings) + advancedSettingsView.addSubview(advancedImage) + let advancedSettingsButton = UIButton(type: .custom) + advancedSettingsButton.frame = advancedSettingsView.bounds + advancedSettingsButton.rx.tap + .throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) + .subscribe(onNext: { [weak self] in + self?.menu.removeFromSuperview() + self?.viewModel.showGeneralSettings() + }) + .disposed(by: self.disposeBag) + advancedSettingsView.addSubview(advancedSettingsButton) + + let aboutView = UIView.init(frame: CGRect(x: 0, y: marginY + itemHeight * 4, width: viewWidth, height: itemHeight)) + let aboutImage = UIImageView.init(frame: CGRect(x: buttonOrigin + 2, y: 2, width: 20, height: 20)) + aboutImage.image = UIImage(asset: Asset.jamiIcon) + aboutView.addSubview(about) + aboutView.addSubview(aboutImage) + let aboutButton = UIButton(type: .custom) + aboutButton.frame = aboutView.bounds + aboutButton.rx.tap + .throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) + .subscribe(onNext: { [weak self] in + self?.infoItemTapped() + self?.menu.removeFromSuperview() + }) + .disposed(by: self.disposeBag) + aboutView.addSubview(aboutButton) + + // update menu frame + menu.frame.size.width = viewWidth + let orientation = UIDevice.current.orientation + let rightMargin: CGFloat = UIDevice.current.hasNotch && (orientation == .landscapeRight || orientation == .landscapeLeft) ? 40 : 10 + menu.frame.origin.x = frame.size.width - viewWidth - rightMargin + menu.addSubview(accountSettingsView) + menu.addSubview(advancedSettingsView) + menu.addSubview(aboutView) + let firstLine = UIView.init(frame: CGRect(x: 0, y: itemHeight * 2, width: viewWidth, height: 1)) + let secondLine = UIView.init(frame: CGRect(x: 0, y: itemHeight * 4, width: viewWidth, height: 1)) + if #available(iOS 13.0, *) { + firstLine.backgroundColor = UIColor.quaternaryLabel + secondLine.backgroundColor = UIColor.quaternaryLabel + } else { + firstLine.backgroundColor = UIColor.gray.lighten(by: 40) + secondLine.backgroundColor = UIColor.gray.lighten(by: 40) + } + menu.addSubview(firstLine) + menu.addSubview(secondLine) + if #available(iOS 13.0, *) { + let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial)) + visualEffectView.frame = menu.bounds + visualEffectView.isUserInteractionEnabled = false + visualEffectView.alpha = 0.97 + menu.insertSubview(visualEffectView, at: 0) + } else { + let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) + visualEffectView.frame = menu.bounds + visualEffectView.isUserInteractionEnabled = false + let background = UIView() + background.frame = menu.bounds + background.backgroundColor = UIColor(red: 245, green: 245, blue: 245, alpha: 0.5) + menu.insertSubview(background, at: 0) + menu.insertSubview(visualEffectView, at: 0) + } + self.navigationController?.view.addSubview(menu) + } + + private func infoItemTapped() { + var compileDate: String { + let dateDefault = "" + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "YYYYMMdd" + let bundleName = Bundle.main.infoDictionary!["CFBundleName"] as? String ?? "Info.plist" + if let infoPath = Bundle.main.path(forResource: bundleName, ofType: nil), + let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath), + let infoDate = infoAttr[FileAttributeKey.creationDate] as? Date { + return dateFormatter.string(from: infoDate) + } + return dateDefault + } + + let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" + + let versionName = L10n.Global.versionName + let alert = UIAlertController(title: "\nJami\nversion: \(appVersion)(\(compileDate))\n\(versionName)", message: "", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: L10n.Global.ok, style: .default, handler: nil)) + let image = UIImageView(image: UIImage(asset: Asset.jamiIcon)) + alert.view.addSubview(image) + image.translatesAutoresizingMaskIntoConstraints = false + alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .centerX, relatedBy: .equal, toItem: alert.view, attribute: .centerX, multiplier: 1, constant: 0)) + alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .centerY, relatedBy: .equal, toItem: alert.view, attribute: .top, multiplier: 1, constant: 0.0)) + alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 64.0)) + alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 64.0)) + self.present(alert, animated: true, completion: nil) + } + + private func updateAccountItemSize() { let screenRect = UIScreen.main.bounds let screenWidth = screenRect.size.width let window = UIApplication.shared.keyWindow let leftPadding: CGFloat = window?.safeAreaInsets.left ?? 0 - searchFieldTrailing.constant = leftPadding let maxWidth: CGFloat = screenWidth - 45 - margin * 3 - leftPadding * 2 accountWidth.constant = maxWidth var accountFrame = accountView.frame @@ -426,14 +686,10 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased guard let keyboardFrame: NSValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return } let keyboardRectangle = keyboardFrame.cgRectValue let keyboardHeight = keyboardRectangle.height - guard let tabBarHeight = (self.tabBarController?.tabBar.frame.size.height) else { - return - } - - self.conversationsTableView.contentInset.bottom = keyboardHeight - tabBarHeight - self.searchView.searchResultsTableView.contentInset.bottom = keyboardHeight - tabBarHeight - self.conversationsTableView.scrollIndicatorInsets.bottom = keyboardHeight - tabBarHeight - self.searchView.searchResultsTableView.scrollIndicatorInsets.bottom = keyboardHeight - tabBarHeight + self.conversationsTableView.contentInset.bottom = keyboardHeight + self.searchView.searchResultsTableView.contentInset.bottom = keyboardHeight + self.conversationsTableView.scrollIndicatorInsets.bottom = keyboardHeight + self.searchView.searchResultsTableView.scrollIndicatorInsets.bottom = keyboardHeight } @objc @@ -488,52 +744,47 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased self.conversationsTableView.rx.setDelegate(self).disposed(by: disposeBag) } - func setupSearchBar() { - searchBarShadow.backgroundColor = UIColor.clear - self.searchBarShadow.layer.shadowColor = UIColor.jamiNavigationBarShadow.cgColor - self.searchBarShadow.layer.shadowOffset = CGSize(width: 0.0, height: 1.5) - self.searchBarShadow.layer.shadowOpacity = 0.2 - self.searchBarShadow.layer.shadowRadius = 3 - self.searchBarShadow.layer.masksToBounds = false - - if #available(iOS 13.0, *) { - let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial)) - visualEffectView.frame = searchBarShadow.bounds - visualEffectView.isUserInteractionEnabled = false - searchBarShadow.insertSubview(visualEffectView, at: 0) - visualEffectView.translatesAutoresizingMaskIntoConstraints = false - visualEffectView.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: 0).isActive = true - visualEffectView.trailingAnchor.constraint(equalTo: self.searchBarShadow.trailingAnchor, constant: 0).isActive = true - visualEffectView.leadingAnchor.constraint(equalTo: self.searchBarShadow.leadingAnchor, constant: 0).isActive = true - visualEffectView.topAnchor.constraint(equalTo: self.searchBarShadow.topAnchor, constant: 0).isActive = true - visualEffectView.bottomAnchor.constraint(equalTo: self.searchBarShadow.bottomAnchor, constant: 0).isActive = true + let searchController: CustomSearchController = { + let searchController = CustomSearchController(searchResultsController: nil) + searchController.searchBar.searchBarStyle = .minimal + searchController.obscuresBackgroundDuringPresentation = false + searchController.definesPresentationContext = true + searchController.hidesNavigationBarDuringPresentation = true + return searchController + }() + + func updateSearchBar() { + guard let account = self.viewModel.currentAccount else { return } + let accountSip = account.type == AccountType.sip + let image = accountSip ? UIImage(asset: Asset.phoneBook) : UIImage(asset: Asset.qrCode) + guard let buttonImage = image else { return } + searchController.updateSearchBar(image: buttonImage) + } - } else { - let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) - visualEffectView.frame = searchBarShadow.bounds - visualEffectView.isUserInteractionEnabled = false - let background = UIView() - background.frame = searchBarShadow.bounds - background.backgroundColor = UIColor(red: 245, green: 245, blue: 245, alpha: 1.0) - background.alpha = 0.7 - searchBarShadow.insertSubview(background, at: 0) - searchBarShadow.insertSubview(visualEffectView, at: 0) - background.translatesAutoresizingMaskIntoConstraints = false - visualEffectView.translatesAutoresizingMaskIntoConstraints = false - visualEffectView.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: 0).isActive = true - background.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: 0).isActive = true - visualEffectView.trailingAnchor.constraint(equalTo: self.searchBarShadow.trailingAnchor, constant: 0).isActive = true - background.trailingAnchor.constraint(equalTo: self.searchBarShadow.trailingAnchor, constant: 0).isActive = true - visualEffectView.leadingAnchor.constraint(equalTo: self.searchBarShadow.leadingAnchor, constant: 0).isActive = true - background.leadingAnchor.constraint(equalTo: self.searchBarShadow.leadingAnchor, constant: 0).isActive = true - visualEffectView.topAnchor.constraint(equalTo: self.searchBarShadow.topAnchor, constant: 0).isActive = true - background.topAnchor.constraint(equalTo: self.searchBarShadow.topAnchor, constant: 0).isActive = true - visualEffectView.bottomAnchor.constraint(equalTo: self.searchBarShadow.bottomAnchor, constant: 0).isActive = true - background.bottomAnchor.constraint(equalTo: self.searchBarShadow.bottomAnchor, constant: 0).isActive = true - } + func setupSearchBar() { + guard let account = self.viewModel.currentAccount else { return } + let accountSip = account.type == AccountType.sip + let image = accountSip ? UIImage(asset: Asset.phoneBook) : UIImage(asset: Asset.qrCode) + guard let buttonImage = image else { return } + searchController + .configureSearchBar(image: buttonImage, + buttonPressed: { [weak self] in + guard let self = self else { return } + guard let account = self.viewModel.currentAccount else { return } + let accountSip = account.type == AccountType.sip + if accountSip { + self.contactPicker.delegate = self + self.present(self.contactPicker, animated: true, completion: nil) + } else { + self.openScan() + } + }) + navigationItem.searchController = searchController + + navigationItem.hidesSearchBarWhenScrolling = false + searchView.searchBar = searchController.searchBar self.searchView.editSearch .subscribe(onNext: {[weak self] (editing) in - self?.scanButtonLeadingConstraint.constant = editing ? -40 : 10 self?.viewModel.searching.onNext(editing) }) .disposed(by: disposeBag) @@ -598,22 +849,6 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased extension SmartlistViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { - guard let headerView = view as? UITableViewHeaderFooterView else { return } - headerView.tintColor = .clear - } - - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - if section == 0 { - if tableView == self.conversationsTableView { - return SmartlistConstants.tableHeaderViewHeight - } - return SmartlistConstants.tableHeaderViewHeight + SmartlistConstants.firstSectionHeightForHeader - } else { - return SmartlistConstants.tableHeaderViewHeight - } - } - func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? { let block = UITableViewRowAction(style: .normal, title: "Block") { _, index in self.showBlockContactConfirmation(atIndex: index) diff --git a/Ring/Ring/Features/Conversations/SmartList/SmartlistViewModel.swift b/Ring/Ring/Features/Conversations/SmartList/SmartlistViewModel.swift index 109eb503a9030eb6a3c29614360e058d8d54048b..8e0bbeeba01aeb9622d8888056b05b766866706f 100644 --- a/Ring/Ring/Features/Conversations/SmartList/SmartlistViewModel.swift +++ b/Ring/Ring/Features/Conversations/SmartList/SmartlistViewModel.swift @@ -189,6 +189,49 @@ class SmartlistViewModel: Stateable, ViewModel, FilterConversationDataSource { }) }() + lazy var unreadMessages: Observable<Int> = {[weak self] in + guard let self = self else { + return Observable.just(0) + } + return self.conversationsForCurrentAccount + .share() + .map { conversations -> Int in + var result = 0 + for conversation in conversations { + result += conversation.messages.filter({ $0.status != .displayed && !$0.isTransfer && $0.incoming }).count + } + return result + } + }() + + lazy var unhandeledRequests: Observable<Int> = {[weak self] in + guard let self = self else { + return Observable.just(0) + } + return self.contactsService.contactRequests + .asObservable() + .map({ contactRequests -> Int in + guard let account = self.accountsService.currentAccount else { + return 0 + } + return contactRequests.filter { $0.accountId == account.id }.count + }) + }() + typealias BageValues = (messages: Int, requests: Int) + lazy var updateSegmentControl: Observable<BageValues> = {[weak self] in + guard let self = self else { + let value: BageValues = (0, 0) + return Observable.just(value) + } + return Observable<BageValues> + .combineLatest(self.unreadMessages, + self.unhandeledRequests, + resultSelector: {(messages, requests) -> BageValues in + return (messages, requests) + }) + .observeOn(MainScheduler.instance) + }() + var conversationsForCurrentAccount = PublishSubject<[ConversationModel]>() func reloadDataFor(accountId: String) { @@ -314,6 +357,10 @@ class SmartlistViewModel: Stateable, ViewModel, FilterConversationDataSource { conversationViewModel)) } + func showAccountSettings() { + self.stateSubject.onNext(ConversationState.showAccountSettings) + } + func closeAllPlayers() { self.conversationViewModels.forEach { (conversationModel) in conversationModel.closeAllPlayers() diff --git a/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchView.swift b/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchView.swift index f22fcb349665309566a3ea51b56488080518064f..6bcf3fe841ba37af89d7b03b3a7332ef47e24e8f 100644 --- a/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchView.swift +++ b/Ring/Ring/Features/Conversations/views/JamiSearchView/JamiSearchView.swift @@ -38,6 +38,7 @@ class JamiSearchView: NSObject { let incognitoCellHeight: CGFloat = 150 let incognitoHeaderHeight: CGFloat = 0 + var showSearchResult: Bool = true func configure(with injectionBag: InjectionBag, source: FilterConversationDataSource, isIncognito: Bool) { self.viewModel = JamiSearchViewModel(with: injectionBag, source: source) @@ -63,7 +64,6 @@ class JamiSearchView: NSObject { } else { self.searchResultsTableView.register(cellType: SmartListCell.self) self.searchResultsTableView.rowHeight = SmartlistConstants.smartlistRowHeight - self.searchResultsTableView.tableFooterView = UIView() } self.searchResultsTableView.backgroundColor = UIColor.jamiBackgroundColor @@ -84,14 +84,13 @@ class JamiSearchView: NSObject { self.viewModel .searchResults - .map({ (conversations) -> Bool in return conversations.isEmpty }) - .subscribe(onNext: { [weak self] (hideFooterView) in - self?.searchResultsTableView.tableFooterView?.isHidden = hideFooterView }) + .bind(to: self.searchResultsTableView.rx.items(dataSource: searchResultsDatasource)) .disposed(by: disposeBag) - self.viewModel .searchResults - .bind(to: self.searchResultsTableView.rx.items(dataSource: searchResultsDatasource)) + .map({ (conversations) -> Bool in return conversations.isEmpty }) + .subscribe(onNext: { [weak self] (hideFooterView) in + self?.searchResultsTableView.tableFooterView?.isHidden = hideFooterView }) .disposed(by: disposeBag) self.searchResultsTableView.rx.itemSelected @@ -111,14 +110,10 @@ class JamiSearchView: NSObject { self.viewModel.isSearching .subscribe(onNext: { [weak self] (isSearching) in - self?.searchResultsTableView.isHidden = !isSearching - self?.searchingLabel.isHidden = !isSearching - }) - .disposed(by: disposeBag) - - self.viewModel.searchStatus - .subscribe(onNext: { [weak self] (searchText) in - self?.searchResultsTableView.contentInset.top = searchText.isEmpty ? 0 : 24 + guard let self = self else { return } + self.searchResultsTableView.isHidden = !isSearching + let resultvisible = isSearching && self.showSearchResult + self.searchingLabel.isHidden = !resultvisible }) .disposed(by: disposeBag) } @@ -166,8 +161,7 @@ class JamiSearchView: NSObject { searchBar.returnKeyType = .done searchBar.autocapitalizationType = .none searchBar.tintColor = UIColor.jamiMain - searchBar.placeholder = L10n.Smartlist.searchBarPlaceholder - searchBar.searchBarStyle = .minimal + searchBar.placeholder = L10n.Smartlist.searchBar searchBar.backgroundImage = UIImage() searchBar.backgroundColor = UIColor.clear } @@ -175,12 +169,6 @@ class JamiSearchView: NSObject { // MARK: UITableViewDelegate extension JamiSearchView: UITableViewDelegate { - - func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { - guard let headerView = view as? UITableViewHeaderFooterView else { return } - headerView.tintColor = .clear - } - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return isIncognito ? incognitoHeaderHeight : SmartlistConstants.tableHeaderViewHeight } diff --git a/Ring/Ring/Features/Me/Detail/MeDetailViewController.storyboard b/Ring/Ring/Features/Me/Detail/MeDetailViewController.storyboard deleted file mode 100644 index 291ff69e0444f3de26164eb67a3c1339efc33609..0000000000000000000000000000000000000000 --- a/Ring/Ring/Features/Me/Detail/MeDetailViewController.storyboard +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Xnm-t3-8pO"> - <device id="retina4_7" orientation="portrait"> - <adaptation id="fullscreen"/> - </device> - <dependencies> - <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> - <capability name="Constraints to layout margins" minToolsVersion="6.0"/> - <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> - </dependencies> - <scenes> - <!--Details--> - <scene sceneID="Yh1-8d-nle"> - <objects> - <viewController title="Details" id="Xnm-t3-8pO" customClass="MeDetailViewController" customModule="Ring" customModuleProvider="target" sceneMemberID="viewController"> - <layoutGuides> - <viewControllerLayoutGuide type="top" id="C4W-cD-ScH"/> - <viewControllerLayoutGuide type="bottom" id="gIx-Me-F8R"/> - </layoutGuides> - <view key="view" contentMode="scaleToFill" id="mBS-Fy-f7e"> - <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Details" textAlignment="natural" lineBreakMode="clip" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="YiK-C6-85o"> - <rect key="frame" x="16" y="40" width="343" height="16"/> - <fontDescription key="fontDescription" type="system" pointSize="13"/> - <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <constraints> - <constraint firstItem="YiK-C6-85o" firstAttribute="top" secondItem="C4W-cD-ScH" secondAttribute="bottom" constant="20" id="0qe-xX-bzR"/> - <constraint firstItem="YiK-C6-85o" firstAttribute="leading" secondItem="mBS-Fy-f7e" secondAttribute="leadingMargin" id="mvb-LU-BZ8"/> - <constraint firstItem="YiK-C6-85o" firstAttribute="trailing" secondItem="mBS-Fy-f7e" secondAttribute="trailingMargin" id="oie-oE-20L"/> - </constraints> - </view> - <extendedEdge key="edgesForExtendedLayout" bottom="YES"/> - <navigationItem key="navigationItem" title="Details" id="QbY-2p-rda"/> - <connections> - <outlet property="detailsLabel" destination="YiK-C6-85o" id="Vu7-1P-P7p"/> - </connections> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="UcU-7l-x8f" userLabel="First Responder" sceneMemberID="firstResponder"/> - </objects> - <point key="canvasLocation" x="784" y="-438"/> - </scene> - </scenes> -</document> diff --git a/Ring/Ring/Features/Me/Detail/MeDetailViewController.swift b/Ring/Ring/Features/Me/Detail/MeDetailViewController.swift deleted file mode 100644 index a306879c367d8422eb2abe366792d2406bcdebd8..0000000000000000000000000000000000000000 --- a/Ring/Ring/Features/Me/Detail/MeDetailViewController.swift +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2016-2019 Savoir-faire Linux Inc. - * - * Author: Edric Ladent-Milaret <edric.ladent-milaret@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -import UIKit -import Reusable - -class MeDetailViewController: UIViewController, StoryboardBased, ViewModelBased { - - // MARK: - Properties - var account: AccountModel! - var viewModel: MeDetailViewModel! - - @IBOutlet weak var detailsLabel: UILabel! - -} diff --git a/Ring/Ring/Features/Me/Detail/MeDetailViewModel.swift b/Ring/Ring/Features/Me/Detail/MeDetailViewModel.swift deleted file mode 100644 index b9a0d32971d9ef60961a21fb87381124bcd536e7..0000000000000000000000000000000000000000 --- a/Ring/Ring/Features/Me/Detail/MeDetailViewModel.swift +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. - * - * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -import Foundation - -class MeDetailViewModel: ViewModel { - - required init(with injectionBag: InjectionBag) { - } - -} diff --git a/Ring/Ring/Features/Me/LinkNewDeviceViewController.swift b/Ring/Ring/Features/Me/LinkNewDeviceViewController.swift index 2709eac4ca886774fa0340b0c4dae019979ae6c4..a93f45de3e55a7a13f672e76170128b2227206b2 100644 --- a/Ring/Ring/Features/Me/LinkNewDeviceViewController.swift +++ b/Ring/Ring/Features/Me/LinkNewDeviceViewController.swift @@ -33,8 +33,6 @@ class LinkNewDeviceViewController: UIViewController, StoryboardBased, ViewModelB self.view.backgroundColor = UIColor.white.withAlphaComponent(0.0) super.viewDidLoad() - self.showInitialAlert() - self.viewModel.observableState .observeOn(MainScheduler.instance) .subscribe(onNext: { [weak self] (state) in @@ -54,6 +52,11 @@ class LinkNewDeviceViewController: UIViewController, StoryboardBased, ViewModelB .disposed(by: self.disposeBag) } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.showInitialAlert() + } + private func showProgress() { HUD.show(.labeledProgress(title: L10n.LinkDevice.hudMessage, subtitle: nil)) } diff --git a/Ring/Ring/Features/Me/Me/AccountHeader.xib b/Ring/Ring/Features/Me/Me/AccountHeader.xib index faaf9628ccda70f3c017214384f5001faa1f49e6..763bee2199a064da61127541dab0ddf5687c897c 100644 --- a/Ring/Ring/Features/Me/Me/AccountHeader.xib +++ b/Ring/Ring/Features/Me/Me/AccountHeader.xib @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> @@ -11,14 +11,14 @@ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="AccountHeader" customModule="Ring" customModuleProvider="target"> - <rect key="frame" x="0.0" y="0.0" width="375" height="270"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="280"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="CHp-YH-dZ5"> - <rect key="frame" x="0.0" y="0.0" width="375" height="270"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="280"/> <subviews> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_contact_picture" translatesAutoresizingMaskIntoConstraints="NO" id="bD3-jT-xLr"> - <rect key="frame" x="137.5" y="100" width="100" height="100"/> + <rect key="frame" x="137.5" y="120" width="100" height="100"/> <color key="tintColor" red="0.24705882352941178" green="0.42745098039215684" blue="0.65490196078431373" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> <constraints> <constraint firstAttribute="height" constant="100" id="2mb-uU-dHb"/> @@ -32,7 +32,7 @@ </userDefinedRuntimeAttributes> </imageView> <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="oQJ-jT-wTv"> - <rect key="frame" x="20" y="210" width="335" height="35"/> + <rect key="frame" x="20" y="230" width="335" height="35"/> <fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/> <textInputTraits key="textInputTraits"/> <userDefinedRuntimeAttributes> @@ -42,7 +42,7 @@ </subviews> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <constraints> - <constraint firstItem="bD3-jT-xLr" firstAttribute="top" secondItem="CHp-YH-dZ5" secondAttribute="top" constant="100" id="HnG-Ht-Pfl"/> + <constraint firstItem="bD3-jT-xLr" firstAttribute="top" secondItem="CHp-YH-dZ5" secondAttribute="top" constant="120" id="HnG-Ht-Pfl"/> <constraint firstItem="oQJ-jT-wTv" firstAttribute="top" secondItem="bD3-jT-xLr" secondAttribute="bottom" constant="10" id="oKl-Yq-gZw"/> <constraint firstItem="bD3-jT-xLr" firstAttribute="centerX" secondItem="CHp-YH-dZ5" secondAttribute="centerX" id="pf4-Dp-CPJ"/> <constraint firstItem="oQJ-jT-wTv" firstAttribute="leading" secondItem="CHp-YH-dZ5" secondAttribute="leading" constant="20" id="txQ-DZ-CHU"/> @@ -50,6 +50,7 @@ </constraints> </view> </subviews> + <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="CHp-YH-dZ5" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="C9b-rk-lYC"/> @@ -58,10 +59,9 @@ <constraint firstItem="CHp-YH-dZ5" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="v1F-D0-1oe"/> </constraints> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> - <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/> <userDefinedRuntimeAttributes> <userDefinedRuntimeAttribute type="number" keyPath="maximumContentHeight"> - <real key="value" value="270"/> + <real key="value" value="280"/> </userDefinedRuntimeAttribute> <userDefinedRuntimeAttribute type="number" keyPath="minimumContentHeight"> <real key="value" value="0.0"/> diff --git a/Ring/Ring/Features/Me/Me/BlockListViewController.storyboard b/Ring/Ring/Features/Me/Me/BlockListViewController.storyboard index 99d548e634bdb38a4762b291328b6097be67df19..cb53076908380ef95eaab5a3f13e74438a03fc2d 100644 --- a/Ring/Ring/Features/Me/Me/BlockListViewController.storyboard +++ b/Ring/Ring/Features/Me/Me/BlockListViewController.storyboard @@ -1,24 +1,25 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cWr-kq-EfK"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cWr-kq-EfK"> <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> <!--Block List View Controller--> <scene sceneID="CDw-GO-ni9"> <objects> - <viewController extendedLayoutIncludesOpaqueBars="YES" hidesBottomBarWhenPushed="YES" id="cWr-kq-EfK" customClass="BlockListViewController" customModule="Ring" customModuleProvider="target" sceneMemberID="viewController"> + <viewController automaticallyAdjustsScrollViewInsets="NO" id="cWr-kq-EfK" customClass="BlockListViewController" customModule="Ring" customModuleProvider="target" sceneMemberID="viewController"> <view key="view" contentMode="scaleToFill" id="YKN-B2-7X7"> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="72" estimatedRowHeight="72" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="eGc-th-VK5"> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> - <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> </tableView> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No blocked contacts" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nUo-eH-a0f"> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> @@ -27,18 +28,19 @@ <nil key="highlightedColor"/> </label> </subviews> + <viewLayoutGuide key="safeArea" id="wN6-Fz-tau"/> <constraints> <constraint firstItem="eGc-th-VK5" firstAttribute="top" secondItem="YKN-B2-7X7" secondAttribute="top" id="5Nj-Mt-QeY"/> <constraint firstItem="nUo-eH-a0f" firstAttribute="top" secondItem="YKN-B2-7X7" secondAttribute="top" id="6YC-L1-UO0"/> <constraint firstItem="nUo-eH-a0f" firstAttribute="leading" secondItem="wN6-Fz-tau" secondAttribute="leading" id="7G3-4b-v8w"/> <constraint firstItem="nUo-eH-a0f" firstAttribute="trailing" secondItem="wN6-Fz-tau" secondAttribute="trailing" id="DwO-qn-bYX"/> - <constraint firstItem="wN6-Fz-tau" firstAttribute="bottom" secondItem="nUo-eH-a0f" secondAttribute="bottom" id="gsh-dP-Os8"/> + <constraint firstItem="nUo-eH-a0f" firstAttribute="bottom" secondItem="eGc-th-VK5" secondAttribute="bottom" id="GcN-Wl-7s4"/> + <constraint firstAttribute="bottom" secondItem="eGc-th-VK5" secondAttribute="bottom" id="Zty-gx-bJ1"/> <constraint firstItem="eGc-th-VK5" firstAttribute="trailing" secondItem="wN6-Fz-tau" secondAttribute="trailing" id="uq4-pz-rcL"/> <constraint firstItem="eGc-th-VK5" firstAttribute="leading" secondItem="wN6-Fz-tau" secondAttribute="leading" id="xU3-rh-8zX"/> - <constraint firstItem="eGc-th-VK5" firstAttribute="bottom" secondItem="wN6-Fz-tau" secondAttribute="bottom" id="xqa-be-YtG"/> </constraints> - <viewLayoutGuide key="safeArea" id="wN6-Fz-tau"/> </view> + <extendedEdge key="edgesForExtendedLayout" top="YES"/> <connections> <outlet property="noBlockedContactLabel" destination="nUo-eH-a0f" id="0zv-9l-3GL"/> <outlet property="tableView" destination="eGc-th-VK5" id="4JY-jU-2Xb"/> @@ -49,4 +51,9 @@ <point key="canvasLocation" x="0.80000000000000004" y="136.28185907046478"/> </scene> </scenes> + <resources> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> + </resources> </document> diff --git a/Ring/Ring/Features/Me/Me/BlockListViewController.swift b/Ring/Ring/Features/Me/Me/BlockListViewController.swift index a6b9e7b2cd34df2d804373a711b60aa0cd052c6d..d59c610d8488dc28472cfb976c2e9ab90faf63a4 100644 --- a/Ring/Ring/Features/Me/Me/BlockListViewController.swift +++ b/Ring/Ring/Features/Me/Me/BlockListViewController.swift @@ -51,10 +51,9 @@ class BlockListViewController: UIViewController, StoryboardBased, ViewModelBased .observeOn(MainScheduler.instance) .bind(to: self.noBlockedContactLabel.rx.isHidden) .disposed(by: self.disposeBag) - self.navigationController?.navigationBar - .titleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "HelveticaNeue-Light", size: 25)!, - NSAttributedString.Key.foregroundColor: UIColor.jamiMain] + .titleTextAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18, weight: .medium), + NSAttributedString.Key.foregroundColor: UIColor.jamiLabelColor] } func setupTableView() { diff --git a/Ring/Ring/Features/Me/Me/MeViewController.swift b/Ring/Ring/Features/Me/Me/MeViewController.swift index 7fe8cbfc83c691d6a85c6549ea56e3116d4d068c..65c0e19c28bc3d9a600c5b03e89ce8e0d245db70 100644 --- a/Ring/Ring/Features/Me/Me/MeViewController.swift +++ b/Ring/Ring/Features/Me/Me/MeViewController.swift @@ -74,9 +74,10 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + self.navigationController?.navigationBar.layer.shadowColor = UIColor.jamiNavigationBarShadow.cgColor self.navigationController?.navigationBar - .titleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "HelveticaNeue-Light", size: 25)!, - NSAttributedString.Key.foregroundColor: UIColor.jamiMain] + .titleTextAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18, weight: .medium), + NSAttributedString.Key.foregroundColor: UIColor.jamiLabelColor] } func applyL10n() { @@ -96,7 +97,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas } headerView.backgroundColor = UIColor.jamiBackgroundColor self.stretchyHeader = headerView - let point = CGPoint(x: 0, y: 100) + let point = CGPoint(x: 0, y: 120) self.stretchyHeader.frame.origin = point self.settingsTable.addSubview(self.stretchyHeader) self.settingsTable.delegate = self @@ -115,7 +116,6 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas } private func configureBindings() { - let infoButton = UIButton(type: .infoLight) let imageQrCode = UIImage(asset: Asset.qrCode) as UIImage? let qrCodeButton = UIButton(type: UIButton.ButtonType.custom) as UIButton qrCodeButton.setImage(imageQrCode, for: .normal) @@ -127,13 +127,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas qrCodeButton?.isEnabled = !isSip }) .disposed(by: self.disposeBag) - let infoItem = UIBarButtonItem(customView: infoButton) let qrCodeButtonItem = UIBarButtonItem(customView: qrCodeButton) - infoButton.rx.tap.throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) - .subscribe(onNext: { [weak self] in - self?.infoItemTapped() - }) - .disposed(by: self.disposeBag) qrCodeButton.rx.tap.throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) .subscribe(onNext: { [weak self] in self?.qrCodeItemTapped() @@ -160,8 +154,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas } }) .disposed(by: self.disposeBag) - self.navigationItem.rightBarButtonItem = infoItem - self.navigationItem.leftBarButtonItem = qrCodeButtonItem + self.navigationItem.rightBarButtonItem = qrCodeButtonItem //setup Table self.settingsTable.estimatedRowHeight = 35 @@ -226,35 +219,6 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas } } - private func infoItemTapped() { - var compileDate: String { - let dateDefault = "" - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "YYYYMMdd" - let bundleName = Bundle.main.infoDictionary!["CFBundleName"] as? String ?? "Info.plist" - if let infoPath = Bundle.main.path(forResource: bundleName, ofType: nil), - let infoAttr = try? FileManager.default.attributesOfItem(atPath: infoPath), - let infoDate = infoAttr[FileAttributeKey.creationDate] as? Date { - return dateFormatter.string(from: infoDate) - } - return dateDefault - } - - let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" - - let versionName = L10n.Global.versionName - let alert = UIAlertController(title: "\nJami\nversion: \(appVersion)(\(compileDate))\n\(versionName)", message: "", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: L10n.Global.ok, style: .default, handler: nil)) - let image = UIImageView(image: UIImage(asset: Asset.jamiIcon)) - alert.view.addSubview(image) - image.translatesAutoresizingMaskIntoConstraints = false - alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .centerX, relatedBy: .equal, toItem: alert.view, attribute: .centerX, multiplier: 1, constant: 0)) - alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .centerY, relatedBy: .equal, toItem: alert.view, attribute: .top, multiplier: 1, constant: 0.0)) - alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 64.0)) - alert.view.addConstraint(NSLayoutConstraint(item: image, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 64.0)) - self.present(alert, animated: true, completion: nil) - } - private func qrCodeItemTapped() { let alert = UIAlertController(title: "", message: "", preferredStyle: .alert) guard let ringId = viewModel.getRingId() else { return } @@ -1091,12 +1055,7 @@ class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBas style: .cancel) let actionConfirm = UIAlertAction(title: L10n.AccountPage.removeAccountButton, style: .destructive) { [weak self] _ in - UIView.animate(withDuration: 0.1, animations: { - self?.view.alpha = 0 - }, completion: { _ in - self?.viewModel.startAccountRemoving() - self?.view.alpha = 1 - }) + self?.viewModel.startAccountRemoving() } alert.addAction(actionCancel) alert.addAction(actionConfirm) @@ -1143,7 +1102,11 @@ extension MeViewController: UITableViewDelegate { let activityViewController = UIActivityViewController(activityItems: content, applicationActivities: nil) activityViewController.setValue(title, forKey: "Subject") - activityViewController.popoverPresentationController?.sourceView = self.view + if UIDevice.current.userInterfaceIdiom == .phone { + activityViewController.popoverPresentationController?.sourceView = self.view + } else { + activityViewController.popoverPresentationController?.sourceView = stretchyHeader + } self.present(activityViewController, animated: true, completion: nil) } diff --git a/Ring/Ring/Features/Me/MeCoordinator.swift b/Ring/Ring/Features/Me/MeCoordinator.swift index ac598442325872855cdc9295566bfbcf0f5b09f0..3a3f561ae5eb6f68d429dcfa835485a08e57f380 100644 --- a/Ring/Ring/Features/Me/MeCoordinator.swift +++ b/Ring/Ring/Features/Me/MeCoordinator.swift @@ -23,10 +23,8 @@ import RxSwift /// Represents Me navigation state /// -/// - meDetail: user want its account detail /// -linkDevice: link new device to account public enum MeState: State { - case meDetail case linkNewDevice case blockedContacts case needToOnboard @@ -42,12 +40,11 @@ class MeCoordinator: Coordinator, StateableResponsive { var rootViewController: UIViewController { return self.navigationViewController } - var parentCoordinator: Coordinator? var childCoordinators = [Coordinator]() - private let navigationViewController = BaseViewController(with: TabBarItemType.account) + private var navigationViewController = UINavigationController() private let injectionBag: InjectionBag let disposeBag = DisposeBag() @@ -62,8 +59,6 @@ class MeCoordinator: Coordinator, StateableResponsive { .subscribe(onNext: { [weak self] (state) in guard let self = self, let state = state as? MeState else { return } switch state { - case .meDetail: - self.showMeDetail() case .linkNewDevice: self.showLinkDeviceWindow() case .blockedContacts: @@ -82,26 +77,26 @@ class MeCoordinator: Coordinator, StateableResponsive { } func needToOnboard() { - if let parent = self.parentCoordinator as? AppCoordinator { - parent.stateSubject.onNext(AppState.needToOnboard(animated: false, isFirstAccount: true)) + if let parent = self.parentCoordinator as? ConversationsCoordinator { + parent.stateSubject.onNext(ConversationState.needToOnboard) } } func accountModeChanged() { - if let parent = self.parentCoordinator as? AppCoordinator { - parent.stateSubject.onNext(AppState.accountModeSwitched) + if let parent = self.parentCoordinator as? ConversationsCoordinator { + parent.stateSubject.onNext(ConversationState.accountModeChanged) } } func migrateAccount(accountId: String) { - if let parent = self.parentCoordinator as? AppCoordinator { - parent.stateSubject.onNext(AppState.needAccountMigration(accountId: accountId)) + if let parent = self.parentCoordinator as? ConversationsCoordinator { + parent.stateSubject.onNext(ConversationState.needAccountMigration(accountId: accountId)) } } func accountRemoved() { - if let parent = self.parentCoordinator as? AppCoordinator { - parent.stateSubject.onNext(AppState.accountRemoved) + if let parent = self.parentCoordinator as? ConversationsCoordinator { + parent.stateSubject.onNext(ConversationState.accountRemoved) } } @@ -112,6 +107,10 @@ class MeCoordinator: Coordinator, StateableResponsive { self.present(viewController: meViewController, withStyle: .show, withAnimation: true, withStateable: meViewController.viewModel) } + func setNavigationController(controller: UINavigationController) { + navigationViewController = controller + } + private func showBlockedContacts() { if let flag = self.presentingVC[VCType.blockList.rawValue], flag { return @@ -125,11 +124,6 @@ class MeCoordinator: Coordinator, StateableResponsive { disposeBag: self.disposeBag) } - private func showMeDetail () { - let meDetailViewController = MeDetailViewController.instantiate(with: self.injectionBag) - self.present(viewController: meDetailViewController, withStyle: .show, withAnimation: true, disposeBag: self.disposeBag) - } - private func showLinkDeviceWindow() { let linkDeviceVC = LinkNewDeviceViewController.instantiate(with: self.injectionBag) self.present(viewController: linkDeviceVC, withStyle: .popup, withAnimation: false, disposeBag: self.disposeBag) diff --git a/Ring/Ring/GeneralSettings/GeneralSettingsViewController.storyboard b/Ring/Ring/GeneralSettings/GeneralSettingsViewController.storyboard index ccdd120ad43a4dd25b3db16d85f00db99b2152b5..c2f9de97730e49f0b2b697aec41400b405ed7338 100644 --- a/Ring/Ring/GeneralSettings/GeneralSettingsViewController.storyboard +++ b/Ring/Ring/GeneralSettings/GeneralSettingsViewController.storyboard @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="0KF-lS-cXQ"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="0KF-lS-cXQ"> <device id="retina4_7" orientation="portrait" appearance="light"/> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> @@ -16,56 +16,22 @@ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OaU-bt-R2w"> - <rect key="frame" x="0.0" y="0.0" width="375" height="120"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="General Settings" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fm1-VN-ppT"> - <rect key="frame" x="80.5" y="38.5" width="214" height="38.5"/> - <fontDescription key="fontDescription" type="system" weight="thin" pointSize="32"/> - <color key="textColor" red="0.1215686275" green="0.28627450980000002" blue="0.4431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <nil key="highlightedColor"/> - </label> - <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NE7-nL-DvW"> - <rect key="frame" x="0.0" y="30" width="55" height="55"/> - <constraints> - <constraint firstAttribute="height" constant="55" id="R0J-pI-wkz"/> - <constraint firstAttribute="width" constant="55" id="gl1-ki-xOB"/> - </constraints> - <color key="tintColor" red="0.1215686275" green="0.28627450980000002" blue="0.4431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> - <inset key="contentEdgeInsets" minX="15" minY="15" maxX="15" maxY="15"/> - <state key="normal" image="cross"/> - </button> - </subviews> - <constraints> - <constraint firstItem="fm1-VN-ppT" firstAttribute="centerX" secondItem="OaU-bt-R2w" secondAttribute="centerX" id="1kP-cu-cDP"/> - <constraint firstAttribute="bottom" secondItem="NE7-nL-DvW" secondAttribute="bottom" constant="35" id="Hsx-he-cDE"/> - <constraint firstAttribute="height" constant="120" id="JGl-fJ-5S9"/> - <constraint firstItem="fm1-VN-ppT" firstAttribute="centerY" secondItem="NE7-nL-DvW" secondAttribute="centerY" id="TAY-0E-oeR"/> - <constraint firstItem="NE7-nL-DvW" firstAttribute="leading" secondItem="OaU-bt-R2w" secondAttribute="leading" id="Ytg-WO-MP4"/> - </constraints> - </view> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="XAa-ES-xki"> - <rect key="frame" x="0.0" y="120" width="375" height="547"/> + <rect key="frame" x="0.0" y="20" width="375" height="647"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> </tableView> </subviews> + <viewLayoutGuide key="safeArea" id="f8H-BQ-kNd"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <constraints> - <constraint firstItem="OaU-bt-R2w" firstAttribute="top" secondItem="tdP-kF-vrw" secondAttribute="top" id="99o-PS-Hfy"/> - <constraint firstItem="OaU-bt-R2w" firstAttribute="leading" secondItem="tdP-kF-vrw" secondAttribute="leading" id="9Aq-IP-zrF"/> <constraint firstItem="XAa-ES-xki" firstAttribute="trailing" secondItem="f8H-BQ-kNd" secondAttribute="trailing" id="Ekj-a6-3GP"/> <constraint firstItem="XAa-ES-xki" firstAttribute="bottom" secondItem="f8H-BQ-kNd" secondAttribute="bottom" id="JGK-tS-24D"/> <constraint firstItem="XAa-ES-xki" firstAttribute="leading" secondItem="f8H-BQ-kNd" secondAttribute="leading" id="Kob-5x-TQ2"/> - <constraint firstAttribute="trailing" secondItem="OaU-bt-R2w" secondAttribute="trailing" id="Nht-yV-tfZ"/> - <constraint firstItem="XAa-ES-xki" firstAttribute="top" secondItem="OaU-bt-R2w" secondAttribute="bottom" id="dHt-YB-mRk"/> + <constraint firstItem="XAa-ES-xki" firstAttribute="top" secondItem="f8H-BQ-kNd" secondAttribute="top" constant="20" id="o6c-Em-qHA"/> </constraints> - <viewLayoutGuide key="safeArea" id="f8H-BQ-kNd"/> </view> - <extendedEdge key="edgesForExtendedLayout" bottom="YES"/> <connections> - <outlet property="doneButton" destination="NE7-nL-DvW" id="a2F-oe-Fon"/> <outlet property="settingsTable" destination="XAa-ES-xki" id="Af8-lt-Nsn"/> - <outlet property="tilteLabel" destination="fm1-VN-ppT" id="ycX-1U-ihE"/> </connections> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="1qI-Sw-ka9" userLabel="First Responder" sceneMemberID="firstResponder"/> @@ -73,7 +39,4 @@ <point key="canvasLocation" x="-108" y="137.18140929535232"/> </scene> </scenes> - <resources> - <image name="cross" width="40" height="40"/> - </resources> </document> diff --git a/Ring/Ring/GeneralSettings/GeneralSettingsViewController.swift b/Ring/Ring/GeneralSettings/GeneralSettingsViewController.swift index 83a79fbf972f61d89252d047cd86af0f342d18db..47f6be8f65e46d2457b8a44f81cf051e321997ab 100644 --- a/Ring/Ring/GeneralSettings/GeneralSettingsViewController.swift +++ b/Ring/Ring/GeneralSettings/GeneralSettingsViewController.swift @@ -28,9 +28,6 @@ class GeneralSettingsViewController: UIViewController, StoryboardBased, ViewMode var viewModel: GeneralSettingsViewModel! let disposeBag = DisposeBag() - @IBOutlet weak var doneButton: UIButton! - @IBOutlet weak var tilteLabel: UILabel! - @IBOutlet weak var settingsTable: UITableView! override func viewDidLoad() { @@ -39,22 +36,25 @@ class GeneralSettingsViewController: UIViewController, StoryboardBased, ViewMode settingsTable.backgroundColor = UIColor.jamiBackgroundColor self.applyL10n() self.setUpTable() - doneButton.rx.tap - .subscribe(onNext: { [weak self] in - self?.dismiss(animated: true, completion: nil) - }) - .disposed(by: self.disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.navigationBar.layer.shadowColor = UIColor.jamiNavigationBarShadow.cgColor + self.navigationController?.navigationBar + .titleTextAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18, weight: .medium), + NSAttributedString.Key.foregroundColor: UIColor.jamiLabelColor] } func setUpTable() { - self.settingsTable.estimatedRowHeight = 35 + self.settingsTable.estimatedRowHeight = 50 self.settingsTable.rowHeight = UITableView.automaticDimension self.settingsTable.tableFooterView = UIView() self.setUpDataSource() } func applyL10n() { - tilteLabel.text = L10n.GeneralSettings.title + self.navigationItem.title = L10n.GeneralSettings.title } private func setUpDataSource() { diff --git a/Ring/Ring/Helpers/LocalNotificationsHelper.swift b/Ring/Ring/Helpers/LocalNotificationsHelper.swift index ecd8db53567b231dbe1cff456da23174d2e6684f..573a216f6305a3e66376c6ffac70b41aa7061942 100644 --- a/Ring/Ring/Helpers/LocalNotificationsHelper.swift +++ b/Ring/Ring/Helpers/LocalNotificationsHelper.swift @@ -118,52 +118,6 @@ class LocalNotificationsHelper { self.timer = nil } - func presentCallNotification(data: [String: String], callService: CallsService) { - let title = NotificationCallTitle.incomingCall.getString() - guard let name = data [NotificationUserInfoKeys.name.rawValue], - let callID = data [NotificationUserInfoKeys.callID.rawValue] else { - return - } - timer = Timer.scheduledTimer(timeInterval: 60, - target: self, - selector: #selector(cancelCall), - userInfo: [NotificationUserInfoKeys.callID.rawValue: callID], - repeats: false) - let content = UNMutableNotificationContent() - content.title = title - content.body = name - content.userInfo = data - content.categoryIdentifier = self.callCategory - let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false) - let notificationRequest = UNNotificationRequest(identifier: callID, content: content, trigger: notificationTrigger) - UNUserNotificationCenter.current().add(notificationRequest) { (error) in - if let error = error { - print("Unable to Add Notification Request (\(error), \(error.localizedDescription))") - } - } - callService.currentCall(callId: callID) - .filter({ call in - return (call.state == .over || call.state == .failure) - }) - .single() - .observeOn(MainScheduler.instance) - .subscribe(onNext: { _ in - let content = UNMutableNotificationContent() - content.title = NotificationCallTitle.missedCall.getString() - content.body = name - content.sound = UNNotificationSound.default - content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber - let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false) - let notificationRequest = UNNotificationRequest(identifier: callID, content: content, trigger: notificationTrigger) - UNUserNotificationCenter.current().add(notificationRequest) { (error) in - if let error = error { - print("Unable to Add Notification Request (\(error), \(error.localizedDescription))") - } - } - }) - .disposed(by: self.disposeBag) - } - class func isEnabled() -> Bool { return UserDefaults.standard.bool(forKey: enbleNotificationsKey) } diff --git a/Ring/Ring/Protocols/ConversationNavigation.swift b/Ring/Ring/Protocols/ConversationNavigation.swift index f01bda3cc6e6cf6f5469a380c029309aafc48f03..d84951c9050df7c339b2ce8727d923f644a6cf73 100644 --- a/Ring/Ring/Protocols/ConversationNavigation.swift +++ b/Ring/Ring/Protocols/ConversationNavigation.swift @@ -38,6 +38,11 @@ enum ConversationState: State { case accountModeChanged case openFullScreenPreview(parentView: UIViewController, viewModel: PlayerViewModel?, image: UIImage?, initialFrame: CGRect, delegate: PreviewViewControllerDelegate) case replaceCurrentWithConversationFor(participantUri: String) + case showAccountSettings + case accountRemoved + case needToOnboard + case returnToSmartList + case migrateAccount(accountId: String) } protocol ConversationNavigation: class { @@ -70,11 +75,9 @@ extension ConversationNavigation where Self: Coordinator, Self: StateableRespons case .fromCallToConversation(let conversation): self.fromCallToConversation(withConversationViewModel: conversation) case .navigateToCall(let call): - self.presentCallController(call: call) + self.navigateToCall(call: call) case .needAccountMigration(let accountId): self.migrateAccount(accountId: accountId) - case .accountModeChanged: - self.accountModeChanged() case .openFullScreenPreview(let parentView, let viewModel, let image, let initialFrame, let delegate): self.openFullScreenPreview(parentView: parentView, viewModel: viewModel, image: image, initialFrame: initialFrame, delegate: delegate) default: @@ -89,11 +92,6 @@ extension ConversationNavigation where Self: Coordinator, Self: StateableRespons parent.stateSubject.onNext(AppState.needAccountMigration(accountId: accountId)) } } - func accountModeChanged() { - if let parent = self.parentCoordinator as? AppCoordinator { - parent.stateSubject.onNext(AppState.accountModeSwitched) - } - } func openRecordFile(conversation: ConversationModel, audioOnly: Bool) { let recordFileViewController = SendFileViewController.instantiate(with: self.injectionBag) @@ -167,7 +165,6 @@ extension ConversationNavigation where Self: Coordinator, Self: StateableRespons return } } - navigationController.popToRootViewController(animated: false) self.showConversation(withConversationViewModel: conversationViewModel) } @@ -185,7 +182,7 @@ extension ConversationNavigation where Self: Coordinator, Self: StateableRespons lockWhilePresenting: VCType.conversation.rawValue) } - func presentCallController (call: CallModel) { + func navigateToCall (call: CallModel) { guard let navController = self.rootViewController as? UINavigationController else { return } let controllers = navController.children for controller in controllers diff --git a/Ring/Ring/Resources/Images.xcassets/remove.imageset/Contents.json b/Ring/Ring/Resources/Images.xcassets/remove.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..bc65a35c095fa53a39c11291f6880fefe6afe968 --- /dev/null +++ b/Ring/Ring/Resources/Images.xcassets/remove.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "remove1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "remove2.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "remove3png.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove1.png b/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove1.png new file mode 100644 index 0000000000000000000000000000000000000000..23a9f6a7976a372e8750b1deec93ee3171973df3 Binary files /dev/null and b/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove1.png differ diff --git a/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove2.png b/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove2.png new file mode 100644 index 0000000000000000000000000000000000000000..d28b711846cd3bdd1df434db6a969125a25a3df4 Binary files /dev/null and b/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove2.png differ diff --git a/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove3png.png b/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove3png.png new file mode 100644 index 0000000000000000000000000000000000000000..8c3233f881bd9ed58936243cca79383d4e35fde1 Binary files /dev/null and b/Ring/Ring/Resources/Images.xcassets/remove.imageset/remove3png.png differ diff --git a/Ring/Ring/Resources/en.lproj/Localizable.strings b/Ring/Ring/Resources/en.lproj/Localizable.strings index 19d32d258fa82a0fe755eb244752935ac2a1c621..b6824237af0e5cfb1c63df330c89dc47f278f707 100644 --- a/Ring/Ring/Resources/en.lproj/Localizable.strings +++ b/Ring/Ring/Resources/en.lproj/Localizable.strings @@ -20,8 +20,7 @@ // Global "global.homeTabBarTitle" = "Conversations"; -"global.contactRequestsTabBarTitle" = "Invitations"; -"global.meTabBarTitle" = "Account"; +"global.meTabBarTitle" = "Account Settings"; "global.ok" = "Ok"; "global.versionName" = "Together"; "global.close" = "Close"; @@ -37,18 +36,23 @@ // Smartlist "smartlist.yesterday" = "Yesterday"; -"smartlist.results" = "Search Result"; +"smartlist.results" = "Public Directory"; "smartlist.conversations" = "Conversations"; "smartlist.searching" = "Searching..."; "smartlist.noResults" = "No results"; "smartlist.noConversation" = "No conversations"; "smartlist.searchBarPlaceholder" = "Enter name..."; +"smartlist.searchBar" = "Search for new or existing contact..."; "smartlist.noNetworkConnectivity" = "No network connectivity"; "smartlist.cellularAccess" = "Be sure cellular access is granted in your settings"; "smartlist.accountsTitle" = "Accounts"; "smartlist.addAccountButton" = "+ Add Account"; "smartlist.noNumber" = "Selected contact does not have any number"; "smartlist.selectOneNumber" = "Select one of the numbers"; +"smartlist.invitations" = "Invitations"; +"smartlist.accountSettings" = "Account Settings"; +"smartlist.advancedSettings" = "Advanced Settings"; +"smartlist.aboutJami" = "About Jami"; //Conversation "conversation.messagePlaceholder" = "Write message to "; @@ -331,7 +335,7 @@ "generatedMessage.liveLocationSharing" = "Live location sharing"; //General Settings -"generalSettings.title" = "General settings"; +"generalSettings.title" = "Advanced settings"; "generalSettings.videoAcceleration" = "Enable video acceleration"; //Migrate Account diff --git a/Ring/Ring/TabBar/BaseViewController.swift b/Ring/Ring/TabBar/BaseViewController.swift deleted file mode 100644 index e31f673d8614c27b8bb8dd5f64f5a65acfb4a044..0000000000000000000000000000000000000000 --- a/Ring/Ring/TabBar/BaseViewController.swift +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. - * - * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -import Foundation -import RxSwift - -protocol TabBarItemViewModel { - var itemBadgeValue: Observable<String?> { get set } -} - -public enum TabBarItemType { - case chat - case account - case contactRequest - - var tabBarItem: UITabBarItem { - switch self { - case .chat: - return UITabBarItem(title: L10n.Global.homeTabBarTitle, image: UIImage(named: "conversation_icon"), selectedImage: UIImage(named: "conversation_icon")) - case .account: - return UITabBarItem(title: L10n.Global.meTabBarTitle, image: UIImage(named: "account_icon"), selectedImage: UIImage(named: "account_icon")) - case .contactRequest: - return UITabBarItem(title: L10n.Global.contactRequestsTabBarTitle, image: UIImage(named: "contact_request_icon"), selectedImage: UIImage(named: "contact_request_icon")) - } - } -} - -class BaseViewController: UINavigationController { - - let disposeBag = DisposeBag() - - var viewModel: TabBarItemViewModel? { - didSet { - self.viewModel?.itemBadgeValue.bind(to: self.tabBarItem.rx.badgeValue) - .disposed(by: self.disposeBag) - } - } - - convenience init(with type: TabBarItemType) { - self.init() - self.navigationBar.isTranslucent = true - self.tabBarItem = type.tabBarItem - self.view.backgroundColor = UIColor.jamiBackgroundColor - } -} diff --git a/Ring/Ring/TabBar/ChatTabBarItemViewModel.swift b/Ring/Ring/TabBar/ChatTabBarItemViewModel.swift deleted file mode 100644 index 237795a26f2b502283f6cc86b38c59f7c9b60c78..0000000000000000000000000000000000000000 --- a/Ring/Ring/TabBar/ChatTabBarItemViewModel.swift +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. - * - * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -import Foundation -import RxSwift - -class ChatTabBarItemViewModel: ViewModel, TabBarItemViewModel { - - var itemBadgeValue: Observable<String?> - - required init(with injectionBag: InjectionBag) { - let conversationService = injectionBag.conversationsService - let contactsService = injectionBag.contactsService - self.itemBadgeValue = { - return conversationService.conversationsForCurrentAccount - .map({ conversations in - return conversations - .map({ conversation in - let unreadMsg = conversation.messages.filter({ message in - //filtre out read messages, outgoing messages and messages that are displayed in contactrequest conversation - return message.status != .displayed && !message.isTransfer && message.incoming - && (contactsService.contactRequest(withRingId: JamiURI.init(schema: URIType.ring, infoHach: message.authorURI).hash ?? "") == nil) - }) - return unreadMsg.count - }) - .reduce(0, +) - }) - }() - .map({ number in - if number == 0 { - return nil - } - return "\(number)" - }) - } -} diff --git a/Ring/Ring/TabBar/ContactRequestTabBarItem.swift b/Ring/Ring/TabBar/ContactRequestTabBarItem.swift deleted file mode 100644 index a826bdb9e2055435a2a92d4453f96ebb8afe4e6b..0000000000000000000000000000000000000000 --- a/Ring/Ring/TabBar/ContactRequestTabBarItem.swift +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. - * - * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -import Foundation -import RxSwift - -class ContactRequestTabBarItem: ViewModel, TabBarItemViewModel { - - var itemBadgeValue: Observable<String?> - - required init(with injectionBag: InjectionBag) { - let contactService = injectionBag.contactsService - let accountService = injectionBag.accountService - self.itemBadgeValue = contactService.contactRequests - .asObservable() - .map({ contactRequests in - return contactRequests - .filter { $0.accountId == accountService - .currentAccount?.id - } - }) - .map({items in - if items.isEmpty { - return nil - } - return "\(items.count)"}) - } -} diff --git a/Ring/Ring/UI/CustomSearchBar.swift b/Ring/Ring/UI/CustomSearchBar.swift new file mode 100644 index 0000000000000000000000000000000000000000..e28462d520ae2203a9e5c8c0df07948aa4adc7f0 --- /dev/null +++ b/Ring/Ring/UI/CustomSearchBar.swift @@ -0,0 +1,163 @@ +/* +* Copyright (C) 2021 Savoir-faire Linux Inc. +* +* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +import UIKit +import RxSwift + +class CustomSearchBar: UISearchBar { + var rightButton = UIButton() + let trailing: CGFloat = -50 + let trailing1: CGFloat = -50.5 + let leading: CGFloat = 15 + let trailingEditing: CGFloat = -80 + let trailingEditing1: CGFloat = -80.5 + let buttonOriginXOffset: CGFloat = -49 + let buttonSize: CGFloat = 40 + let disposeBag = DisposeBag() + + var rightMargin: CGFloat { + let orientation = UIDevice.current.orientation + let margin: CGFloat = UIDevice.current.hasNotch && (orientation == .landscapeRight || orientation == .landscapeLeft) ? -50 : 0 + return margin + } + + var currentTrailing: CGFloat { + if #available(iOS 13.0, *) { + return trailing + } + let trailingConst = searchFieldTrailing.constant + if trailingConst == trailing { + return trailing1 + } + return trailing + } + + var currentTrailingEditing: CGFloat { + if #available(iOS 13.0, *) { + return trailingEditing + } + let trailingConst = searchFieldTrailing.constant + if trailingConst == trailingEditing { + return trailingEditing1 + } + return trailingEditing + } + + var leftMargin: CGFloat { + let orientation = UIDevice.current.orientation + let margin: CGFloat = UIDevice.current.hasNotch && (orientation == .landscapeRight || orientation == .landscapeLeft) ? 60 : 15 + return margin + } + + var searchFieldTrailing = NSLayoutConstraint() + var searchFieldLeading = NSLayoutConstraint() + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + init() { + super.init(frame: CGRect.zero) + } + func sizeChanged(to size: CGFloat) { + var buttonFrame = rightButton.frame + let margin = rightMargin + buttonFrame.origin.x = size + buttonOriginXOffset + margin + rightButton.frame = buttonFrame + if margin == 0 { + searchFieldTrailing.constant = rightButton.isHidden ? currentTrailingEditing : currentTrailing + } else { + searchFieldTrailing.constant += margin + } + searchFieldLeading.constant = leftMargin + } + + func updateImage(buttonImage: UIImage) { + rightButton.setImage(buttonImage, for: .normal) + } + + func configure(buttonImage: UIImage, buttonPressed: @escaping (() -> Void)) { + rightButton = UIButton(frame: CGRect(x: self.frame.size.width + buttonOriginXOffset, y: 3, width: buttonSize, height: buttonSize)) + rightButton.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + rightButton.setImage(buttonImage, for: .normal) + rightButton.tintColor = UIColor.jamiMain + self.addSubview(rightButton) + rightButton.translatesAutoresizingMaskIntoConstraints = true + if #available(iOS 13.0, *) { + self.searchTextField.translatesAutoresizingMaskIntoConstraints = false + searchFieldTrailing = self.searchTextField.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: currentTrailing) + searchFieldTrailing.isActive = true + searchFieldLeading = self.searchTextField.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: leading) + searchFieldLeading.isActive = true + self.searchTextField.topAnchor.constraint(equalTo: self.topAnchor, constant: 7).isActive = true + } else { + for view in subviews { + if let searchField = view as? UITextField { + searchField.translatesAutoresizingMaskIntoConstraints = false + searchFieldTrailing = searchField.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: currentTrailing) + searchFieldTrailing.isActive = true + searchField.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true + searchField.topAnchor.constraint(equalTo: self.topAnchor, constant: 7).isActive = true + } else { + for sView in view.subviews { + if let searchField = sView as? UITextField { + searchField.translatesAutoresizingMaskIntoConstraints = false + searchFieldTrailing = searchField.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: currentTrailing) + searchFieldTrailing.isActive = true + searchField.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true + searchField.topAnchor.constraint(equalTo: self.topAnchor, constant: 7).isActive = true + } + } + } + } + } + rightButton.rx.tap + .throttle(Durations.halfSecond.toTimeInterval(), scheduler: MainScheduler.instance) + .subscribe(onNext: { buttonPressed() }) + .disposed(by: self.disposeBag) + self.rx.textDidBeginEditing + .subscribe(onNext: { [weak self] in + self?.hideRightButton() + }) + .disposed(by: self.disposeBag) + self.rx.textDidEndEditing + .subscribe(onNext: { [weak self] in + self?.showRightButton() + }) + .disposed(by: self.disposeBag) + } + + func hideRightButton() { + rightButton.isHidden = true + rightButton.isEnabled = false + searchFieldTrailing.constant = currentTrailingEditing + searchFieldTrailing.constant += rightMargin + } + + func showRightButton() { + rightButton.isHidden = false + rightButton.isEnabled = true + searchFieldTrailing.constant = currentTrailing + searchFieldTrailing.constant += rightMargin + } + + func hideButton(hide: Bool) { + rightButton.isHidden = hide + } +} diff --git a/Ring/Ring/UI/CustomSearchController.swift b/Ring/Ring/UI/CustomSearchController.swift new file mode 100644 index 0000000000000000000000000000000000000000..bdb4acac4815037f212b2059afae8e33ee9e20be --- /dev/null +++ b/Ring/Ring/UI/CustomSearchController.swift @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2021 Savoir-faire Linux Inc. +* +* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +import UIKit + +class CustomSearchController: UISearchController { + private var customSearchBar = CustomSearchBar() + override var searchBar: UISearchBar { + return customSearchBar + } + + func configureSearchBar(image: UIImage, buttonPressed: @escaping (() -> Void)) { + customSearchBar.configure(buttonImage: image, buttonPressed: buttonPressed) + } + + func updateSearchBar(image: UIImage) { + customSearchBar.updateImage(buttonImage: image) + } + func sizeChanged(to size: CGFloat) { + customSearchBar.sizeChanged(to: size) + } + func hideButton(hide: Bool) { + customSearchBar.hideButton(hide: hide) + } +}