From 6e8af91439d78cffa1e069749a5f7ac84f11e656 Mon Sep 17 00:00:00 2001 From: fmodf Date: Tue, 3 Sep 2024 17:11:58 +0200 Subject: [PATCH] wip --- .../AppData/Model/Message+OMEMO.swift | 5 + old/AppCore/Actions/AccountsActions.swift | 12 - old/AppCore/Actions/AppActions.swift | 15 - old/AppCore/Actions/ChatsActions.swift | 10 - old/AppCore/Actions/ConversationActions.swift | 10 - old/AppCore/Actions/DatabaseActions.swift | 12 - old/AppCore/Actions/FileActions.swift | 17 - old/AppCore/Actions/RostersActions.swift | 12 - old/AppCore/Actions/SharingActions.swift | 21 - old/AppCore/Actions/StartActions.swift | 5 - old/AppCore/Actions/XMPPActions.swift | 17 - old/AppCore/AppStore.swift | 102 - .../Database+Martin/Database+Martin.swift | 7 - .../Database+MartinChannelManager.swift | 21 - .../Database+MartinChatManager.swift | 72 - .../Database+MartinRoomManager.swift | 105 - .../Database+MartinRosterManager.swift | 153 - .../Database/Database+Migrations.swift | 90 - old/AppCore/Database/Database.swift | 55 - old/AppCore/Files/DownloadManager.swift | 48 - old/AppCore/Files/FileProcessing.swift | 302 - .../Middlewares/AccountsMiddleware.swift | 69 - .../ArchivedMessagesMiddleware.swift | 49 - old/AppCore/Middlewares/ChatsMiddleware.swift | 34 - .../Middlewares/ConversationMiddleware.swift | 25 - .../Middlewares/DatabaseMiddleware.swift | 530 -- old/AppCore/Middlewares/FileMiddleware.swift | 141 - .../Middlewares/LoggerMiddleware.swift | 69 - .../Middlewares/RostersMiddleware.swift | 16 - .../Middlewares/SharingMiddleware.swift | 131 - old/AppCore/Middlewares/StartMiddleware.swift | 32 - old/AppCore/Middlewares/XMPPMiddleware.swift | 160 - old/AppCore/Models/Account.swift | 22 - old/AppCore/Models/Channel.swift | 15 - old/AppCore/Models/Chat.swift | 19 - old/AppCore/Models/ConnectionStatus.swift | 27 - old/AppCore/Models/Message.swift | 128 - old/AppCore/Models/Room.swift | 16 - old/AppCore/Models/Roster.swift | 62 - old/AppCore/Models/ServerFeature.swift | 10 - old/AppCore/Reducers/AccountsReducer.swift | 25 - old/AppCore/Reducers/AppReducer.swift | 35 - old/AppCore/Reducers/ChatsReducer.swift | 14 - .../Reducers/ConversationReducer.swift | 24 - old/AppCore/Reducers/RostersReducer.swift | 25 - old/AppCore/Reducers/SharingReducer.swift | 22 - old/AppCore/Reducers/StartReducer.swift | 11 - old/AppCore/State/AccountsState.swift | 20 - old/AppCore/State/AppState.swift | 39 - old/AppCore/State/ChatsState.swift | 11 - old/AppCore/State/ConversationState.swift | 15 - old/AppCore/State/RostersState.swift | 15 - old/AppCore/State/SharingState.swift | 32 - old/AppCore/State/StartState.swift | 15 - old/AppCore/XMPP/XMPPService.swift | 266 - old/Generated/.gitignore | 2 - old/Helpers/Bool+Extensions.swift | 7 - old/Helpers/Const.swift | 53 - old/Helpers/Map+Extensions.swift | 16 - old/Helpers/Set+Extensions.swift | 26 - old/Helpers/String+Extensions.swift | 106 - old/Helpers/TimeInterval+Extensions.swift | 9 - old/Helpers/UIApplication+Extensions.swift | 10 - old/Helpers/URL+Extensions.swift | 13 - old/Helpers/UserDefaultsWrapper.swift | 32 - .../Assets/Colors.xcassets/Contents.json | 6 - .../Colors.xcassets/material/Contents.json | 9 - .../material/background/Contents.json | 9 - .../background/dark.colorset/Contents.json | 20 - .../background/light.colorset/Contents.json | 20 - .../material/elements/Contents.json | 9 - .../elements/active.colorset/Contents.json | 20 - .../elements/inactive.colorset/Contents.json | 20 - .../material/shape/Contents.json | 9 - .../shape/alternate.colorset/Contents.json | 20 - .../shape/black.colorset/Contents.json | 20 - .../shape/separator.colorset/Contents.json | 20 - .../shape/white.colorset/Contents.json | 20 - .../material/text/Contents.json | 9 - .../material/text/main.colorset/Contents.json | 20 - .../material/text/sub.colorset/Contents.json | 20 - .../text/white.colorset/Contents.json | 20 - .../Assets/Colors.xcassets/old/Contents.json | 9 - .../old/background/Contents.json | 9 - .../Colors.xcassets/old/primary/Contents.json | 9 - .../old/primary/c100.colorset/Contents.json | 20 - .../old/primary/c200.colorset/Contents.json | 20 - .../old/primary/c400.colorset/Contents.json | 20 - .../old/primary/c50.colorset/Contents.json | 20 - .../primary/c500main.colorset/Contents.json | 20 - .../old/secondary/Contents.json | 9 - .../old/secondary/c100.colorset/Contents.json | 20 - .../old/secondary/c200.colorset/Contents.json | 20 - .../old/secondary/c300.colorset/Contents.json | 20 - .../old/secondary/c400.colorset/Contents.json | 20 - .../old/secondary/c50.colorset/Contents.json | 20 - .../secondary/c500main.colorset/Contents.json | 20 - .../old/secondary/c600.colorset/Contents.json | 20 - .../old/secondary/c700.colorset/Contents.json | 20 - .../old/secondary/c800.colorset/Contents.json | 20 - .../old/secondary/c900.colorset/Contents.json | 20 - .../Colors.xcassets/old/text/Contents.json | 9 - .../old/text/main.colorset/Contents.json | 20 - .../old/text/sub.colorset/Contents.json | 20 - .../Colors.xcassets/rainbow/Contents.json | 9 - .../rainbow/blue200.colorset/Contents.json | 20 - .../rainbow/blue300.colorset/Contents.json | 20 - .../rainbow/blue500.colorset/Contents.json | 20 - .../rainbow/blue800.colorset/Contents.json | 20 - .../blueDark200.colorset/Contents.json | 20 - .../blueDark300.colorset/Contents.json | 20 - .../blueDark500.colorset/Contents.json | 20 - .../blueDark800.colorset/Contents.json | 20 - .../blueLight200.colorset/Contents.json | 20 - .../blueLight300.colorset/Contents.json | 20 - .../blueLight500.colorset/Contents.json | 20 - .../blueLight800.colorset/Contents.json | 20 - .../rainbow/brown200.colorset/Contents.json | 20 - .../rainbow/brown300.colorset/Contents.json | 20 - .../rainbow/brown500.colorset/Contents.json | 20 - .../rainbow/brown800.colorset/Contents.json | 20 - .../greenDark100.colorset/Contents.json | 20 - .../greenDark200.colorset/Contents.json | 20 - .../greenDark300.colorset/Contents.json | 20 - .../greenDark500.colorset/Contents.json | 20 - .../greenDark800.colorset/Contents.json | 20 - .../greenLight200.colorset/Contents.json | 20 - .../greenLight300.colorset/Contents.json | 20 - .../greenLight500.colorset/Contents.json | 20 - .../greenLight800.colorset/Contents.json | 20 - .../magentaDark200.colorset/Contents.json | 20 - .../magentaDark300.colorset/Contents.json | 20 - .../magentaDark500.colorset/Contents.json | 20 - .../magentaDark800.colorset/Contents.json | 20 - .../magentaLight200.colorset/Contents.json | 20 - .../magentaLight300.colorset/Contents.json | 20 - .../magentaLight500.colorset/Contents.json | 20 - .../magentaLight800.colorset/Contents.json | 20 - .../orangeDark200.colorset/Contents.json | 20 - .../orangeDark300.colorset/Contents.json | 20 - .../orangeDark500.colorset/Contents.json | 20 - .../orangeDark800.colorset/Contents.json | 20 - .../orangeLight200.colorset/Contents.json | 20 - .../orangeLight300.colorset/Contents.json | 20 - .../orangeLight500.colorset/Contents.json | 20 - .../orangeLight800.colorset/Contents.json | 20 - .../rainbow/pink200.colorset/Contents.json | 20 - .../rainbow/pink300.colorset/Contents.json | 20 - .../rainbow/pink500.colorset/Contents.json | 20 - .../rainbow/pink800.colorset/Contents.json | 20 - .../rainbow/red200.colorset/Contents.json | 20 - .../rainbow/red300.colorset/Contents.json | 20 - .../rainbow/red500.colorset/Contents.json | 20 - .../rainbow/red800.colorset/Contents.json | 20 - .../tortoiseDark200.colorset/Contents.json | 20 - .../tortoiseDark300.colorset/Contents.json | 20 - .../tortoiseDark500.colorset/Contents.json | 20 - .../tortoiseDark800.colorset/Contents.json | 20 - .../tortoiseLight200.colorset/Contents.json | 20 - .../tortoiseLight300.colorset/Contents.json | 20 - .../tortoiseLight500.colorset/Contents.json | 20 - .../tortoiseLight800.colorset/Contents.json | 20 - .../yellowDark200.colorset/Contents.json | 20 - .../yellowDark300.colorset/Contents.json | 20 - .../yellowDark500.colorset/Contents.json | 20 - .../yellowDark800.colorset/Contents.json | 20 - .../yellowLight200.colorset/Contents.json | 20 - .../yellowLight300.colorset/Contents.json | 20 - .../yellowLight500.colorset/Contents.json | 20 - .../yellowLight800.colorset/Contents.json | 20 - .../AppIcon.appiconset/Contents.json | 14 - .../AppIcon.appiconset/logo2.png | Bin 104462 -> 0 bytes .../Assets/Images.xcassets/Contents.json | 6 - .../logo.imageset/Contents.json | 15 - .../logo.imageset/logo2_wo_bg.png | Bin 152001 -> 0 bytes .../Preview Assets.xcassets/Contents.json | 6 - old/Resources/Strings/Localizable.strings | 76 - old/Resources/launchscreen.storyboard | 49 - old/Resources/server_features.plist | 6598 ----------------- old/View/BaseNavigationView.swift | 39 - old/View/Screens/AddAccountScreen.swift | 122 - .../Screens/Chats/ChatsCreateMainScreen.swift | 182 - old/View/Screens/Chats/ChatsListScreen.swift | 61 - .../Contacts/AddContactOrChannelScreen.swift | 148 - .../Screens/Contacts/ContactsScreen.swift | 172 - .../ConversationMessageContainer.swift | 254 - .../Conversation/ConversationMessageRow.swift | 82 - .../Conversation/ConversationScreen.swift | 198 - .../Conversation/ConversationTextInput.swift | 113 - old/View/Screens/RegistrationScreen.swift | 20 - .../Screens/Settings/SettingsScreen.swift | 20 - .../Sharing/SharingContactsPickerView.swift | 64 - .../Sharing/SharingFilesPickerView.swift | 64 - .../Sharing/SharingLocationPickerView.swift | 134 - .../Sharing/SharingMediaPickerView.swift | 289 - .../Screens/Sharing/SharingPickerScreen.swift | 47 - old/View/Screens/Sharing/SharingTabBar.swift | 85 - old/View/Screens/StartScreen.swift | 19 - old/View/Screens/WelcomeScreen.swift | 53 - old/View/SharedComponents/SharedListRow.swift | 59 - .../SharedNavigationBar.swift | 78 - old/View/SharedComponents/SharedTabBar.swift | 76 - .../UniversalInputCollection.swift | 203 - old/View/UIToolkit/Binding+Extensions.swift | 12 - old/View/UIToolkit/ButtonStyles.swift | 50 - old/View/UIToolkit/Colors+Tappable.swift | 13 - .../UIToolkit/EdgeInsets+Extensions.swift | 15 - .../KeyboardDisposableModifier.swift | 22 - old/View/UIToolkit/Typography.swift | 13 - old/View/UIToolkit/UIImage+Crop.swift | 42 - old/View/UIToolkit/Vibration.swift | 17 - old/View/UIToolkit/View+Debug.swift | 35 - old/View/UIToolkit/View+If.swift | 11 - old/View/UIToolkit/View+Loader.swift | 40 - old/View/UIToolkit/View+OnLoad.swift | 27 - old/View/UIToolkit/View+TappableArea.swift | 27 - project.yml | 1 - 217 files changed, 5 insertions(+), 15120 deletions(-) delete mode 100644 old/AppCore/Actions/AccountsActions.swift delete mode 100644 old/AppCore/Actions/AppActions.swift delete mode 100644 old/AppCore/Actions/ChatsActions.swift delete mode 100644 old/AppCore/Actions/ConversationActions.swift delete mode 100644 old/AppCore/Actions/DatabaseActions.swift delete mode 100644 old/AppCore/Actions/FileActions.swift delete mode 100644 old/AppCore/Actions/RostersActions.swift delete mode 100644 old/AppCore/Actions/SharingActions.swift delete mode 100644 old/AppCore/Actions/StartActions.swift delete mode 100644 old/AppCore/Actions/XMPPActions.swift delete mode 100644 old/AppCore/AppStore.swift delete mode 100644 old/AppCore/Database/Database+Martin/Database+Martin.swift delete mode 100644 old/AppCore/Database/Database+Martin/Database+MartinChannelManager.swift delete mode 100644 old/AppCore/Database/Database+Martin/Database+MartinChatManager.swift delete mode 100644 old/AppCore/Database/Database+Martin/Database+MartinRoomManager.swift delete mode 100644 old/AppCore/Database/Database+Martin/Database+MartinRosterManager.swift delete mode 100644 old/AppCore/Database/Database+Migrations.swift delete mode 100644 old/AppCore/Database/Database.swift delete mode 100644 old/AppCore/Files/DownloadManager.swift delete mode 100644 old/AppCore/Files/FileProcessing.swift delete mode 100644 old/AppCore/Middlewares/AccountsMiddleware.swift delete mode 100644 old/AppCore/Middlewares/ArchivedMessagesMiddleware.swift delete mode 100644 old/AppCore/Middlewares/ChatsMiddleware.swift delete mode 100644 old/AppCore/Middlewares/ConversationMiddleware.swift delete mode 100644 old/AppCore/Middlewares/DatabaseMiddleware.swift delete mode 100644 old/AppCore/Middlewares/FileMiddleware.swift delete mode 100644 old/AppCore/Middlewares/LoggerMiddleware.swift delete mode 100644 old/AppCore/Middlewares/RostersMiddleware.swift delete mode 100644 old/AppCore/Middlewares/SharingMiddleware.swift delete mode 100644 old/AppCore/Middlewares/StartMiddleware.swift delete mode 100644 old/AppCore/Middlewares/XMPPMiddleware.swift delete mode 100644 old/AppCore/Models/Account.swift delete mode 100644 old/AppCore/Models/Channel.swift delete mode 100644 old/AppCore/Models/Chat.swift delete mode 100644 old/AppCore/Models/ConnectionStatus.swift delete mode 100644 old/AppCore/Models/Message.swift delete mode 100644 old/AppCore/Models/Room.swift delete mode 100644 old/AppCore/Models/Roster.swift delete mode 100644 old/AppCore/Models/ServerFeature.swift delete mode 100644 old/AppCore/Reducers/AccountsReducer.swift delete mode 100644 old/AppCore/Reducers/AppReducer.swift delete mode 100644 old/AppCore/Reducers/ChatsReducer.swift delete mode 100644 old/AppCore/Reducers/ConversationReducer.swift delete mode 100644 old/AppCore/Reducers/RostersReducer.swift delete mode 100644 old/AppCore/Reducers/SharingReducer.swift delete mode 100644 old/AppCore/Reducers/StartReducer.swift delete mode 100644 old/AppCore/State/AccountsState.swift delete mode 100644 old/AppCore/State/AppState.swift delete mode 100644 old/AppCore/State/ChatsState.swift delete mode 100644 old/AppCore/State/ConversationState.swift delete mode 100644 old/AppCore/State/RostersState.swift delete mode 100644 old/AppCore/State/SharingState.swift delete mode 100644 old/AppCore/State/StartState.swift delete mode 100644 old/AppCore/XMPP/XMPPService.swift delete mode 100644 old/Generated/.gitignore delete mode 100644 old/Helpers/Bool+Extensions.swift delete mode 100644 old/Helpers/Const.swift delete mode 100644 old/Helpers/Map+Extensions.swift delete mode 100644 old/Helpers/Set+Extensions.swift delete mode 100644 old/Helpers/String+Extensions.swift delete mode 100644 old/Helpers/TimeInterval+Extensions.swift delete mode 100644 old/Helpers/UIApplication+Extensions.swift delete mode 100644 old/Helpers/URL+Extensions.swift delete mode 100644 old/Helpers/UserDefaultsWrapper.swift delete mode 100644 old/Resources/Assets/Colors.xcassets/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/background/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/background/dark.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/background/light.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/elements/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/elements/active.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/elements/inactive.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/shape/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/shape/alternate.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/shape/black.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/shape/separator.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/shape/white.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/text/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/text/main.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/text/sub.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/material/text/white.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/background/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/primary/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/primary/c100.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/primary/c200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/primary/c400.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/primary/c50.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/primary/c500main.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c100.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c400.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c50.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c500main.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c600.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c700.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/secondary/c900.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/text/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/text/main.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/old/text/sub.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blue200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blue300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blue500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blue800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueDark200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueDark300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueDark500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueDark800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueLight200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueLight300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueLight500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/blueLight800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/brown200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/brown300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/brown500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/brown800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenDark100.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenDark200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenDark300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenDark500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenDark800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenLight200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenLight300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenLight500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/greenLight800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaDark200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaDark300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaDark500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaDark800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaLight200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaLight300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaLight500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/magentaLight800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeDark200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeDark300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeDark500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeDark800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeLight200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeLight300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeLight500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/orangeLight800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/pink200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/pink300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/pink500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/pink800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/red200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/red300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/red500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/red800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowDark200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowDark300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowDark500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowDark800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowLight200.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowLight300.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowLight500.colorset/Contents.json delete mode 100644 old/Resources/Assets/Colors.xcassets/rainbow/yellowLight800.colorset/Contents.json delete mode 100644 old/Resources/Assets/Images.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 old/Resources/Assets/Images.xcassets/AppIcon.appiconset/logo2.png delete mode 100644 old/Resources/Assets/Images.xcassets/Contents.json delete mode 100644 old/Resources/Assets/Images.xcassets/logo.imageset/Contents.json delete mode 100644 old/Resources/Assets/Images.xcassets/logo.imageset/logo2_wo_bg.png delete mode 100644 old/Resources/Preview Content/Preview Assets.xcassets/Contents.json delete mode 100644 old/Resources/Strings/Localizable.strings delete mode 100644 old/Resources/launchscreen.storyboard delete mode 100644 old/Resources/server_features.plist delete mode 100644 old/View/BaseNavigationView.swift delete mode 100644 old/View/Screens/AddAccountScreen.swift delete mode 100644 old/View/Screens/Chats/ChatsCreateMainScreen.swift delete mode 100644 old/View/Screens/Chats/ChatsListScreen.swift delete mode 100644 old/View/Screens/Contacts/AddContactOrChannelScreen.swift delete mode 100644 old/View/Screens/Contacts/ContactsScreen.swift delete mode 100644 old/View/Screens/Conversation/ConversationMessageContainer.swift delete mode 100644 old/View/Screens/Conversation/ConversationMessageRow.swift delete mode 100644 old/View/Screens/Conversation/ConversationScreen.swift delete mode 100644 old/View/Screens/Conversation/ConversationTextInput.swift delete mode 100644 old/View/Screens/RegistrationScreen.swift delete mode 100644 old/View/Screens/Settings/SettingsScreen.swift delete mode 100644 old/View/Screens/Sharing/SharingContactsPickerView.swift delete mode 100644 old/View/Screens/Sharing/SharingFilesPickerView.swift delete mode 100644 old/View/Screens/Sharing/SharingLocationPickerView.swift delete mode 100644 old/View/Screens/Sharing/SharingMediaPickerView.swift delete mode 100644 old/View/Screens/Sharing/SharingPickerScreen.swift delete mode 100644 old/View/Screens/Sharing/SharingTabBar.swift delete mode 100644 old/View/Screens/StartScreen.swift delete mode 100644 old/View/Screens/WelcomeScreen.swift delete mode 100644 old/View/SharedComponents/SharedListRow.swift delete mode 100644 old/View/SharedComponents/SharedNavigationBar.swift delete mode 100644 old/View/SharedComponents/SharedTabBar.swift delete mode 100644 old/View/SharedComponents/UniversalInputCollection.swift delete mode 100644 old/View/UIToolkit/Binding+Extensions.swift delete mode 100644 old/View/UIToolkit/ButtonStyles.swift delete mode 100644 old/View/UIToolkit/Colors+Tappable.swift delete mode 100644 old/View/UIToolkit/EdgeInsets+Extensions.swift delete mode 100644 old/View/UIToolkit/KeyboardDisposableModifier.swift delete mode 100644 old/View/UIToolkit/Typography.swift delete mode 100644 old/View/UIToolkit/UIImage+Crop.swift delete mode 100644 old/View/UIToolkit/Vibration.swift delete mode 100644 old/View/UIToolkit/View+Debug.swift delete mode 100644 old/View/UIToolkit/View+If.swift delete mode 100644 old/View/UIToolkit/View+Loader.swift delete mode 100644 old/View/UIToolkit/View+OnLoad.swift delete mode 100644 old/View/UIToolkit/View+TappableArea.swift diff --git a/ConversationsClassic/AppData/Model/Message+OMEMO.swift b/ConversationsClassic/AppData/Model/Message+OMEMO.swift index 3a9c253..538d3e7 100644 --- a/ConversationsClassic/AppData/Model/Message+OMEMO.swift +++ b/ConversationsClassic/AppData/Model/Message+OMEMO.swift @@ -48,6 +48,11 @@ extension Message { } } + // skip for non-visible messages + if martinMessage.body == nil, martinMessage.oob == nil, martinMessage.type == .chat { + return nil + } + // From/To let from = martinMessage.from?.bareJid.stringValue ?? "" let to = martinMessage.to?.bareJid.stringValue diff --git a/old/AppCore/Actions/AccountsActions.swift b/old/AppCore/Actions/AccountsActions.swift deleted file mode 100644 index b2b6890..0000000 --- a/old/AppCore/Actions/AccountsActions.swift +++ /dev/null @@ -1,12 +0,0 @@ -enum AccountsAction: Codable { - case accountsListUpdated(accounts: [Account]) - - case goTo(AccountNavigationState) - - case tryAddAccountWithCredentials(login: String, password: String) - case addAccountError(jid: String, reason: String?) - - case makeAccountPermanent(account: Account) - - case clientServerFeaturesUpdated(jid: String, features: [ServerFeature]) -} diff --git a/old/AppCore/Actions/AppActions.swift b/old/AppCore/Actions/AppActions.swift deleted file mode 100644 index 2cb786d..0000000 --- a/old/AppCore/Actions/AppActions.swift +++ /dev/null @@ -1,15 +0,0 @@ -enum AppAction: Codable { - case info(String) - case flushState - case changeFlow(_ flow: AppFlow) - - case startAction(_ action: StartAction) - case databaseAction(_ action: DatabaseAction) - case accountsAction(_ action: AccountsAction) - case xmppAction(_ action: XMPPAction) - case rostersAction(_ action: RostersAction) - case chatsAction(_ action: ChatsAction) - case conversationAction(_ action: ConversationAction) - case sharingAction(_ action: SharingAction) - case fileAction(_ action: FileAction) -} diff --git a/old/AppCore/Actions/ChatsActions.swift b/old/AppCore/Actions/ChatsActions.swift deleted file mode 100644 index b247cd2..0000000 --- a/old/AppCore/Actions/ChatsActions.swift +++ /dev/null @@ -1,10 +0,0 @@ -enum ChatsAction: Codable { - case chatsListUpdated(chats: [Chat]) - - case startChat(accountJid: String, participantJid: String) - case chatStarted(chat: Chat) - - case createNewChat(accountJid: String, participantJid: String) - case chatCreated(chat: Chat) - case chatCreationFailed(reason: String) -} diff --git a/old/AppCore/Actions/ConversationActions.swift b/old/AppCore/Actions/ConversationActions.swift deleted file mode 100644 index 6bb8b32..0000000 --- a/old/AppCore/Actions/ConversationActions.swift +++ /dev/null @@ -1,10 +0,0 @@ -enum ConversationAction: Codable { - case makeConversationActive(chat: Chat, roster: Roster?) - - case messagesUpdated(messages: [Message]) - - case sendMessage(from: String, to: String, body: String) - case setReplyText(String) - - case sendMediaMessages(from: String, to: String, messagesIds: [String], localFilesNames: [String]) -} diff --git a/old/AppCore/Actions/DatabaseActions.swift b/old/AppCore/Actions/DatabaseActions.swift deleted file mode 100644 index b474cae..0000000 --- a/old/AppCore/Actions/DatabaseActions.swift +++ /dev/null @@ -1,12 +0,0 @@ -enum DatabaseAction: Codable { - case storedAccountsLoaded(accounts: [Account]) - case loadingStoredAccountsFailed - case updateAccountFailed - - case storedRostersLoaded(rosters: [Roster]) - case storedChatsLoaded(chats: [Chat]) - - case storeMessageFailed(reason: String) - - case updateAttachmentFailed(id: String, reason: String) -} diff --git a/old/AppCore/Actions/FileActions.swift b/old/AppCore/Actions/FileActions.swift deleted file mode 100644 index 46187c6..0000000 --- a/old/AppCore/Actions/FileActions.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -enum FileAction: Stateable { - case downloadAttachmentFile(messageId: String, attachmentRemotePath: URL) - case attachmentFileDownloaded(messageId: String, localName: String) - case downloadingAttachmentFileFailed(messageId: String, reason: String) - - case createAttachmentThumbnail(messageId: String, localName: String) - case attachmentThumbnailCreated(messageId: String, thumbnailName: String) - - case fetchItemsFromGallery - case itemsFromGalleryFetched(items: [SharingGalleryItem]) - - case copyGalleryItemsForUploading(items: [SharingGalleryItem]) - case copyCameraCapturedForUploading(media: Data, type: SharingCameraMediaType) - case itemsCopiedForUploading(newMessageIds: [String], localNames: [String]) -} diff --git a/old/AppCore/Actions/RostersActions.swift b/old/AppCore/Actions/RostersActions.swift deleted file mode 100644 index b4ba796..0000000 --- a/old/AppCore/Actions/RostersActions.swift +++ /dev/null @@ -1,12 +0,0 @@ -enum RostersAction: Codable { - case addRoster(ownerJID: String, contactJID: String, name: String?, groups: [String]) - case addRosterDone(jid: String) - case addRosterError(reason: String) - - case rostersListUpdated([Roster]) - - case markRosterAsLocallyDeleted(ownerJID: String, contactJID: String) - case unmarkRosterAsLocallyDeleted(ownerJID: String, contactJID: String) - case deleteRoster(ownerJID: String, contactJID: String) - case rosterDeletingFailed(reason: String) -} diff --git a/old/AppCore/Actions/SharingActions.swift b/old/AppCore/Actions/SharingActions.swift deleted file mode 100644 index 6d8d0ee..0000000 --- a/old/AppCore/Actions/SharingActions.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -enum SharingAction: Stateable { - case showSharing(Bool) - - case shareLocation(lat: Double, lon: Double) - case shareContact(jid: String) - case shareDocuments([Data], [String]) - case shareMedia(ids: [String]) - - case checkCameraAccess - case setCameraAccess(Bool) - - case checkGalleryAccess - case setGalleryAccess(Bool) - case galleryItemsUpdated(items: [SharingGalleryItem]) - - case cameraCaptured(media: Data, type: SharingCameraMediaType) - - case retrySharing(messageId: String) -} diff --git a/old/AppCore/Actions/StartActions.swift b/old/AppCore/Actions/StartActions.swift deleted file mode 100644 index 7d41c7c..0000000 --- a/old/AppCore/Actions/StartActions.swift +++ /dev/null @@ -1,5 +0,0 @@ -enum StartAction: Codable { - case loadStoredAccounts - - case goTo(StartNavigationState) -} diff --git a/old/AppCore/Actions/XMPPActions.swift b/old/AppCore/Actions/XMPPActions.swift deleted file mode 100644 index 8876ad3..0000000 --- a/old/AppCore/Actions/XMPPActions.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -enum XMPPAction: Codable { - case clientConnectionChanged(jid: String, state: ConnectionStatus) - case xmppMessageReceived(Message) - - case xmppMessageSent(Message) - case xmppMessageSendFailed(msgId: String) - case xmppMessageSendSuccess(msgId: String) - - case xmppSharingTryUpload(Message) - case xmppSharingUploadFailed(msgId: String, reason: String) - case xmppSharingUploadSuccess(msgId: String, attachmentRemotePath: String) - case serverFeaturesLoaded(jid: String, features: [String]) - - case xmppLoadArchivedMessages(jid: String, to: String?, fromDate: Date) -} diff --git a/old/AppCore/AppStore.swift b/old/AppCore/AppStore.swift deleted file mode 100644 index 11ad860..0000000 --- a/old/AppCore/AppStore.swift +++ /dev/null @@ -1,102 +0,0 @@ -// This file declare global state object for whole app -// and reducers/actions/middleware types. Core of app. -import Combine -import Foundation - -typealias Stateable = Codable & Equatable -typealias AppStore = Store -typealias Reducer = (inout State, Action) -> Void -typealias Middleware = (State, Action) -> AnyPublisher? - -final class Store: ObservableObject { - @Published private(set) var state: State - - // Serial queue for performing any actions sequentially - private let serialQueue = DispatchQueue(label: "im.narayana.conversations.classic.serial.queue", qos: .userInteractive) - private let middlewareQueue = DispatchQueue(label: "im.narayana.conversations.classic.middleware.queue", qos: .default, attributes: .concurrent) - - private let reducer: Reducer - private let middlewares: [Middleware] - private var middlewareCancellables: Set = [] - - // Init - init( - initialState: State, - reducer: @escaping Reducer, - middlewares: [Middleware] = [] - ) { - state = initialState - self.reducer = reducer - self.middlewares = middlewares - } - - // Run reducers/middlewares - func dispatch(_ action: Action) { - if !Thread.isMainThread { - print("❌WARNING!: AppStore.dispatch should be called from the main thread") - } - serialQueue.sync { [weak self] in - guard let wSelf = self else { return } - let newState = wSelf.dispatch(wSelf.state, action) - wSelf.state = newState - } - } - - private func dispatch(_ currentState: State, _ action: Action) -> State { - // Do reducing - var startTime = CFAbsoluteTimeGetCurrent() - var newState = currentState - reducer(&newState, action) - var timeElapsed = CFAbsoluteTimeGetCurrent() - startTime - if timeElapsed > 0.05 { - #if DEBUG - print( - """ - -- - (Ignore this warning ONLY in case, when execution is paused by your breakpoint) - 🕐Execution time: \(timeElapsed) - ❌WARNING! Some reducers work too long! It will lead to issues in production build! - Because of execution each action is synchronous the any stuck will reduce performance dramatically. - Probably you need check which part of reducer/middleware should be async (wrapped with Futures, as example) - -- - """ - ) - #else - #endif - } - - // Dispatch all middleware functions - for middleware in middlewares { - guard let middleware = middleware(newState, action) else { - break - } - startTime = CFAbsoluteTimeGetCurrent() - middleware - .subscribe(on: middlewareQueue) - .receive(on: DispatchQueue.main) - .sink(receiveValue: { [weak self] action in - self?.dispatch(action) - }) - .store(in: &middlewareCancellables) - timeElapsed = CFAbsoluteTimeGetCurrent() - startTime - if timeElapsed > 0.05 { - #if DEBUG - print( - """ - -- - (Ignore this warning ONLY in case, when execution is paused by your breakpoint) - 🕐Execution time: \(timeElapsed) - ❌WARNING! Middleware work too long! It will lead to issues in production build! - Because of execution each action is synchronous the any stuck will reduce performance dramatically. - Probably you need check which part of reducer/middleware should be async (wrapped with Futures, as example) - -- - """ - ) - #else - #endif - } - } - - return newState - } -} diff --git a/old/AppCore/Database/Database+Martin/Database+Martin.swift b/old/AppCore/Database/Database+Martin/Database+Martin.swift deleted file mode 100644 index aec3ef4..0000000 --- a/old/AppCore/Database/Database+Martin/Database+Martin.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation -import GRDB -import Martin - -extension Database: MartinsManager {} - -// Check specific implementation in Database+Martin* files diff --git a/old/AppCore/Database/Database+Martin/Database+MartinChannelManager.swift b/old/AppCore/Database/Database+Martin/Database+MartinChannelManager.swift deleted file mode 100644 index bac242c..0000000 --- a/old/AppCore/Database/Database+Martin/Database+MartinChannelManager.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation -import GRDB -import Martin - -extension Database: Martin.ChannelManager { - func channels(for _: Martin.Context) -> [any Martin.ChannelProtocol] { - [] - } - - func createChannel(for _: Martin.Context, with _: Martin.BareJID, participantId _: String, nick _: String?, state _: Martin.ChannelState) -> Martin.ConversationCreateResult { - .none - } - - func channel(for _: Martin.Context, with _: Martin.BareJID) -> (any Martin.ChannelProtocol)? { - nil - } - - func close(channel _: any Martin.ChannelProtocol) -> Bool { - false - } -} diff --git a/old/AppCore/Database/Database+Martin/Database+MartinChatManager.swift b/old/AppCore/Database/Database+Martin/Database+MartinChatManager.swift deleted file mode 100644 index 6f795f9..0000000 --- a/old/AppCore/Database/Database+Martin/Database+MartinChatManager.swift +++ /dev/null @@ -1,72 +0,0 @@ -import Foundation -import GRDB -import Martin - -extension Database: Martin.ChatManager { - func chats(for context: Martin.Context) -> [any Martin.ChatProtocol] { - do { - let chats: [Chat] = try _db.read { db in - try Chat.filter(Column("account") == context.userBareJid.stringValue).fetchAll(db) - } - return chats.map { chat in - Martin.ChatBase(context: context, jid: BareJID(chat.participant)) - } - } catch { - logIt(.error, "Error fetching chats: \(error.localizedDescription)") - return [] - } - } - - func chat(for context: Martin.Context, with: Martin.BareJID) -> (any Martin.ChatProtocol)? { - do { - let chat: Chat? = try _db.read { db in - try Chat - .filter(Column("account") == context.userBareJid.stringValue) - .filter(Column("participant") == with.stringValue) - .fetchOne(db) - } - if chat != nil { - return Martin.ChatBase(context: context, jid: with) - } else { - return nil - } - } catch { - logIt(.error, "Error fetching chat: \(error.localizedDescription)") - return nil - } - } - - func createChat(for context: Martin.Context, with: Martin.BareJID) -> (any Martin.ChatProtocol)? { - do { - let chat: Chat? = try _db.read { db in - try Chat - .filter(Column("account") == context.userBareJid.stringValue) - .filter(Column("participant") == with.stringValue) - .fetchOne(db) - } - if chat != nil { - return Martin.ChatBase(context: context, jid: with) - } else { - let chat = Chat( - id: UUID().uuidString, - account: context.userBareJid.stringValue, - participant: with.stringValue, - type: .chat - ) - try _db.write { db in - try chat.save(db) - } - return Martin.ChatBase(context: context, jid: with) - } - } catch { - logIt(.error, "Error fetching chat: \(error.localizedDescription)") - return nil - } - } - - func close(chat: any Martin.ChatProtocol) -> Bool { - // not used in Martin library for now - print("Closing chat: \(chat)") - return false - } -} diff --git a/old/AppCore/Database/Database+Martin/Database+MartinRoomManager.swift b/old/AppCore/Database/Database+Martin/Database+MartinRoomManager.swift deleted file mode 100644 index 6a399c4..0000000 --- a/old/AppCore/Database/Database+Martin/Database+MartinRoomManager.swift +++ /dev/null @@ -1,105 +0,0 @@ -import Foundation -import GRDB -import Martin - -extension Database: Martin.RoomManager { - func rooms(for context: Martin.Context) -> [any Martin.RoomProtocol] { - do { - let rooms: [Room] = try _db.read { db in - try Room.filter(Column("account") == context.userBareJid.stringValue).fetchAll(db) - } - return rooms.map { room in - Martin.RoomBase( - context: context, - jid: context.userBareJid, - nickname: room.nickname, - password: room.password, - dispatcher: QueueDispatcher(label: "room-\(room.id)") - ) - } - } catch { - logIt(.error, "Error fetching channels: \(error.localizedDescription)") - return [] - } - } - - func room(for context: Martin.Context, with roomJid: Martin.BareJID) -> (any Martin.RoomProtocol)? { - do { - let room: Room? = try _db.read { db in - try Room - .filter(Column("account") == context.userBareJid.stringValue) - .filter(Column("id") == roomJid.stringValue) - .fetchOne(db) - } - if let room { - return Martin.RoomBase( - context: context, - jid: context.userBareJid, - nickname: room.nickname, - password: room.password, - dispatcher: QueueDispatcher(label: "room-\(room.id)") - ) - } else { - return nil - } - } catch { - logIt(.error, "Error fetching room: \(error.localizedDescription)") - return nil - } - } - - func createRoom(for context: Martin.Context, with roomJid: Martin.BareJID, nickname: String, password: String?) -> (any Martin.RoomProtocol)? { - do { - let room: Room? = try _db.read { db in - try Room - .filter(Column("account") == context.userBareJid.stringValue) - .filter(Column("id") == roomJid.stringValue) - .fetchOne(db) - } - if let room { - return Martin.RoomBase( - context: context, - jid: context.userBareJid, - nickname: room.nickname, - password: room.password, - dispatcher: QueueDispatcher(label: "room-\(room.id)") - ) - } else { - let room = Room( - id: roomJid.stringValue, - account: context.userBareJid.stringValue, - nickname: nickname, - password: password - ) - try _db.write { db in - try room.save(db) - } - return Martin.RoomBase( - context: context, - jid: context.userBareJid, - nickname: nickname, - password: password, - dispatcher: QueueDispatcher(label: "room-\(room.id)") - ) - } - } catch { - logIt(.error, "Error fetching room: \(error.localizedDescription)") - return nil - } - } - - func close(room: any Martin.RoomProtocol) -> Bool { - do { - try _db.write { db in - try Room - .filter(Column("account") == room.context?.userBareJid.stringValue ?? "") - .filter(Column("id") == room.jid.stringValue) - .deleteAll(db) - } - return true - } catch { - logIt(.error, "Error closing room: \(error.localizedDescription)") - return false - } - } -} diff --git a/old/AppCore/Database/Database+Martin/Database+MartinRosterManager.swift b/old/AppCore/Database/Database+Martin/Database+MartinRosterManager.swift deleted file mode 100644 index 194dc29..0000000 --- a/old/AppCore/Database/Database+Martin/Database+MartinRosterManager.swift +++ /dev/null @@ -1,153 +0,0 @@ -import Foundation -import GRDB -import Martin - -extension Database: Martin.RosterManager { - func clear(for context: Martin.Context) { - print("Clearing roster for context: \(context)") - do { - try _db.write { db in - try Roster - .filter(Column("bareJid") == context.userBareJid.stringValue) - .deleteAll(db) - - try RosterVersion - .filter(Column("bareJid") == context.userBareJid.stringValue) - .deleteAll(db) - } - } catch { - logIt(.error, "Error clearing roster: \(error.localizedDescription)") - } - } - - func items(for context: Martin.Context) -> [any Martin.RosterItemProtocol] { - do { - let rosters: [Roster] = try _db.read { db in - try Roster.filter(Column("bareJid") == context.userBareJid.stringValue).fetchAll(db) - } - return rosters.map { roster in - RosterItemBase( - jid: JID(roster.bareJid), - name: roster.name, - subscription: RosterItemSubscription(rawValue: roster.subscription) ?? .none, - groups: roster.data.groups, - ask: roster.ask, - annotations: roster.data.annotations - ) - } - } catch { - logIt(.error, "Error fetching roster items: \(error.localizedDescription)") - return [] - } - } - - func item(for context: Martin.Context, jid: Martin.JID) -> (any Martin.RosterItemProtocol)? { - do { - let roster: Roster? = try _db.read { db in - try Roster - .filter(Column("bareJid") == context.userBareJid.stringValue) - .filter(Column("contactBareJid") == jid.stringValue) - .fetchOne(db) - } - if let roster { - return RosterItemBase( - jid: JID(roster.bareJid), - name: roster.name, - subscription: RosterItemSubscription(rawValue: roster.subscription) ?? .none, - groups: roster.data.groups, - ask: roster.ask, - annotations: roster.data.annotations - ) - } else { - return nil - } - } catch { - logIt(.error, "Error fetching roster item: \(error.localizedDescription)") - return nil - } - } - - func updateItem(for context: Martin.Context, jid: Martin.JID, name: String?, subscription: Martin.RosterItemSubscription, groups: [String], ask: Bool, annotations: [Martin.RosterItemAnnotation]) -> (any Martin.RosterItemProtocol)? { - do { - let roster = Roster( - bareJid: context.userBareJid.stringValue, - contactBareJid: jid.stringValue, - name: name, - subscription: subscription.rawValue, - ask: ask, - data: DBRosterData( - groups: groups, - annotations: annotations - ) - ) - try _db.write { db in - try roster.save(db) - } - return RosterItemBase(jid: jid, name: name, subscription: subscription, groups: groups, ask: ask, annotations: annotations) - } catch { - logIt(.error, "Error updating roster item: \(error.localizedDescription)") - return nil - } - } - - func deleteItem(for context: Martin.Context, jid: Martin.JID) -> (any Martin.RosterItemProtocol)? { - do { - let roster: Roster? = try _db.read { db in - try Roster - .filter(Column("bareJid") == context.userBareJid.stringValue) - .filter(Column("contactBareJid") == jid.stringValue) - .fetchOne(db) - } - if let roster { - _ = try _db.write { db in - try roster.delete(db) - } - return RosterItemBase( - jid: JID(roster.bareJid), - name: roster.name, - subscription: RosterItemSubscription(rawValue: roster.subscription) ?? .none, - groups: roster.data.groups, - ask: roster.ask, - annotations: roster.data.annotations - ) - } else { - return nil - } - } catch { - logIt(.error, "Error fetching roster version: \(error.localizedDescription)") - return nil - } - } - - func version(for context: Martin.Context) -> String? { - do { - let version: RosterVersion? = try _db.read { db in - try RosterVersion - .filter(Column("bareJid") == context.userBareJid.stringValue) - .fetchOne(db) - } - return version?.version - } catch { - logIt(.error, "Error fetching roster version: \(error.localizedDescription)") - return nil - } - } - - func set(version: String?, for context: Martin.Context) { - guard let version else { return } - do { - try _db.write { db in - let rosterVersion = RosterVersion( - bareJid: context.userBareJid.stringValue, - version: version - ) - try rosterVersion.save(db) - } - } catch { - logIt(.error, "Error setting roster version: \(error.localizedDescription)") - } - } - - func initialize(context _: Martin.Context) {} - func deinitialize(context _: Martin.Context) {} -} diff --git a/old/AppCore/Database/Database+Migrations.swift b/old/AppCore/Database/Database+Migrations.swift deleted file mode 100644 index c0336d3..0000000 --- a/old/AppCore/Database/Database+Migrations.swift +++ /dev/null @@ -1,90 +0,0 @@ -import Foundation -import GRDB - -extension Database { - static var migrator: DatabaseMigrator = { - var migrator = DatabaseMigrator() - - // flush db on schema change (only in DEV mode) - #if DEBUG - migrator.eraseDatabaseOnSchemaChange = true - #endif - - // 1st migration - basic tables - migrator.registerMigration("Add basic tables") { db in - // accounts - try db.create(table: "accounts", options: [.ifNotExists]) { table in - table.column("bareJid", .text).notNull().primaryKey().unique(onConflict: .replace) - table.column("pass", .text).notNull() - table.column("isActive", .boolean).notNull().defaults(to: true) - table.column("isTemp", .boolean).notNull().defaults(to: false) - } - - // rosters - try db.create(table: "rosterVersions", options: [.ifNotExists]) { table in - table.column("bareJid", .text).notNull().primaryKey().unique(onConflict: .replace) - table.column("version", .text).notNull() - } - try db.create(table: "rosters", options: [.ifNotExists]) { table in - table.column("bareJid", .text).notNull() - table.column("contactBareJid", .text).notNull() - table.column("name", .text) - table.column("subscription", .text).notNull() - table.column("ask", .boolean).notNull().defaults(to: false) - table.column("data", .text).notNull() - table.primaryKey(["bareJid", "contactBareJid"], onConflict: .replace) - table.column("locallyDeleted", .boolean).notNull().defaults(to: false) - } - - // chats - try db.create(table: "chats", options: [.ifNotExists]) { table in - table.column("id", .text).notNull().primaryKey().unique(onConflict: .replace) - table.column("account", .text).notNull() - table.column("participant", .text).notNull() - table.column("type", .integer).notNull() - } - - // messages - try db.create(table: "messages", options: [.ifNotExists]) { table in - table.column("id", .text).notNull().primaryKey().unique(onConflict: .replace) - table.column("type", .text).notNull() - table.column("contentType", .text).notNull() - table.column("from", .text).notNull() - table.column("to", .text) - table.column("body", .text) - table.column("subject", .text) - table.column("thread", .text) - table.column("oobUrl", .text) - table.column("date", .datetime).notNull() - table.column("pending", .boolean).notNull() - table.column("sentError", .boolean).notNull() - table.column("attachmentType", .integer) - table.column("attachmentLocalName", .text) - table.column("attachmentRemotePath", .text) - table.column("attachmentThumbnailName", .text) - table.column("attachmentDownloadFailed", .boolean).notNull().defaults(to: false) - } - } - - // 2nd migration - channels/rooms - migrator.registerMigration("Add channels/rooms") { db in - // rooms - try db.create(table: "rooms", options: [.ifNotExists]) { table in - table.column("id", .text).notNull().primaryKey().unique(onConflict: .replace) - table.column("account", .text).notNull() - table.column("nickname", .text).notNull() - table.column("password", .text) - } - - // channels - // try db.create(table: "channels", options: [.ifNotExists]) { table in - // table.column("id", .text).notNull().primaryKey().unique(onConflict: .replace) - // table.column("account", .text).notNull() - // table.column("channel", .text).notNull() - // } - } - - // return migrator - return migrator - }() -} diff --git a/old/AppCore/Database/Database.swift b/old/AppCore/Database/Database.swift deleted file mode 100644 index dc06f02..0000000 --- a/old/AppCore/Database/Database.swift +++ /dev/null @@ -1,55 +0,0 @@ -import Combine -import Foundation -import GRDB -import SwiftUI - -// MARK: - Models protocol -typealias DBStorable = Codable & FetchableRecord & Identifiable & PersistableRecord & TableRecord - -// MARK: - Database init -final class Database { - static let shared = Database() - let _db: DatabaseQueue - - private init() { - do { - // Create db folder if not exists - let fileManager = FileManager.default - let appSupportURL = try fileManager.url( - for: .applicationSupportDirectory, in: .userDomainMask, - appropriateFor: nil, create: true - ) - let directoryURL = appSupportURL.appendingPathComponent("ConversationsClassic", isDirectory: true) - try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true) - - // Open or create the database - let databaseURL = directoryURL.appendingPathComponent("db.sqlite") - _db = try DatabaseQueue(path: databaseURL.path, configuration: Database.config) - - // Some debug info - #if DEBUG - print("Database path: \(databaseURL.path)") - #endif - - // Apply migrations - try Database.migrator.migrate(_db) - } catch { - fatalError("Database initialization failed: \(error)") - } - } -} - -// MARK: - Config -private extension Database { - static let config: Configuration = { - var config = Configuration() - #if DEBUG - // verbose and debugging in DEBUG builds only. - config.publicStatementArguments = true - config.prepareDatabase { db in - db.trace { print("SQL> \($0)\n") } - } - #endif - return config - }() -} diff --git a/old/AppCore/Files/DownloadManager.swift b/old/AppCore/Files/DownloadManager.swift deleted file mode 100644 index 67bf06e..0000000 --- a/old/AppCore/Files/DownloadManager.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation - -final class DownloadManager { - static let shared = DownloadManager() - - private let urlSession: URLSession - private let downloadQueue = DispatchQueue(label: "com.example.downloadQueue") - private var activeDownloads = Set() - - init() { - let configuration = URLSessionConfiguration.default - urlSession = URLSession(configuration: configuration) - } - - func enqueueDownload(from url: URL, to localUrl: URL, completion: @escaping (Error?) -> Void) { - downloadQueue.async { - if self.activeDownloads.contains(url) { - print("Download for this file is already in queue.") - return - } - - self.activeDownloads.insert(url) - - let task = self.urlSession.downloadTask(with: url) { tempLocalUrl, _, error in - self.downloadQueue.async { - self.activeDownloads.remove(url) - - guard let tempLocalUrl = tempLocalUrl, error == nil else { - completion(error) - return - } - - do { - if FileManager.default.fileExists(atPath: localUrl.path) { - try FileManager.default.removeItem(at: localUrl) - } - let data = try Data(contentsOf: tempLocalUrl) - try data.write(to: localUrl) - completion(nil) - } catch let writeError { - completion(writeError) - } - } - } - task.resume() - } - } -} diff --git a/old/AppCore/Files/FileProcessing.swift b/old/AppCore/Files/FileProcessing.swift deleted file mode 100644 index 14b0048..0000000 --- a/old/AppCore/Files/FileProcessing.swift +++ /dev/null @@ -1,302 +0,0 @@ -import Foundation -import Photos -import UIKit - -final class FileProcessing { - static let shared = FileProcessing() - - static var fileFolder: URL { - // swiftlint:disable:next force_unwrapping - let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - let subdirectoryURL = documentsURL.appendingPathComponent(Const.fileFolder) - if !FileManager.default.fileExists(atPath: subdirectoryURL.path) { - try? FileManager.default.createDirectory(at: subdirectoryURL, withIntermediateDirectories: true, attributes: nil) - } - return subdirectoryURL - } - - func createThumbnail(localName: String) -> String? { - let thumbnailFileName = "thumb_\(localName)" - let thumbnailUrl = FileProcessing.fileFolder.appendingPathComponent(thumbnailFileName) - let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) - - // check if thumbnail already exists - if FileManager.default.fileExists(atPath: thumbnailUrl.path) { - return thumbnailFileName - } - - // create thumbnail if not exists - switch localName.attachmentType { - case .image: - guard let image = UIImage(contentsOfFile: localUrl.path) else { - print("FileProcessing: Error loading image: \(localUrl)") - return nil - } - let targetSize = CGSize(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) - guard let thumbnail = scaleAndCropImage(image, targetSize) else { - print("FileProcessing: Error scaling image: \(localUrl)") - return nil - } - guard let data = thumbnail.pngData() else { - print("FileProcessing: Error converting thumbnail of \(localUrl) to data") - return nil - } - do { - try data.write(to: thumbnailUrl) - return thumbnailFileName - } catch { - print("FileProcessing: Error writing thumbnail: \(error)") - return nil - } - - default: - return nil - } - } - - func fetchGallery() -> [SharingGalleryItem] { - let items = syncGalleryEnumerate() - .map { - SharingGalleryItem( - id: $0.localIdentifier, - type: $0.mediaType == .image ? .photo : .video, - duration: $0.mediaType == .video ? $0.duration.minAndSec : nil - ) - } - return items - } - - func fillGalleryItemsThumbnails(items: [SharingGalleryItem]) -> [SharingGalleryItem] { - let ids = items - .filter { $0.thumbnail == nil } - .map { $0.id } - - let assets = syncGalleryEnumerate(ids) - return assets.compactMap { asset in - if asset.mediaType == .image { - return syncGalleryProcessImage(asset) { [weak self] image in - if let thumbnail = self?.scaleAndCropImage(image, CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize)) { - let data = thumbnail.jpegData(compressionQuality: 1.0) ?? Data() - return SharingGalleryItem(id: asset.localIdentifier, type: .photo, thumbnail: data) - } else { - return nil - } - } - } else if asset.mediaType == .video { - return syncGalleryProcessVideo(asset) { [weak self] avAsset in - // swiftlint:disable:next force_cast - let assetURL = avAsset as! AVURLAsset - let url = assetURL.url - if let thumbnail = self?.generateVideoThumbnail(url, CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize)) { - let data = thumbnail.jpegData(compressionQuality: 1.0) ?? Data() - return SharingGalleryItem( - id: asset.localIdentifier, - type: .video, - thumbnail: data, - duration: asset.duration.minAndSec - ) - } else { - return nil - } - } - } else { - return nil - } - } - } - - // This function also creates new ids for messages for each new attachment - func copyGalleryItemsForUploading(items: [SharingGalleryItem]) -> [(String, String)] { - let assets = syncGalleryEnumerate(items.map { $0.id }) - return assets - .compactMap { asset in - let newMessageId = UUID().uuidString - let fileId = UUID().uuidString - if asset.mediaType == .image { - return syncGalleryProcessImage(asset) { image in - let localName = "\(newMessageId)_\(fileId).jpg" - let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) - if let data = image.jpegData(compressionQuality: 1.0) { - do { - try data.write(to: localUrl) - return (newMessageId, localName) - } catch { - return nil - } - } else { - return nil - } - } - } else if asset.mediaType == .video { - return syncGalleryProcessVideo(asset) { avAsset in - // swiftlint:disable:next force_cast - let assetURL = avAsset as! AVURLAsset - let url = assetURL.url - let localName = "\(newMessageId)_\(fileId).mov" - let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) - do { - try FileManager.default.copyItem(at: url, to: localUrl) - return (newMessageId, localName) - } catch { - return nil - } - } - } else { - return nil - } - } - } - - // This function also creates new id for file from camera capturing - func copyCameraCapturedForUploading(media: Data, type: SharingCameraMediaType) -> (String, String)? { - let newMessageId = UUID().uuidString - let fileId = UUID().uuidString - let localName: String - switch type { - case .photo: - localName = "\(newMessageId)_\(fileId).jpg" - - case .video: - localName = "\(newMessageId)_\(fileId).mov" - } - let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) - do { - try media.write(to: localUrl) - return (newMessageId, localName) - } catch { - return nil - } - } - - // This function also creates new id for file from document sharing - func copyDocumentsForUploading(data: [Data], extensions: [String]) -> [(String, String)] { - data.enumerated().compactMap { index, data in - let newMessageId = UUID().uuidString - let fileId = UUID().uuidString - let localName = "\(newMessageId)_\(fileId).\(extensions[index])" - let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) - do { - try data.write(to: localUrl) - return (newMessageId, localName) - } catch { - print("FileProcessing: Error writing document: \(error)") - return nil - } - } - } -} - -private extension FileProcessing { - func scaleAndCropImage(_ img: UIImage, _ size: CGSize) -> UIImage? { - let aspect = img.size.width / img.size.height - let targetAspect = size.width / size.height - var newWidth: CGFloat - var newHeight: CGFloat - if aspect < targetAspect { - newWidth = size.width - newHeight = size.width / aspect - } else { - newHeight = size.height - newWidth = size.height * aspect - } - - UIGraphicsBeginImageContextWithOptions(size, false, 0.0) - img.draw(in: CGRect(x: (size.width - newWidth) / 2, y: (size.height - newHeight) / 2, width: newWidth, height: newHeight)) - let newImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - return newImage - } - - func syncGalleryEnumerate(_ ids: [String]? = nil) -> [PHAsset] { - var result: [PHAsset] = [] - - let group = DispatchGroup() - DispatchQueue.global(qos: .userInitiated).sync { - let fetchOptions = PHFetchOptions() - fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] - if let ids { - fetchOptions.predicate = NSPredicate(format: "localIdentifier IN %@", ids) - } - let assets = PHAsset.fetchAssets(with: fetchOptions) - assets.enumerateObjects { asset, _, _ in - group.enter() - result.append(asset) - group.leave() - } - } - group.wait() - return result - } - - func syncGalleryProcess(_ assets: [PHAsset], _ block: @escaping (PHAsset) -> T) -> [T] { - var result: [T] = [] - let group = DispatchGroup() - DispatchQueue.global(qos: .userInitiated).sync { - for asset in assets { - group.enter() - let res = block(asset) - result.append(res) - group.leave() - } - } - group.wait() - return result - } - - func syncGalleryProcessImage(_ asset: PHAsset, _ block: @escaping (UIImage) -> T?) -> T? { - var result: T? - let semaphore = DispatchSemaphore(value: 0) - DispatchQueue.global(qos: .userInitiated).sync { - let options = PHImageRequestOptions() - options.version = .original - options.isSynchronous = true - PHImageManager.default().requestImage( - for: asset, - targetSize: PHImageManagerMaximumSize, - contentMode: .aspectFill, - options: options - ) { image, _ in - if let image { - result = block(image) - } else { - result = nil - } - semaphore.signal() - } - } - semaphore.wait() - return result - } - - func syncGalleryProcessVideo(_ asset: PHAsset, _ block: @escaping (AVAsset) -> T?) -> T? { - var result: T? - let semaphore = DispatchSemaphore(value: 0) - _ = DispatchQueue.global(qos: .userInitiated).sync { - PHImageManager.default().requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in - if let avAsset { - result = block(avAsset) - } else { - result = nil - } - semaphore.signal() - } - } - semaphore.wait() - return result - } - - func generateVideoThumbnail(_ url: URL, _ size: CGSize) -> UIImage? { - let asset = AVAsset(url: url) - let assetImgGenerate = AVAssetImageGenerator(asset: asset) - assetImgGenerate.appliesPreferredTrackTransform = true - let time = CMTimeMakeWithSeconds(Float64(1), preferredTimescale: 600) - do { - let cgImage = try assetImgGenerate.copyCGImage(at: time, actualTime: nil) - let image = UIImage(cgImage: cgImage) - return scaleAndCropImage(image, size) - } catch { - return nil - } - } -} diff --git a/old/AppCore/Middlewares/AccountsMiddleware.swift b/old/AppCore/Middlewares/AccountsMiddleware.swift deleted file mode 100644 index 04eb2db..0000000 --- a/old/AppCore/Middlewares/AccountsMiddleware.swift +++ /dev/null @@ -1,69 +0,0 @@ -import Combine -import Foundation - -final class AccountsMiddleware { - static let shared = AccountsMiddleware() - - private lazy var allFeatures: [ServerFeature] = { - guard - let url = Bundle.main.url(forResource: "server_features", withExtension: "plist"), - let data = try? Data(contentsOf: url), - let loaded = try? PropertyListDecoder().decode([ServerFeature].self, from: data) - else { - return [] - } - return loaded - }() - - func middleware(state: AppState, action: AppAction) -> AnyPublisher { - switch action { - case .databaseAction(.storedAccountsLoaded(let accounts)): - return Just(.accountsAction(.accountsListUpdated(accounts: accounts))) - .eraseToAnyPublisher() - - case .xmppAction(.clientConnectionChanged(let jid, let connectionStatus)): - return Deferred { - Future { promise in - guard let account = state.accountsState.accounts.first(where: { $0.bareJid == jid }) else { - promise(.success(.info("AccountsMiddleware: account not found for jid \(jid)"))) - return - } - if account.isTemp { - switch connectionStatus { - case .connected: - promise(.success(.accountsAction(.makeAccountPermanent(account: account)))) - - case .disconnected(let reason): - if reason != "No error!" { - promise(.success(.accountsAction(.addAccountError(jid: jid, reason: reason)))) - } else { - promise(.success(.info("AccountsMiddleware: account \(jid) disconnected with no error"))) - } - - default: - promise(.success(.info("AccountsMiddleware: account \(jid) connection status changed to \(connectionStatus)"))) - } - } else { - promise(.success(.info("AccountsMiddleware: account \(jid) is not temporary, ignoring"))) - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.serverFeaturesLoaded(let jid, let features)): - return Deferred { - Future { [weak self] promise in - let serverFeatures = features - .compactMap { featureId in - self?.allFeatures.first(where: { $0.xmppId == featureId }) - } - promise(.success(.accountsAction(.clientServerFeaturesUpdated(jid: jid, features: serverFeatures)))) - } - } - .eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/ArchivedMessagesMiddleware.swift b/old/AppCore/Middlewares/ArchivedMessagesMiddleware.swift deleted file mode 100644 index bf0aa08..0000000 --- a/old/AppCore/Middlewares/ArchivedMessagesMiddleware.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Combine -import Foundation - -final class ArchivedMessagesMiddleware { - static let shared = ArchivedMessagesMiddleware() - - func middleware(state _: AppState, action: AppAction) -> AnyPublisher { - switch action { - // case .conversationAction(.messagesUpdated(let messages)): - // if state.conversationsState.archivedMessagesRequested { - // return Empty().eraseToAnyPublisher() - // } else { - // guard let chat = state.conversationsState.currentChat else { - // return Empty().eraseToAnyPublisher() - // } - // return Deferred { - // Future { promise in - // if let currentClient = state.accountsState.accounts.first(where: { $0.bareJid == chat.account }) { - // let features = state.accountsState.discoFeatures[currentClient.bareJid] ?? [] - // if features.map({ $0.xep }).contains("XEP-0313") { - // let roster = state.conversationsState.currentRoster - // let date = self.archivesRequestDate(from: messages) - // promise(.success(.xmppAction(.xmppLoadArchivedMessages(jid: currentClient.bareJid, to: roster?.bareJid, fromDate: date)))) - // } else { - // promise(.success(.info("MessageMiddleware: XEP-0313 not supported for client \(currentClient.bareJid)"))) - // } - // } else { - // promise(.success(.info("MessageMiddleware: No client found for account \(chat.account), probably some error here"))) - // } - // } - // } - // .eraseToAnyPublisher() - // } - - default: - return Empty().eraseToAnyPublisher() - } - } -} - -private extension ArchivedMessagesMiddleware { - func archivesRequestDate(from messages: [Message]) -> Date { - if let lastDate = messages.first?.date { - return lastDate - } else { - return Calendar.current.date(byAdding: .day, value: -Const.mamRequestDaysLength, to: Date()) ?? Date() - } - } -} diff --git a/old/AppCore/Middlewares/ChatsMiddleware.swift b/old/AppCore/Middlewares/ChatsMiddleware.swift deleted file mode 100644 index 797f93d..0000000 --- a/old/AppCore/Middlewares/ChatsMiddleware.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Combine - -final class ChatsMiddleware { - static let shared = ChatsMiddleware() - - func middleware(state: AppState, action: AppAction) -> AnyPublisher { - switch action { - case .databaseAction(.storedChatsLoaded(let chats)): - return Just(.chatsAction(.chatsListUpdated(chats: chats))) - .eraseToAnyPublisher() - - case .chatsAction(.startChat(accountJid: let accountJid, participantJid: let participantJid)): - return Deferred { - Future { promise in - if let exist = state.chatsState.chats.first(where: { $0.account == accountJid && $0.participant == participantJid }) { - // open existing chat - promise(.success(.chatsAction(.chatStarted(chat: exist)))) - } else { - // create new chat - promise(.success(.chatsAction(.createNewChat(accountJid: accountJid, participantJid: participantJid)))) - } - } - } - .eraseToAnyPublisher() - - case .chatsAction(.chatCreated(let chat)): - return Just(.chatsAction(.chatStarted(chat: chat))) - .eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/ConversationMiddleware.swift b/old/AppCore/Middlewares/ConversationMiddleware.swift deleted file mode 100644 index e03839d..0000000 --- a/old/AppCore/Middlewares/ConversationMiddleware.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Combine - -final class ConversationMiddleware { - static let shared = ConversationMiddleware() - - func middleware(state: AppState, action: AppAction) -> AnyPublisher { - switch action { - case .chatsAction(.chatStarted(let chat)): - return Deferred { - Future { promise in - let roster = state.rostersState.rosters - .first { $0.bareJid == chat.account && $0.contactBareJid == chat.participant } - promise(.success(.conversationAction(.makeConversationActive(chat: chat, roster: roster)))) - } - } - .eraseToAnyPublisher() - - case .conversationAction(.makeConversationActive): - return Just(AppAction.changeFlow(.conversation)).eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/DatabaseMiddleware.swift b/old/AppCore/Middlewares/DatabaseMiddleware.swift deleted file mode 100644 index c14dce8..0000000 --- a/old/AppCore/Middlewares/DatabaseMiddleware.swift +++ /dev/null @@ -1,530 +0,0 @@ -import Combine -import Foundation -import GRDB - -// swiftlint:disable:next type_body_length -final class DatabaseMiddleware { - static let shared = DatabaseMiddleware() - private let database = Database.shared - private var cancellables: Set = [] - private var conversationCancellables: Set = [] - - private init() { - // Database changes - ValueObservation - .tracking(Roster.fetchAll) - .publisher(in: database._db, scheduling: .immediate) - .sink { _ in - // Handle completion - } receiveValue: { rosters in - DispatchQueue.main.async { - store.dispatch(.databaseAction(.storedRostersLoaded(rosters: rosters))) - } - } - .store(in: &cancellables) - ValueObservation - .tracking(Chat.fetchAll) - .publisher(in: database._db, scheduling: .immediate) - .sink { _ in - // Handle completion - } receiveValue: { chats in - DispatchQueue.main.async { - store.dispatch(.databaseAction(.storedChatsLoaded(chats: chats))) - } - } - .store(in: &cancellables) - } - - // swiftlint:disable:next function_body_length cyclomatic_complexity - func middleware(state _: AppState, action: AppAction) -> AnyPublisher { - switch action { - // MARK: Accounts - case .startAction(.loadStoredAccounts): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.loadingStoredAccountsFailed))) - return - } - do { - try database._db.read { db in - let accounts = try Account.fetchAll(db) - promise(.success(.databaseAction(.storedAccountsLoaded(accounts: accounts)))) - } - } catch { - promise(.success(.databaseAction(.loadingStoredAccountsFailed))) - } - } - } - } - .eraseToAnyPublisher() - - case .accountsAction(.makeAccountPermanent(let account)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAccountFailed))) - return - } - do { - try database._db.write { db in - // make permanent and store to database - var acc = account - acc.isTemp = false - try acc.insert(db) - - // Re-Fetch all accounts - let accounts = try Account.fetchAll(db) - - // Use the accounts - promise(.success(.databaseAction(.storedAccountsLoaded(accounts: accounts)))) - } - } catch { - promise(.success(.databaseAction(.updateAccountFailed))) - } - } - } - } - .eraseToAnyPublisher() - - // MARK: Rosters - case .rostersAction(.markRosterAsLocallyDeleted(let ownerJID, let contactJID)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.rostersAction(.rosterDeletingFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - do { - _ = try database._db.write { db in - try Roster - .filter(Column("bareJid") == ownerJID) - .filter(Column("contactBareJid") == contactJID) - .updateAll(db, Column("locallyDeleted").set(to: true)) - } - promise(.success(.info("DatabaseMiddleware: roster \(contactJID) for account \(ownerJID) marked as locally deleted"))) - } catch { - promise(.success(.rostersAction(.rosterDeletingFailed(reason: L10n.Global.Error.genericDbError)))) - } - } - } - } - .eraseToAnyPublisher() - - case .rostersAction(.unmarkRosterAsLocallyDeleted(let ownerJID, let contactJID)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.rostersAction(.rosterDeletingFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - do { - _ = try database._db.write { db in - try Roster - .filter(Column("bareJid") == ownerJID) - .filter(Column("contactBareJid") == contactJID) - .updateAll(db, Column("locallyDeleted").set(to: false)) - } - promise(.success(.info("DatabaseMiddleware: roster \(contactJID) for account \(ownerJID) unmarked as locally deleted"))) - } catch { - promise(.success(.rostersAction(.rosterDeletingFailed(reason: L10n.Global.Error.genericDbError)))) - } - } - } - } - .eraseToAnyPublisher() - - // MARK: Chats - case .chatsAction(.createNewChat(let accountJid, let participantJid)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.chatsAction(.chatCreationFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - do { - try database._db.write { db in - let chat = Chat( - id: UUID().uuidString, - account: accountJid, - participant: participantJid, - type: .chat - ) - try chat.insert(db) - promise(.success(.chatsAction(.chatCreated(chat: chat)))) - } - } catch { - promise(.success(.chatsAction(.chatCreationFailed(reason: L10n.Global.Error.genericDbError)))) - } - } - } - } - .eraseToAnyPublisher() - - // MARK: Conversation and messages - case .conversationAction(.makeConversationActive(let chat, _)): - subscribeToMessages(chat: chat) - return Empty().eraseToAnyPublisher() - - case .xmppAction(.xmppMessageReceived(let message)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.storeMessageFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - guard message.contentType != .typing, message.body != nil else { - promise(.success(.info("DatabaseMiddleware: message \(message.id) received as 'typing...' or message body is nil"))) - return - } - do { - try database._db.write { db in - try message.insert(db) - } - promise(.success(.info("DatabaseMiddleware: message \(message.id) stored in db"))) - } catch { - promise(.success(.databaseAction(.storeMessageFailed(reason: error.localizedDescription)))) - } - } - } - } - .eraseToAnyPublisher() - - case .conversationAction(.sendMessage(let from, let to, let body)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.storeMessageFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - do { - let message = Message( - id: UUID().uuidString, - type: .chat, - contentType: .text, - from: from, - to: to, - body: body, - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: true, - sentError: false - ) - try database._db.write { db in - try message.insert(db) - } - promise(.success(.xmppAction(.xmppMessageSent(message)))) - } catch { - promise(.success(.databaseAction(.storeMessageFailed(reason: error.localizedDescription)))) - } - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppMessageSendSuccess(let msgId)): - // mark message as pending false and sentError false - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.storeMessageFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == msgId) - .updateAll(db, Column("pending").set(to: false), Column("sentError").set(to: false)) - } - promise(.success(.info("DatabaseMiddleware: message \(msgId) marked in db as sent"))) - } catch { - promise(.success(.databaseAction(.storeMessageFailed(reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppMessageSendFailed(let msgId)): - // mark message as pending false and sentError true - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.storeMessageFailed(reason: L10n.Global.Error.genericDbError)))) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == msgId) - .updateAll(db, Column("pending").set(to: false), Column("sentError").set(to: true)) - } - promise(.success(.info("DatabaseMiddleware: message \(msgId) marked in db as failed to send"))) - } catch { - promise(.success(.databaseAction(.storeMessageFailed(reason: error.localizedDescription)))) - } - } - } - } - .eraseToAnyPublisher() - - // MARK: Attachments - case .fileAction(.downloadAttachmentFile(let id, _)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == id) - .updateAll(db, Column("attachmentDownloadFailed").set(to: false)) - } - promise(.success(.info("DatabaseMiddleware: message \(id) marked in db as starting downloading attachment"))) - } catch { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .fileAction(.downloadingAttachmentFileFailed(let id, _)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == id) - .updateAll(db, Column("attachmentDownloadFailed").set(to: true)) - } - promise(.success(.info("DatabaseMiddleware: message \(id) marked in db as failed to download attachment"))) - } catch { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .fileAction(.attachmentFileDownloaded(let id, let localName)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == id) - .updateAll(db, Column("attachmentLocalName").set(to: localName), Column("attachmentDownloadFailed").set(to: false)) - } - promise(.success(.info("DatabaseMiddleware: message \(id) marked in db as downloaded attachment"))) - } catch { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .fileAction(.attachmentThumbnailCreated(let id, let thumbnailName)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == id) - .updateAll(db, Column("attachmentThumbnailName").set(to: thumbnailName)) - } - promise(.success(.info("DatabaseMiddleware: message \(id) marked in db as thumbnail created"))) - } catch { - promise(.success(.databaseAction(.updateAttachmentFailed(id: id, reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - // MARK: Sharing - case .conversationAction(.sendMediaMessages(let from, let to, let messageIds, let localFilesNames)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.storeMessageFailed(reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - for (index, id) in messageIds.enumerated() { - let message = Message( - id: id, - type: .chat, - contentType: .attachment, - from: from, - to: to, - body: nil, - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: true, - sentError: false, - attachmentType: localFilesNames[index].attachmentType, - attachmentLocalName: localFilesNames[index] - ) - try database._db.write { db in - try message.insert(db) - } - } - promise(.success(.info("DatabaseMiddleware: messages with sharings stored in db"))) - } catch { - promise(.success(.databaseAction(.storeMessageFailed(reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .sharingAction(.retrySharing(let id)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.storeMessageFailed(reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == id) - .updateAll(db, Column("pending").set(to: true), Column("sentError").set(to: false)) - } - promise(.success(.info("DatabaseMiddleware: message \(id) with shares marked in db as pending to send"))) - } catch { - promise(.success(.databaseAction(.storeMessageFailed(reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppSharingUploadSuccess(let messageId, let remotePath)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAttachmentFailed(id: messageId, reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == messageId) - .updateAll(db, Column("attachmentRemotePath").set(to: remotePath), Column("pending").set(to: false), Column("sentError").set(to: false)) - } - promise(.success(.info("DatabaseMiddleware: shared file uploaded and message \(messageId) marked in db as sent"))) - } catch { - promise(.success(.databaseAction(.updateAttachmentFailed(id: messageId, reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppSharingUploadFailed(let messageId, _)): - return Deferred { - Future { promise in - Task(priority: .background) { [weak self] in - guard let database = self?.database else { - promise(.success(.databaseAction(.updateAttachmentFailed(id: messageId, reason: L10n.Global.Error.genericDbError))) - ) - return - } - do { - _ = try database._db.write { db in - try Message - .filter(Column("id") == messageId) - .updateAll(db, Column("pending").set(to: false), Column("sentError").set(to: true)) - } - promise(.success(.info("DatabaseMiddleware: shared file upload failed and message \(messageId) marked in db as failed to send"))) - } catch { - promise(.success(.databaseAction(.updateAttachmentFailed(id: messageId, reason: error.localizedDescription))) - ) - } - } - } - } - .eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} - -private extension DatabaseMiddleware { - func subscribeToMessages(chat: Chat) { - conversationCancellables = [] - ValueObservation - .tracking( - Message - .filter( - (Column("to") == chat.account && Column("from") == chat.participant) || - (Column("from") == chat.account && Column("to") == chat.participant) - ) - .order(Column("date").desc) - .fetchAll - ) - .publisher(in: database._db, scheduling: .immediate) - .sink { _ in - } receiveValue: { messages in - // messages - DispatchQueue.main.async { - store.dispatch(.conversationAction(.messagesUpdated(messages: messages))) - } - } - .store(in: &conversationCancellables) - } -} diff --git a/old/AppCore/Middlewares/FileMiddleware.swift b/old/AppCore/Middlewares/FileMiddleware.swift deleted file mode 100644 index 8237ac2..0000000 --- a/old/AppCore/Middlewares/FileMiddleware.swift +++ /dev/null @@ -1,141 +0,0 @@ -import Combine -import Foundation -import UIKit - -final class FileMiddleware { - static let shared = FileMiddleware() - private var downloadingMessageIDs = ThreadSafeSet() - - func middleware(state _: AppState, action: AppAction) -> AnyPublisher { - switch action { - // MARK: - For incomig attachments - case .conversationAction(.messagesUpdated(let messages)): - return Deferred { - Future { [weak self] promise in - guard let wSelf = self else { - promise(.success(.info("FileMiddleware: on checking attachments/shares messages, middleware self is nil"))) - return - } - - // for incoming messages with attachments - for message in messages where message.attachmentRemotePath != nil && message.attachmentLocalPath == nil { - if wSelf.downloadingMessageIDs.contains(message.id) { - continue - } - wSelf.downloadingMessageIDs.insert(message.id) - DispatchQueue.main.async { - // swiftlint:disable:next force_unwrapping - store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: message.attachmentRemotePath!))) - } - } - - // for outgoing messages with shared attachments - for message in messages where message.attachmentLocalPath != nil && message.attachmentRemotePath == nil && message.pending { - DispatchQueue.main.async { - store.dispatch(.xmppAction(.xmppSharingTryUpload(message))) - } - } - - // for outgoing messages with shared attachments which are already uploaded - // but have no thumbnail (only for images) - for message in messages where !message.pending && !message.sentError && message.attachmentType == .image { - if message.attachmentLocalName != nil && message.attachmentRemotePath != nil && message.attachmentThumbnailName == nil { - DispatchQueue.main.async { - // swiftlint:disable:next force_unwrapping - store.dispatch(.fileAction(.createAttachmentThumbnail(messageId: message.id, localName: message.attachmentLocalName!))) - } - } - } - - promise(.success(.info("FileMiddleware: attachments/shares messages processed"))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.downloadAttachmentFile(let id, let attachmentRemotePath)): - return Deferred { - Future { promise in - let localName = "\(id)_\(UUID().uuidString)\(attachmentRemotePath.lastPathComponent)" - let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) - DownloadManager.shared.enqueueDownload(from: attachmentRemotePath, to: localUrl) { error in - DispatchQueue.main.async { - if let error { - store.dispatch(.fileAction(.downloadingAttachmentFileFailed(messageId: id, reason: error.localizedDescription))) - } else { - store.dispatch(.fileAction(.attachmentFileDownloaded(messageId: id, localName: localName))) - } - } - } - promise(.success(.info("FileMiddleware: started downloading attachment for message \(id)"))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.attachmentFileDownloaded(let id, let localName)): - return Deferred { - Future { [weak self] promise in - self?.downloadingMessageIDs.remove(id) - promise(.success(.fileAction(.createAttachmentThumbnail(messageId: id, localName: localName)))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.createAttachmentThumbnail(let id, let localName)): - return Deferred { - Future { [weak self] promise in - if let thumbnailName = FileProcessing.shared.createThumbnail(localName: localName) { - self?.downloadingMessageIDs.remove(id) - promise(.success(.fileAction(.attachmentThumbnailCreated(messageId: id, thumbnailName: thumbnailName)))) - } else { - self?.downloadingMessageIDs.remove(id) - promise(.success(.info("FileMiddleware: failed to create thumbnail from \(localName) for message \(id)"))) - } - } - } - .eraseToAnyPublisher() - - // MARK: - For outgoing sharing - case .fileAction(.fetchItemsFromGallery): - return Deferred { - Future { promise in - let items = FileProcessing.shared.fetchGallery() - promise(.success(.fileAction(.itemsFromGalleryFetched(items: items)))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.itemsFromGalleryFetched(let items)): - return Deferred { - Future { promise in - let newItems = FileProcessing.shared.fillGalleryItemsThumbnails(items: items) - promise(.success(.sharingAction(.galleryItemsUpdated(items: newItems)))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.copyGalleryItemsForUploading(let items)): - return Deferred { - Future { promise in - let ids = FileProcessing.shared.copyGalleryItemsForUploading(items: items) - promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: ids.map { $0.0 }, localNames: ids.map { $0.1 })))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.copyCameraCapturedForUploading(let media, let type)): - return Deferred { - Future { promise in - if let (id, localName) = FileProcessing.shared.copyCameraCapturedForUploading(media: media, type: type) { - promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: [id], localNames: [localName])))) - } else { - promise(.success(.info("FileMiddleware: failed to copy camera captured media for uploading"))) - } - } - } - .eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/LoggerMiddleware.swift b/old/AppCore/Middlewares/LoggerMiddleware.swift deleted file mode 100644 index f9fec20..0000000 --- a/old/AppCore/Middlewares/LoggerMiddleware.swift +++ /dev/null @@ -1,69 +0,0 @@ -import Combine -import Foundation -import SwiftUI - -let isConsoleLoggingEnabled = false - -#if DEBUG - let prefixLength = 400 - func loggerMiddleware() -> Middleware { - { state, action in - let timeStr = dateFormatter.string(from: Date()) - var actionStr = "\(action)" - actionStr = String(actionStr.prefix(prefixLength)) + " ..." - var stateStr = "\(state)" - stateStr = String(stateStr.prefix(prefixLength)) + " ..." - - let str = "\(timeStr) \u{EA86} \(actionStr)\n\(timeStr) \u{F129} \(stateStr)\n" - - print(str) - if isConsoleLoggingEnabled { - NSLog(str) - } - return Empty().eraseToAnyPublisher() - } - } -#else - func loggerMiddleware() -> Middleware { - { _, _ in - Empty().eraseToAnyPublisher() - } - } -#endif - -enum LogLevels: String { - case info = "\u{F449}" - case warning = "\u{F071}" - case error = "\u{EA76}" -} - -// For database errors logging -func logIt(_ level: LogLevels, _ message: String) { - #if DEBUG - let timeStr = dateFormatter.string(from: Date()) - let str = "\(timeStr) \(level.rawValue) \(message)" - print(str) - if isConsoleLoggingEnabled { - NSLog(str) - } - #endif -} - -private var dateFormatter: DateFormatter { - let formatter = DateFormatter() - formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale - formatter.dateFormat = "MM-dd HH:mm:ss.SSS" - return formatter -} - -// For thread debugging -func ptInfo(_ message: String) { - #if DEBUG - let timeStr = dateFormatter.string(from: Date()) - let str = "\(timeStr) \(message) -> \(Thread.current), \(String(validatingUTF8: __dispatch_queue_get_label(nil)) ?? "no queue label")" - print(str) - if isConsoleLoggingEnabled { - NSLog(str) - } - #endif -} diff --git a/old/AppCore/Middlewares/RostersMiddleware.swift b/old/AppCore/Middlewares/RostersMiddleware.swift deleted file mode 100644 index e253589..0000000 --- a/old/AppCore/Middlewares/RostersMiddleware.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Combine - -final class RostersMiddleware { - static let shared = RostersMiddleware() - - func middleware(state _: AppState, action: AppAction) -> AnyPublisher { - switch action { - case .databaseAction(.storedRostersLoaded(let rosters)): - return Just(.rostersAction(.rostersListUpdated(rosters))) - .eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/SharingMiddleware.swift b/old/AppCore/Middlewares/SharingMiddleware.swift deleted file mode 100644 index 7d6e788..0000000 --- a/old/AppCore/Middlewares/SharingMiddleware.swift +++ /dev/null @@ -1,131 +0,0 @@ -import AVFoundation -import Combine -import Foundation -import Photos -import UIKit - -final class SharingMiddleware { - static let shared = SharingMiddleware() - - func middleware(state: AppState, action: AppAction) -> AnyPublisher { - switch action { - // MARK: - Camera and Gallery Access - case .sharingAction(.checkCameraAccess): - return Deferred { - Future { promise in - let status = AVCaptureDevice.authorizationStatus(for: .video) - switch status { - case .authorized: - promise(.success(.sharingAction(.setCameraAccess(true)))) - - case .notDetermined: - AVCaptureDevice.requestAccess(for: .video) { granted in - promise(.success(.sharingAction(.setCameraAccess(granted)))) - } - - case .denied, .restricted: - promise(.success(.sharingAction(.setCameraAccess(false)))) - - @unknown default: - promise(.success(.sharingAction(.setCameraAccess(false)))) - } - } - } - .eraseToAnyPublisher() - - case .sharingAction(.checkGalleryAccess): - return Deferred { - Future { promise in - let status = PHPhotoLibrary.authorizationStatus() - switch status { - case .authorized, .limited: - promise(.success(.sharingAction(.setGalleryAccess(true)))) - - case .notDetermined: - PHPhotoLibrary.requestAuthorization { status in - promise(.success(.sharingAction(.setGalleryAccess(status == .authorized)))) - } - - case .denied, .restricted: - promise(.success(.sharingAction(.setGalleryAccess(false)))) - - @unknown default: - promise(.success(.sharingAction(.setGalleryAccess(false)))) - } - } - } - .eraseToAnyPublisher() - - case .fileAction(.itemsFromGalleryFetched(let items)): - return Just(.sharingAction(.galleryItemsUpdated(items: items))) - .eraseToAnyPublisher() - - // MARK: - Sharing - case .sharingAction(.shareMedia(let ids)): - return Deferred { - Future { promise in - let items = state.sharingState.galleryItems.filter { ids.contains($0.id) } - promise(.success(.fileAction(.copyGalleryItemsForUploading(items: items)))) - } - } - .eraseToAnyPublisher() - - case .fileAction(.itemsCopiedForUploading(let newMessageIds, let localNames)): - if let chat = state.conversationsState.currentChat { - return Just(.conversationAction(.sendMediaMessages( - from: chat.account, - to: chat.participant, - messagesIds: newMessageIds, - localFilesNames: localNames - ))) - .eraseToAnyPublisher() - } else { - return Empty().eraseToAnyPublisher() - } - - case .sharingAction(.cameraCaptured(let media, let type)): - return Deferred { - Future { promise in - if let (id, localName) = FileProcessing.shared.copyCameraCapturedForUploading(media: media, type: type) { - promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: [id], localNames: [localName]))) - ) - } else { - promise(.success(.info("SharingMiddleware: camera's captured file didn't copied"))) - } - } - } - .eraseToAnyPublisher() - - case .sharingAction(.shareLocation(let lat, let lon)): - if let chat = state.conversationsState.currentChat { - let msg = "geo:\(lat),\(lon)" - return Just(.conversationAction(.sendMessage(from: chat.account, to: chat.participant, body: msg))) - .eraseToAnyPublisher() - } else { - return Empty().eraseToAnyPublisher() - } - - case .sharingAction(.shareDocuments(let data, let extensions)): - return Deferred { - Future { promise in - let ids = FileProcessing.shared.copyDocumentsForUploading(data: data, extensions: extensions) - promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: ids.map { $0.0 }, localNames: ids.map { $0.1 }))) - ) - } - } - .eraseToAnyPublisher() - - case .sharingAction(.shareContact(let jid)): - if let chat = state.conversationsState.currentChat { - let msg = "contact:\(jid)" - return Just(.conversationAction(.sendMessage(from: chat.account, to: chat.participant, body: msg))) - .eraseToAnyPublisher() - } else { - return Empty().eraseToAnyPublisher() - } - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/StartMiddleware.swift b/old/AppCore/Middlewares/StartMiddleware.swift deleted file mode 100644 index 1a084b6..0000000 --- a/old/AppCore/Middlewares/StartMiddleware.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Combine - -final class StartMiddleware { - static let shared = StartMiddleware() - - func middleware(state: AppState, action: AppAction) -> AnyPublisher { - switch action { - case .accountsAction(.accountsListUpdated(let accounts)): - if accounts.isEmpty { - if state.currentFlow == .start { - return Just(.startAction(.goTo(.welcomeScreen))) - .eraseToAnyPublisher() - } else { - return Empty().eraseToAnyPublisher() - } - } else { - if state.currentFlow == .accounts, state.accountsState.navigation == .addAccount { - return Just(.changeFlow(.chats)) - .eraseToAnyPublisher() - } else if state.currentFlow == .start { - return Just(.changeFlow(.chats)) - .eraseToAnyPublisher() - } else { - return Empty().eraseToAnyPublisher() - } - } - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Middlewares/XMPPMiddleware.swift b/old/AppCore/Middlewares/XMPPMiddleware.swift deleted file mode 100644 index 4f98a0b..0000000 --- a/old/AppCore/Middlewares/XMPPMiddleware.swift +++ /dev/null @@ -1,160 +0,0 @@ -import Combine -import Foundation -import Martin - -final class XMPPMiddleware { - static let shared = XMPPMiddleware() - private let service = XMPPService(manager: Database.shared) - private var cancellables: Set = [] - private var uploadingMessageIDs = ThreadSafeSet() - - private init() { - service.clientState.sink { client, state in - let jid = client.userBareJid.stringValue - let status = ConnectionStatus.from(state) - let action = AppAction.xmppAction(.clientConnectionChanged(jid: jid, state: status)) - DispatchQueue.main.async { - store.dispatch(action) - } - } - .store(in: &cancellables) - - service.clientMessages.sink { _, martinMessage in - guard let message = Message.map(martinMessage) else { return } - DispatchQueue.main.async { - store.dispatch(.xmppAction(.xmppMessageReceived(message))) - } - } - .store(in: &cancellables) - - service.clientFeatures.sink { client, features in - let jid = client.userBareJid.stringValue - DispatchQueue.main.async { - store.dispatch(.xmppAction(.serverFeaturesLoaded(jid: jid, features: features))) - } - } - .store(in: &cancellables) - } - - func middleware(state: AppState, action: AppAction) -> AnyPublisher { - switch action { - case .accountsAction(.tryAddAccountWithCredentials): - return Deferred { - Future { [weak self] promise in - self?.service.updateClients(for: state.accountsState.accounts) - promise(.success(.info("XMPPMiddleware: clients updated in XMPP service"))) - } - } - .eraseToAnyPublisher() - - case .accountsAction(.addAccountError): - return Deferred { - Future { [weak self] promise in - self?.service.updateClients(for: state.accountsState.accounts) - promise(.success(.info("XMPPMiddleware: clients updated in XMPP service"))) - } - } - .eraseToAnyPublisher() - - case .databaseAction(.storedAccountsLoaded(let accounts)): - return Deferred { - Future { [weak self] promise in - self?.service.updateClients(for: accounts.filter { $0.isActive && !$0.isTemp }) - promise(.success(.info("XMPPMiddleware: clients updated in XMPP service"))) - } - } - .eraseToAnyPublisher() - - case .rostersAction(.addRoster(let ownerJID, let contactJID, let name, let groups)): - return Deferred { - Future { [weak self] promise in - guard let service = self?.service, let client = service.clients.first(where: { $0.connectionConfiguration.userJid.stringValue == ownerJID }) else { - return promise(.success(.rostersAction(.addRosterError(reason: XMPPError.item_not_found.localizedDescription)))) - } - let module = client.modulesManager.module(RosterModule.self) - module.addItem(jid: JID(contactJID), name: name, groups: groups, completionHandler: { result in - switch result { - case .success: - promise(.success(.rostersAction(.addRosterDone(jid: contactJID)))) - - case .failure(let error): - promise(.success(.rostersAction(.addRosterError(reason: error.localizedDescription)))) - } - }) - } - } - .eraseToAnyPublisher() - - case .rostersAction(.deleteRoster(let ownerJID, let contactJID)): - return Deferred { - Future { [weak self] promise in - guard let service = self?.service, let client = service.clients.first(where: { $0.connectionConfiguration.userJid.stringValue == ownerJID }) else { - return promise(.success(.rostersAction(.rosterDeletingFailed(reason: XMPPError.item_not_found.localizedDescription)))) - } - let module = client.modulesManager.module(RosterModule.self) - module.removeItem(jid: JID(contactJID), completionHandler: { result in - switch result { - case .success: - promise(.success(.info("XMPPMiddleware: roster \(contactJID) deleted from \(ownerJID)"))) - - case .failure(let error): - promise(.success(.rostersAction(.rosterDeletingFailed(reason: error.localizedDescription)))) - } - }) - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppMessageSent(let message)): - return Deferred { - Future { [weak self] promise in - DispatchQueue.global().async { - self?.service.sendMessage(message: message) { done in - if done { - promise(.success(.xmppAction(.xmppMessageSendSuccess(msgId: message.id)))) - } else { - promise(.success(.xmppAction(.xmppMessageSendFailed(msgId: message.id)))) - } - } - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppSharingTryUpload(let message)): - return Deferred { - Future { [weak self] promise in - if self?.uploadingMessageIDs.contains(message.id) ?? false { - return promise(.success(.info("XMPPMiddleware: attachment in message \(message.id) is already in uploading process"))) - } else { - self?.uploadingMessageIDs.insert(message.id) - DispatchQueue.global().async { - self?.service.uploadAttachment(message: message) { error, remotePath in - self?.uploadingMessageIDs.remove(message.id) - if let error { - promise(.success(.xmppAction(.xmppSharingUploadFailed(msgId: message.id, reason: error.localizedDescription)))) - } else { - promise(.success(.xmppAction(.xmppSharingUploadSuccess(msgId: message.id, attachmentRemotePath: remotePath)))) - } - } - } - } - } - } - .eraseToAnyPublisher() - - case .xmppAction(.xmppLoadArchivedMessages(let jid, let to, let fromDate)): - return Empty().eraseToAnyPublisher() - // return Deferred { - // Future { [weak self] promise in - // self?.service.requestArchivedMessages(jid: jid, to: to, fromDate: fromDate) - // promise(.success(.conversationAction(.setArchivedMessagesRequested))) - // } - // } - // .eraseToAnyPublisher() - - default: - return Empty().eraseToAnyPublisher() - } - } -} diff --git a/old/AppCore/Models/Account.swift b/old/AppCore/Models/Account.swift deleted file mode 100644 index 264d195..0000000 --- a/old/AppCore/Models/Account.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation -import GRDB -import Martin -import SwiftUI - -// MARK: - Account -struct Account: DBStorable { - var bareJid: String - var pass: String - var isActive: Bool - var isTemp: Bool // account which is added by user, but not yet logged in - var id: String { bareJid } -} - -extension Account: UniversalInputSelectionElement { - var text: String? { bareJid } - var icon: Image? { nil } -} - -extension Account { - static let databaseTableName = "accounts" -} diff --git a/old/AppCore/Models/Channel.swift b/old/AppCore/Models/Channel.swift deleted file mode 100644 index 9c8275f..0000000 --- a/old/AppCore/Models/Channel.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation -import GRDB -import Martin -import SwiftUI - -// MARK: - Account -struct Channel: DBStorable { - var id: String - var account: String - var channel: String -} - -extension Channel { - static let channelTableName = "channels" -} diff --git a/old/AppCore/Models/Chat.swift b/old/AppCore/Models/Chat.swift deleted file mode 100644 index 58fc273..0000000 --- a/old/AppCore/Models/Chat.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation -import GRDB - -enum ConversationType: Int, Codable, DatabaseValueConvertible { - case chat = 0 - case room = 1 - case channel = 2 -} - -struct Chat: DBStorable { - static let databaseTableName = "chats" - - var id: String - var account: String - var participant: String - var type: ConversationType -} - -extension Chat: Equatable {} diff --git a/old/AppCore/Models/ConnectionStatus.swift b/old/AppCore/Models/ConnectionStatus.swift deleted file mode 100644 index fab36aa..0000000 --- a/old/AppCore/Models/ConnectionStatus.swift +++ /dev/null @@ -1,27 +0,0 @@ -// This struct is simpliest variant of Martin's Client State. -// Just for more comfortable using in App State -import Foundation -import Martin - -enum ConnectionStatus: Stateable { - case connecting - case connected(resumed: Bool = false) - case disconnecting - case disconnected(reason: String) - - static func from(_ state: XMPPClient.State) -> ConnectionStatus { - switch state { - case .connecting: - return .connecting - - case .connected(let resumed): - return .connected(resumed: resumed) - - case .disconnecting: - return .disconnecting - - case .disconnected(let reason): - return .disconnected(reason: reason.localizedDescription) - } - } -} diff --git a/old/AppCore/Models/Message.swift b/old/AppCore/Models/Message.swift deleted file mode 100644 index c5fd963..0000000 --- a/old/AppCore/Models/Message.swift +++ /dev/null @@ -1,128 +0,0 @@ -import Foundation -import GRDB -import Martin - -enum MessageType: String, Codable, DatabaseValueConvertible { - case chat - case groupchat - case error -} - -enum MessageAttachmentType: Int, Stateable, DatabaseValueConvertible { - case movie = 0 - case image = 1 - case audio = 2 - case file = 3 -} - -enum MessageContentType: String, Codable, DatabaseValueConvertible { - case text - case typing - case invite - case attachment -} - -struct Message: DBStorable, Equatable { - static let databaseTableName = "messages" - - let id: String - let type: MessageType - let contentType: MessageContentType - - let from: String - let to: String? - - let body: String? - let subject: String? - let thread: String? - let oobUrl: String? - - let date: Date - let pending: Bool - let sentError: Bool - - var attachmentType: MessageAttachmentType? - var attachmentLocalName: String? - var attachmentRemotePath: URL? - var attachmentThumbnailName: String? - var attachmentDownloadFailed: Bool = false -} - -extension Message { - // Universal mapping from Martin's Message to App Message - static func map(_ martinMessage: Martin.Message) -> Message? { - #if DEBUG - print("---") - print("Message received: \(martinMessage)") - print("---") - #endif - - // Check that the message type is supported - let chatTypes: [StanzaType] = [.chat, .groupchat] - guard let mType = martinMessage.type, chatTypes.contains(mType) else { - #if DEBUG - print("Unsupported message type: \(martinMessage.type?.rawValue ?? "nil")") - #endif - return nil - } - - // Type - let type = MessageType(rawValue: martinMessage.type?.rawValue ?? "") ?? .chat - - // Content type - var contentType: MessageContentType = .text - if martinMessage.oob != nil { - contentType = .attachment - } else if martinMessage.hints.contains(.noStore) { - contentType = .typing - } - - // From/To - let from = martinMessage.from?.bareJid.stringValue ?? "" - let to = martinMessage.to?.bareJid.stringValue - - // Extract date or set current - var date = Date() - if let timestampStr = martinMessage.attribute("archived_date"), let timeInterval = TimeInterval(timestampStr) { - date = Date(timeIntervalSince1970: timeInterval) - } - - // Msg - var msg = Message( - id: martinMessage.id ?? UUID().uuidString, - type: type, - contentType: contentType, - from: from, - to: to, - body: martinMessage.body, - subject: martinMessage.subject, - thread: martinMessage.thread, - oobUrl: martinMessage.oob, - date: date, - pending: false, - sentError: false, - attachmentType: nil, - attachmentLocalName: nil, - attachmentRemotePath: nil, - attachmentThumbnailName: nil, - attachmentDownloadFailed: false - ) - if let oob = martinMessage.oob { - msg.attachmentType = oob.attachmentType - msg.attachmentRemotePath = URL(string: oob) - } - return msg - } -} - -extension Message { - var attachmentLocalPath: URL? { - guard let attachmentLocalName = attachmentLocalName else { return nil } - return FileProcessing.fileFolder.appendingPathComponent(attachmentLocalName) - } - - var attachmentThumbnailPath: URL? { - guard let attachmentThumbnailName = attachmentThumbnailName else { return nil } - return FileProcessing.fileFolder.appendingPathComponent(attachmentThumbnailName) - } -} diff --git a/old/AppCore/Models/Room.swift b/old/AppCore/Models/Room.swift deleted file mode 100644 index 583fd8b..0000000 --- a/old/AppCore/Models/Room.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -import GRDB -import Martin -import SwiftUI - -// MARK: - Account -struct Room: DBStorable { - var id: String - var account: String - var nickname: String - var password: String? -} - -extension Room { - static let roomTableName = "rooms" -} diff --git a/old/AppCore/Models/Roster.swift b/old/AppCore/Models/Roster.swift deleted file mode 100644 index b4653cb..0000000 --- a/old/AppCore/Models/Roster.swift +++ /dev/null @@ -1,62 +0,0 @@ -import Foundation -import GRDB -import Martin - -struct RosterVersion: DBStorable { - static let databaseTableName = "rosterVersions" - - var bareJid: String - var version: String - var id: String { bareJid } -} - -struct Roster: DBStorable { - static let databaseTableName = "rosters" - - var bareJid: String = "" - var contactBareJid: String - var name: String? - var subscription: String - var ask: Bool - var data: DBRosterData - var locallyDeleted: Bool = false - - var id: String { "\(bareJid)-\(contactBareJid)" } -} - -struct DBRosterData: Codable, DatabaseValueConvertible { - let groups: [String] - let annotations: [RosterItemAnnotation] - - public var databaseValue: DatabaseValue { - let encoder = JSONEncoder() - // swiftlint:disable:next force_try - let data = try! encoder.encode(self) - return data.databaseValue - } - - public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? { - guard let data = Data.fromDatabaseValue(dbValue) else { - return nil - } - let decoder = JSONDecoder() - // swiftlint:disable:next force_try - return try! decoder.decode(Self.self, from: data) - } - - static func == (lhs: DBRosterData, rhs: DBRosterData) -> Bool { - lhs.groups == rhs.groups && lhs.annotations == rhs.annotations - } -} - -extension RosterItemAnnotation: Equatable { - public static func == (lhs: RosterItemAnnotation, rhs: RosterItemAnnotation) -> Bool { - lhs.type == rhs.type && lhs.values == rhs.values - } -} - -extension Roster: Equatable { - static func == (lhs: Roster, rhs: Roster) -> Bool { - lhs.bareJid == rhs.bareJid && lhs.contactBareJid == rhs.contactBareJid - } -} diff --git a/old/AppCore/Models/ServerFeature.swift b/old/AppCore/Models/ServerFeature.swift deleted file mode 100644 index 8ee3663..0000000 --- a/old/AppCore/Models/ServerFeature.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation - -struct ServerFeature: Stateable, Identifiable { - let xep: String - let name: String - let xmppId: String? - let description: String? - - var id: String { xep } -} diff --git a/old/AppCore/Reducers/AccountsReducer.swift b/old/AppCore/Reducers/AccountsReducer.swift deleted file mode 100644 index f5a7c56..0000000 --- a/old/AppCore/Reducers/AccountsReducer.swift +++ /dev/null @@ -1,25 +0,0 @@ -extension AccountsState { - static func reducer(state: inout AccountsState, action: AccountsAction) { - switch action { - case .accountsListUpdated(let accounts): - state.accounts = accounts - - case .goTo(let navigation): - state.navigation = navigation - - case .tryAddAccountWithCredentials(let login, let password): - let account = Account(bareJid: login, pass: password, isActive: true, isTemp: true) - state.accounts.append(account) - - case .addAccountError(let jid, let reason): - state.accounts = state.accounts.filter { $0.bareJid != jid } - state.addAccountError = reason - - case .clientServerFeaturesUpdated(let jid, let features): - state.discoFeatures[jid] = features - - default: - break - } - } -} diff --git a/old/AppCore/Reducers/AppReducer.swift b/old/AppCore/Reducers/AppReducer.swift deleted file mode 100644 index ff67556..0000000 --- a/old/AppCore/Reducers/AppReducer.swift +++ /dev/null @@ -1,35 +0,0 @@ -import Foundation - -extension AppState { - static func reducer(state: inout AppState, action: AppAction) { - switch action { - case .flushState: - state = AppState() - - case .changeFlow(let flow): - state.previousFlow = state.currentFlow - state.currentFlow = flow - - case .startAction(let action): - StartState.reducer(state: &state.startState, action: action) - - case .databaseAction, .xmppAction, .fileAction, .info: - break // this actions are processed by other middlewares - - case .accountsAction(let action): - AccountsState.reducer(state: &state.accountsState, action: action) - - case .rostersAction(let action): - RostersState.reducer(state: &state.rostersState, action: action) - - case .chatsAction(let action): - ChatsState.reducer(state: &state.chatsState, action: action) - - case .conversationAction(let action): - ConversationState.reducer(state: &state.conversationsState, action: action) - - case .sharingAction(let action): - SharingState.reducer(state: &state.sharingState, action: action) - } - } -} diff --git a/old/AppCore/Reducers/ChatsReducer.swift b/old/AppCore/Reducers/ChatsReducer.swift deleted file mode 100644 index 393c61c..0000000 --- a/old/AppCore/Reducers/ChatsReducer.swift +++ /dev/null @@ -1,14 +0,0 @@ -extension ChatsState { - static func reducer(state: inout ChatsState, action: ChatsAction) { - switch action { - case .chatsListUpdated(let chats): - state.chats = chats - - case .chatStarted(let chat): - state.currentChat = chat - - default: - break - } - } -} diff --git a/old/AppCore/Reducers/ConversationReducer.swift b/old/AppCore/Reducers/ConversationReducer.swift deleted file mode 100644 index cc76c62..0000000 --- a/old/AppCore/Reducers/ConversationReducer.swift +++ /dev/null @@ -1,24 +0,0 @@ -import SwiftUI - -extension ConversationState { - static func reducer(state: inout ConversationState, action: ConversationAction) { - switch action { - case .makeConversationActive(let chat, let roster): - state.currentChat = chat - state.currentRoster = roster - - case .messagesUpdated(let messages): - state.currentMessages = messages - - case .setReplyText(let text): - if text.isEmpty { - state.replyText = "" - } else { - state.replyText = text.makeReply - } - - default: - break - } - } -} diff --git a/old/AppCore/Reducers/RostersReducer.swift b/old/AppCore/Reducers/RostersReducer.swift deleted file mode 100644 index 076559e..0000000 --- a/old/AppCore/Reducers/RostersReducer.swift +++ /dev/null @@ -1,25 +0,0 @@ -extension RostersState { - static func reducer(state: inout RostersState, action: RostersAction) { - switch action { - case .addRosterDone(let jid): - state.newAddedRosterJid = jid - state.newAddedRosterError = nil - - case .addRosterError(let reason): - state.newAddedRosterJid = nil - state.newAddedRosterError = reason - - case .rostersListUpdated(let rosters): - state.rosters = rosters - - case .markRosterAsLocallyDeleted, .deleteRoster: - state.deleteRosterError = nil - - case .rosterDeletingFailed(let reson): - state.deleteRosterError = reson - - default: - break - } - } -} diff --git a/old/AppCore/Reducers/SharingReducer.swift b/old/AppCore/Reducers/SharingReducer.swift deleted file mode 100644 index 3b66fc9..0000000 --- a/old/AppCore/Reducers/SharingReducer.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation - -extension SharingState { - static func reducer(state: inout SharingState, action: SharingAction) { - switch action { - case .showSharing(let shown): - state.sharingShown = shown - - case .setCameraAccess(let granted): - state.isCameraAccessGranted = granted - - case .setGalleryAccess(let granted): - state.isGalleryAccessGranted = granted - - case .galleryItemsUpdated(let items): - state.galleryItems = items - - default: - break - } - } -} diff --git a/old/AppCore/Reducers/StartReducer.swift b/old/AppCore/Reducers/StartReducer.swift deleted file mode 100644 index 76539f6..0000000 --- a/old/AppCore/Reducers/StartReducer.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension StartState { - static func reducer(state: inout StartState, action: StartAction) { - switch action { - case .loadStoredAccounts: - break - - case .goTo(let navigation): - state.navigation = navigation - } - } -} diff --git a/old/AppCore/State/AccountsState.swift b/old/AppCore/State/AccountsState.swift deleted file mode 100644 index 4e6cdb6..0000000 --- a/old/AppCore/State/AccountsState.swift +++ /dev/null @@ -1,20 +0,0 @@ -enum AccountNavigationState: Stateable { - case addAccount -} - -struct AccountsState: Stateable { - var navigation: AccountNavigationState - var accounts: [Account] - var discoFeatures: [String: [ServerFeature]] - - var addAccountError: String? -} - -// MARK: Init -extension AccountsState { - init() { - navigation = .addAccount - accounts = [] - discoFeatures = [:] - } -} diff --git a/old/AppCore/State/AppState.swift b/old/AppCore/State/AppState.swift deleted file mode 100644 index 56f589f..0000000 --- a/old/AppCore/State/AppState.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Foundation - -enum AppFlow: Codable { - case start - case accounts - case chats - case contacts - case settings - case conversation -} - -struct AppState: Stateable { - var appVersion: String - var previousFlow: AppFlow - var currentFlow: AppFlow - - var startState: StartState - var accountsState: AccountsState - var rostersState: RostersState - var chatsState: ChatsState - var conversationsState: ConversationState - var sharingState: SharingState -} - -// MARK: Init -extension AppState { - init() { - appVersion = Const.appVersion - previousFlow = .start - currentFlow = .start - - startState = StartState() - accountsState = AccountsState() - rostersState = RostersState() - chatsState = ChatsState() - conversationsState = ConversationState() - sharingState = SharingState() - } -} diff --git a/old/AppCore/State/ChatsState.swift b/old/AppCore/State/ChatsState.swift deleted file mode 100644 index 469aef8..0000000 --- a/old/AppCore/State/ChatsState.swift +++ /dev/null @@ -1,11 +0,0 @@ -struct ChatsState: Stateable { - var chats: [Chat] - var currentChat: Chat? -} - -// MARK: Init -extension ChatsState { - init() { - chats = [] - } -} diff --git a/old/AppCore/State/ConversationState.swift b/old/AppCore/State/ConversationState.swift deleted file mode 100644 index 9267bbd..0000000 --- a/old/AppCore/State/ConversationState.swift +++ /dev/null @@ -1,15 +0,0 @@ -struct ConversationState: Stateable { - var currentChat: Chat? - var currentRoster: Roster? - var currentMessages: [Message] - - var replyText: String -} - -// MARK: Init -extension ConversationState { - init() { - currentMessages = [] - replyText = "" - } -} diff --git a/old/AppCore/State/RostersState.swift b/old/AppCore/State/RostersState.swift deleted file mode 100644 index bc42a70..0000000 --- a/old/AppCore/State/RostersState.swift +++ /dev/null @@ -1,15 +0,0 @@ -struct RostersState: Stateable { - var rosters: [Roster] - - var newAddedRosterJid: String? - var newAddedRosterError: String? - - var deleteRosterError: String? -} - -// MARK: Init -extension RostersState { - init() { - rosters = [] - } -} diff --git a/old/AppCore/State/SharingState.swift b/old/AppCore/State/SharingState.swift deleted file mode 100644 index d19c489..0000000 --- a/old/AppCore/State/SharingState.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Foundation - -enum SharingCameraMediaType: Stateable { - case video - case photo -} - -struct SharingGalleryItem: Stateable, Identifiable { - var id: String - var type: SharingCameraMediaType - var thumbnail: Data? - var duration: String? -} - -struct SharingState: Stateable { - var sharingShown: Bool - var isCameraAccessGranted: Bool - var isGalleryAccessGranted: Bool - - var galleryItems: [SharingGalleryItem] -} - -// MARK: Init -extension SharingState { - init() { - sharingShown = false - isCameraAccessGranted = false - isGalleryAccessGranted = false - - galleryItems = [] - } -} diff --git a/old/AppCore/State/StartState.swift b/old/AppCore/State/StartState.swift deleted file mode 100644 index 15bb709..0000000 --- a/old/AppCore/State/StartState.swift +++ /dev/null @@ -1,15 +0,0 @@ -enum StartNavigationState: Stateable { - case startScreen - case welcomeScreen -} - -struct StartState: Stateable { - var navigation: StartNavigationState -} - -// MARK: Init -extension StartState { - init() { - navigation = .startScreen - } -} diff --git a/old/AppCore/XMPP/XMPPService.swift b/old/AppCore/XMPP/XMPPService.swift deleted file mode 100644 index f9109ff..0000000 --- a/old/AppCore/XMPP/XMPPService.swift +++ /dev/null @@ -1,266 +0,0 @@ -import Combine -import Foundation -import GRDB -import Martin - -protocol MartinsManager: Martin.RosterManager & Martin.ChatManager & Martin.ChannelManager & Martin.RoomManager {} - -final class XMPPService: ObservableObject { - private let manager: MartinsManager - - private let clientStatePublisher = PassthroughSubject<(XMPPClient, XMPPClient.State), Never>() - private var clientStateCancellables: Set = [] - - private let clientMessagesPublisher = PassthroughSubject<(XMPPClient, Martin.Message), Never>() - private var clientMessagesCancellables: Set = [] - - private let clientFeaturesPublisher = PassthroughSubject<(XMPPClient, [String]), Never>() - private var clientFeaturesCancellables: Set = [] - - @Published private(set) var clients: [XMPPClient] = [] - var clientState: AnyPublisher<(XMPPClient, XMPPClient.State), Never> { - clientStatePublisher.eraseToAnyPublisher() - } - - var clientMessages: AnyPublisher<(XMPPClient, Martin.Message), Never> { - clientMessagesPublisher.eraseToAnyPublisher() - } - - var clientFeatures: AnyPublisher<(XMPPClient, [String]), Never> { - clientFeaturesPublisher.eraseToAnyPublisher() - } - - init(manager: MartinsManager) { - self.manager = manager - } - - func updateClients(for accounts: [Account]) { - // get simple diff - let forAdd = accounts - .filter { !self.clients.map { $0.connectionConfiguration.userJid.stringValue }.contains($0.bareJid) } - let forRemove = clients - .map { $0.connectionConfiguration.userJid.stringValue } - .filter { !accounts.map { $0.bareJid }.contains($0) } - - // init and add clients - for account in forAdd { - // add client - let client = makeClient(for: account, with: manager) - clients.append(client) - - // subscribe to client state - client.$state - .sink { [weak self] state in - self?.clientStatePublisher.send((client, state)) - } - .store(in: &clientStateCancellables) - - // subscribe to client server features - client.module(DiscoveryModule.self).$serverDiscoResult - .sink { [weak self] disco in - self?.clientFeaturesPublisher.send((client, disco.features)) - } - .store(in: &clientFeaturesCancellables) - - // subscribe to client messages - client.module(MessageModule.self).messagesPublisher - .sink { [weak self] message in - self?.clientMessagesPublisher.send((client, message.message)) - } - .store(in: &clientMessagesCancellables) - - // subscribe to carbons - client.module(MessageCarbonsModule.self).carbonsPublisher - .sink { [weak self] carbon in - self?.clientMessagesPublisher.send((client, carbon.message)) - } - .store(in: &clientMessagesCancellables) - - // subscribe to archived messages - // client.module(.mam).archivedMessagesPublisher - // .sink(receiveValue: { [weak self] archived in - // let message = archived.message - // message.attribute("archived_date", newValue: "\(archived.timestamp.timeIntervalSince1970)") - // self?.clientMessagesPublisher.send((client, message)) - // }) - // .store(in: &clientMessagesCancellables) - - // enable carbons if available - client.module(.messageCarbons).$isAvailable.filter { $0 } - .sink(receiveValue: { [weak client] _ in - client?.module(.messageCarbons).enable() - }) - .store(in: &clientMessagesCancellables) - - // finally, do login - client.login() - } - - // remove clients - for jid in forRemove { - deinitClient(jid: jid) - } - } - - private func makeClient(for account: Account, with manager: MartinsManager) -> XMPPClient { - let client = XMPPClient() - - // register modules - // core modules RFC 6120 - client.modulesManager.register(StreamFeaturesModule()) - client.modulesManager.register(SaslModule()) - client.modulesManager.register(AuthModule()) - client.modulesManager.register(SessionEstablishmentModule()) - client.modulesManager.register(ResourceBinderModule()) - client.modulesManager.register(DiscoveryModule(identity: .init(category: "client", type: "iOS", name: Const.appName))) - - // messaging modules RFC 6121 - client.modulesManager.register(RosterModule(rosterManager: manager)) - client.modulesManager.register(PresenceModule()) - - client.modulesManager.register(PubSubModule()) - client.modulesManager.register(MessageModule(chatManager: manager)) - client.modulesManager.register(MessageArchiveManagementModule()) - - client.modulesManager.register(MessageCarbonsModule()) - - // file transfer modules - client.modulesManager.register(HttpFileUploadModule()) - - // extensions - client.modulesManager.register(SoftwareVersionModule()) - client.modulesManager.register(PingModule()) - client.connectionConfiguration.userJid = .init(account.bareJid) - client.connectionConfiguration.credentials = .password(password: account.pass) - - // group chats - client.modulesManager.register(MucModule(roomManager: manager)) - - // channels - // client.modulesManager.register(MixModule(channelManager: manager)) - - // add client to clients - return client - } - - func deinitClient(jid: String) { - if let index = clients.firstIndex(where: { $0.connectionConfiguration.userJid.stringValue == jid }) { - let client = clients.remove(at: index) - _ = client.disconnect() - } - } - - func getClient(for jid: String) -> XMPPClient? { - clients.first { $0.connectionConfiguration.userJid.stringValue == jid } - } - - func sendMessage(message: Message, completion: @escaping (Bool) -> Void) { - guard let client = getClient(for: message.from), let to = message.to else { - completion(false) - return - } - guard let chat = client.module(MessageModule.self).chatManager.chat(for: client.context, with: BareJID(to)) else { - completion(false) - return - } - - let msg = chat.createMessage(text: message.body ?? "??", id: message.id) - chat.send(message: msg) { res in - switch res { - case .success: - completion(true) - - case .failure: - completion(false) - } - } - } - - func uploadAttachment(message: Message, completion: @escaping (Error?, String) -> Void) { - guard let client = getClient(for: message.from), let to = message.to else { - completion(XMPPError.bad_request("No such client"), "") - return - } - guard let fileName = message.attachmentLocalName else { - completion(XMPPError.bad_request("No such file"), "") - return - } - let url = FileProcessing.fileFolder.appendingPathComponent(fileName) - guard let data = try? Data(contentsOf: url) else { - completion(XMPPError.bad_request("No such file"), "") - return - } - guard let chat = client.module(MessageModule.self).chatManager.chat(for: client.context, with: BareJID(to)) else { - completion(XMPPError.bad_request("No such chat"), "") - return - } - - let httpModule = client.module(HttpFileUploadModule.self) - httpModule.findHttpUploadComponent { res in - switch res { - case .success(let components): - guard let component = components.first(where: { $0.maxSize > data.count }) else { - completion(XMPPError.bad_request("File too big"), "") - return - } - httpModule.requestUploadSlot(componentJid: component.jid, filename: fileName, size: data.count, contentType: url.mimeType) { res in - switch res { - case .success(let slot): - var request = URLRequest(url: slot.putUri) - for (key, value) in slot.putHeaders { - request.addValue(value, forHTTPHeaderField: key) - } - request.httpMethod = "PUT" - request.httpBody = data - request.addValue(String(data.count), forHTTPHeaderField: "Content-Length") - request.addValue(url.mimeType, forHTTPHeaderField: "Content-Type") - let session = URLSession(configuration: URLSessionConfiguration.default) - session.dataTask(with: request) { _, response, error in - let code = (response as? HTTPURLResponse)?.statusCode ?? 500 - guard error == nil, code == 200 || code == 201 else { - completion(XMPPError.bad_request("Upload failed"), "") - return - } - if code == 200 { - completion(XMPPError.bad_request("Invalid response code"), "") - } else { - let mesg = chat.createMessage(text: slot.getUri.absoluteString, id: message.id) - mesg.oob = slot.getUri.absoluteString - chat.send(message: mesg) { res in - switch res { - case .success: - completion(nil, slot.getUri.absoluteString) - - case .failure: - completion(XMPPError.bad_request("File uploaded, but message sent failed"), slot.getUri.absoluteString) - } - } - } - }.resume() - - case .failure(let error): - completion(error, "") - } - } - - case .failure(let error): - completion(error, "") - } - } - } - - func requestArchivedMessages(jid: String, to: String?, fromDate: Date) { - guard let client = getClient(for: jid) else { - return - } - client.module(.mam).queryItems(componentJid: JID(jid), with: JID(to), start: fromDate, end: Date(), queryId: UUID().uuidString) { result in - switch result { - case .success(let response): - print("MAM response: \(response)") - - case .failure(let error): - print("MAM error: \(error)") - } - } - } -} diff --git a/old/Generated/.gitignore b/old/Generated/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/old/Generated/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/old/Helpers/Bool+Extensions.swift b/old/Helpers/Bool+Extensions.swift deleted file mode 100644 index b26674c..0000000 --- a/old/Helpers/Bool+Extensions.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -extension Bool { - var intValue: Int { - self ? 1 : 0 - } -} diff --git a/old/Helpers/Const.swift b/old/Helpers/Const.swift deleted file mode 100644 index c96edfd..0000000 --- a/old/Helpers/Const.swift +++ /dev/null @@ -1,53 +0,0 @@ -import Foundation -import UIKit - -enum Const { - // // Network - // #if DEBUG - // static let baseUrl = "staging.some.com/api" - // #else - // static let baseUrl = "prod.some.com/api" - // #endif - // static let requestTimeout = 15.0 - // static let networkLogging = true - - // App - static var appVersion: String { - let info = Bundle.main.infoDictionary - let appVersion = info?["CFBundleShortVersionString"] as? String ?? "Unknown" - let appBuild = info?[kCFBundleVersionKey as String] as? String ?? "Unknown" - return "v \(appVersion)(\(appBuild))" - } - - static var appName: String { - Bundle.main.bundleIdentifier ?? "Conversations Classic iOS" - } - - // Trusted servers - enum TrustedServers: String { - case narayana = "narayana.im" - case conversations = "conversations.im" - } - - // Limit for video for sharing - static let videoDurationLimit = 60.0 - - // Upload/download file folder - static let fileFolder = "Downloads" - - // Grid size for gallery preview (3 in a row) - static let galleryGridSize = UIScreen.main.bounds.width / 3 - - // Size for map preview for location messages - static let mapPreviewSize = UIScreen.main.bounds.width * 0.5 - - // Size for attachment preview - static let attachmentPreviewSize = UIScreen.main.bounds.width * 0.5 - - // Lenght in days for MAM request - static let mamRequestDaysLength = 30 - - // Limits for messages pagination - static let messagesPageMin = 20 - static let messagesPageMax = 100 -} diff --git a/old/Helpers/Map+Extensions.swift b/old/Helpers/Map+Extensions.swift deleted file mode 100644 index 4c25921..0000000 --- a/old/Helpers/Map+Extensions.swift +++ /dev/null @@ -1,16 +0,0 @@ -import MapKit - -extension MKCoordinateRegion: Equatable { - public static func == (lhs: MKCoordinateRegion, rhs: MKCoordinateRegion) -> Bool { - lhs.center.latitude == rhs.center.latitude && - lhs.center.longitude == rhs.center.longitude && - lhs.span.latitudeDelta == rhs.span.latitudeDelta && - lhs.span.longitudeDelta == rhs.span.longitudeDelta - } -} - -extension CLLocationCoordinate2D: Identifiable { - public var id: String { - "\(latitude)-\(longitude)" - } -} diff --git a/old/Helpers/Set+Extensions.swift b/old/Helpers/Set+Extensions.swift deleted file mode 100644 index 910f33b..0000000 --- a/old/Helpers/Set+Extensions.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation - -class ThreadSafeSet { - private var set: Set = [] - private let accessQueue = DispatchQueue(label: "com.example.ThreadSafeSet") - - func insert(_ newElement: T) { - _ = accessQueue.sync { - set.insert(newElement) - } - } - - func remove(_ element: T) { - _ = accessQueue.sync { - set.remove(element) - } - } - - var elements: Set { - accessQueue.sync { set } - } - - func contains(_ element: T) -> Bool { - accessQueue.sync { set.contains(element) } - } -} diff --git a/old/Helpers/String+Extensions.swift b/old/Helpers/String+Extensions.swift deleted file mode 100644 index 1bbdc25..0000000 --- a/old/Helpers/String+Extensions.swift +++ /dev/null @@ -1,106 +0,0 @@ -import CoreLocation -import Foundation -import SwiftUI - -extension String { - var firstLetter: String { - String(prefix(1)).uppercased() - } - - var makeReply: String { - let allLines = components(separatedBy: .newlines) - let nonBlankLines = allLines.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty } - var result = nonBlankLines.joined(separator: "\n") - result = "> \(result)" - return result - } - - var isLocation: Bool { - hasPrefix("geo:") - } - - var getLatLon: CLLocationCoordinate2D { - let geo = components(separatedBy: ":")[1] - let parts = geo.components(separatedBy: ",") - let lat = Double(parts[0]) ?? 0.0 - let lon = Double(parts[1]) ?? 0.0 - return CLLocationCoordinate2D(latitude: lat, longitude: lon) - } - - var isContact: Bool { - hasPrefix("contact:") - } - - var getContactJid: String { - components(separatedBy: ":")[1] - } -} - -extension String { - var attachmentType: MessageAttachmentType { - let ext = (self as NSString).pathExtension.lowercased() - - switch ext { - case "mov", "mp4", "avi": - return .movie - - case "jpg", "png", "gif": - return .image - - case "mp3", "wav", "m4a": - return .audio - - case "txt", "doc", "pdf": - return .file - - default: - return .file - } - } -} - -extension String { - var firstLetterColor: Color { - let firstLetter = self.firstLetter - switch firstLetter { - case "A", "M", "Y": - return Color.Rainbow.tortoiseLight500 - - case "B", "N", "Z": - return Color.Rainbow.orangeLight500 - - case "C", "O": - return Color.Rainbow.yellowLight500 - - case "D", "P": - return Color.Rainbow.greenLight500 - - case "E", "Q": - return Color.Rainbow.blueLight500 - - case "F", "R": - return Color.Rainbow.magentaLight500 - - case "G", "S": - return Color.Rainbow.tortoiseDark500 - - case "H", "T": - return Color.Rainbow.orangeDark500 - - case "I", "U": - return Color.Rainbow.yellowDark500 - - case "J", "V": - return Color.Rainbow.greenDark500 - - case "K", "W": - return Color.Rainbow.blueDark500 - - case "L", "X": - return Color.Rainbow.magentaDark500 - - default: - return Color.Rainbow.tortoiseLight500 - } - } -} diff --git a/old/Helpers/TimeInterval+Extensions.swift b/old/Helpers/TimeInterval+Extensions.swift deleted file mode 100644 index 0dde77a..0000000 --- a/old/Helpers/TimeInterval+Extensions.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -extension TimeInterval { - var minAndSec: String { - let minutes = Int(self) / 60 - let seconds = Int(self) % 60 - return String(format: "%02d:%02d", minutes, seconds) - } -} diff --git a/old/Helpers/UIApplication+Extensions.swift b/old/Helpers/UIApplication+Extensions.swift deleted file mode 100644 index 63550f5..0000000 --- a/old/Helpers/UIApplication+Extensions.swift +++ /dev/null @@ -1,10 +0,0 @@ -import UIKit - -func openAppSettings() { - if - let appSettingsUrl = URL(string: UIApplication.openSettingsURLString), - UIApplication.shared.canOpenURL(appSettingsUrl) - { - UIApplication.shared.open(appSettingsUrl, completionHandler: nil) - } -} diff --git a/old/Helpers/URL+Extensions.swift b/old/Helpers/URL+Extensions.swift deleted file mode 100644 index c84c26a..0000000 --- a/old/Helpers/URL+Extensions.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UniformTypeIdentifiers - -extension URL { - var mimeType: String { - let pathExtension = self.pathExtension - - if let uti = UTType(filenameExtension: pathExtension) { - return uti.preferredMIMEType ?? "application/octet-stream" - } else { - return "application/octet-stream" - } - } -} diff --git a/old/Helpers/UserDefaultsWrapper.swift b/old/Helpers/UserDefaultsWrapper.swift deleted file mode 100644 index 535e9e9..0000000 --- a/old/Helpers/UserDefaultsWrapper.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Foundation - -// Wrapper -@propertyWrapper -struct Storage { - private let key: String - private let defaultValue: T - - init(key: String, defaultValue: T) { - self.key = key - self.defaultValue = defaultValue - } - - var wrappedValue: T { - get { - // Read value from UserDefaults - UserDefaults.standard.object(forKey: key) as? T ?? defaultValue - } - set { - // Set value to UserDefaults - UserDefaults.standard.set(newValue, forKey: key) - } - } -} - -// Storage -private let keyLocalizationSelected = "conversations.classic.user.defaults.localizationSelected" - -enum UserSettings { - @Storage(key: keyLocalizationSelected, defaultValue: false) - static var localizationSelectedByUser: Bool -} diff --git a/old/Resources/Assets/Colors.xcassets/Contents.json b/old/Resources/Assets/Colors.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/old/Resources/Assets/Colors.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/Contents.json b/old/Resources/Assets/Colors.xcassets/material/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/background/Contents.json b/old/Resources/Assets/Colors.xcassets/material/background/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/background/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/background/dark.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/background/dark.colorset/Contents.json deleted file mode 100644 index bdb682b..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/background/dark.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xE4", - "green" : "0xE4", - "red" : "0xE4" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/background/light.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/background/light.colorset/Contents.json deleted file mode 100644 index b8c6d9e..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/background/light.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "235", - "green" : "235", - "red" : "235" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/elements/Contents.json b/old/Resources/Assets/Colors.xcassets/material/elements/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/elements/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/elements/active.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/elements/active.colorset/Contents.json deleted file mode 100644 index 5a42e0f..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/elements/active.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x4D", - "green" : "0x46", - "red" : "0x3C" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/elements/inactive.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/elements/inactive.colorset/Contents.json deleted file mode 100644 index 944aec1..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/elements/inactive.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xAC", - "green" : "0xA3", - "red" : "0x95" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/shape/Contents.json b/old/Resources/Assets/Colors.xcassets/material/shape/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/shape/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/shape/alternate.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/shape/alternate.colorset/Contents.json deleted file mode 100644 index 72469b0..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/shape/alternate.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "201", - "green" : "227", - "red" : "199" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/shape/black.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/shape/black.colorset/Contents.json deleted file mode 100644 index 1c18f8d..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/shape/black.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x62", - "green" : "0x59", - "red" : "0x4A" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/shape/separator.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/shape/separator.colorset/Contents.json deleted file mode 100644 index 3d66dc2..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/shape/separator.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "189", - "green" : "189", - "red" : "189" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/shape/white.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/shape/white.colorset/Contents.json deleted file mode 100644 index fafa476..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/shape/white.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xFF", - "green" : "0xFF", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/text/Contents.json b/old/Resources/Assets/Colors.xcassets/material/text/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/text/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/text/main.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/text/main.colorset/Contents.json deleted file mode 100644 index dfe1a2d..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/text/main.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x36", - "green" : "0x31", - "red" : "0x2A" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/text/sub.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/text/sub.colorset/Contents.json deleted file mode 100644 index 4db6d18..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/text/sub.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x78", - "green" : "0x6D", - "red" : "0x5A" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/material/text/white.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/material/text/white.colorset/Contents.json deleted file mode 100644 index 2cedebe..0000000 --- a/old/Resources/Assets/Colors.xcassets/material/text/white.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xEF", - "green" : "0xEF", - "red" : "0xEF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/Contents.json b/old/Resources/Assets/Colors.xcassets/old/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/background/Contents.json b/old/Resources/Assets/Colors.xcassets/old/background/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/background/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/primary/Contents.json b/old/Resources/Assets/Colors.xcassets/old/primary/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/primary/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/primary/c100.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/primary/c100.colorset/Contents.json deleted file mode 100644 index 2e838f5..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/primary/c100.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xD9", - "green" : "0xD7", - "red" : "0xD3" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/primary/c200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/primary/c200.colorset/Contents.json deleted file mode 100644 index 8bfa21b..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/primary/c200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xC2", - "green" : "0xBD", - "red" : "0xB5" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/primary/c400.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/primary/c400.colorset/Contents.json deleted file mode 100644 index c61781a..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/primary/c400.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x9A", - "green" : "0x8F", - "red" : "0x7D" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/primary/c50.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/primary/c50.colorset/Contents.json deleted file mode 100644 index a61d481..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/primary/c50.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xFF", - "green" : "0xFF", - "red" : "0xFE" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/primary/c500main.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/primary/c500main.colorset/Contents.json deleted file mode 100644 index d4b5ad5..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/primary/c500main.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x89", - "green" : "0x7C", - "red" : "0x66" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c100.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c100.colorset/Contents.json deleted file mode 100644 index 9d735e4..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c100.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xB4", - "green" : "0xEC", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c200.colorset/Contents.json deleted file mode 100644 index aaeed90..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x83", - "green" : "0xF0", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c300.colorset/Contents.json deleted file mode 100644 index a8c8ffc..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x52", - "green" : "0xD5", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c400.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c400.colorset/Contents.json deleted file mode 100644 index c24864c..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c400.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x2D", - "green" : "0xCA", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c50.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c50.colorset/Contents.json deleted file mode 100644 index c345981..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c50.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0xE1", - "green" : "0xF8", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c500main.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c500main.colorset/Contents.json deleted file mode 100644 index 11f3048..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c500main.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x14", - "green" : "0xC1", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c600.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c600.colorset/Contents.json deleted file mode 100644 index 2589002..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c600.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x0F", - "green" : "0xB3", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c700.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c700.colorset/Contents.json deleted file mode 100644 index b745fb4..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c700.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x0D", - "green" : "0xA0", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c800.colorset/Contents.json deleted file mode 100644 index 9024695..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x0C", - "green" : "0x8F", - "red" : "0xFE" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/secondary/c900.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/secondary/c900.colorset/Contents.json deleted file mode 100644 index 8b4228e..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/secondary/c900.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x0B", - "green" : "0x70", - "red" : "0xFE" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/text/Contents.json b/old/Resources/Assets/Colors.xcassets/old/text/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/text/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/text/main.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/text/main.colorset/Contents.json deleted file mode 100644 index 9c8eb66..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/text/main.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x2D", - "green" : "0x2D", - "red" : "0x2D" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/old/text/sub.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/old/text/sub.colorset/Contents.json deleted file mode 100644 index 2e42b95..0000000 --- a/old/Resources/Assets/Colors.xcassets/old/text/sub.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0x78", - "green" : "0x78", - "red" : "0x78" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/Contents.json deleted file mode 100644 index 6e96565..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blue200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blue200.colorset/Contents.json deleted file mode 100644 index 12b3b32..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blue200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.976", - "green" : "0.792", - "red" : "0.565" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blue300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blue300.colorset/Contents.json deleted file mode 100644 index 0b975d5..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blue300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.965", - "green" : "0.710", - "red" : "0.392" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blue500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blue500.colorset/Contents.json deleted file mode 100644 index 3c05e0a..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blue500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.953", - "green" : "0.588", - "red" : "0.129" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blue800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blue800.colorset/Contents.json deleted file mode 100644 index 865adb5..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blue800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.824", - "green" : "0.463", - "red" : "0.098" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueDark200.colorset/Contents.json deleted file mode 100644 index e29b366..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.855", - "green" : "0.659", - "red" : "0.624" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueDark300.colorset/Contents.json deleted file mode 100644 index 096e5f1..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.796", - "green" : "0.525", - "red" : "0.475" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueDark500.colorset/Contents.json deleted file mode 100644 index 22f8cb4..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.710", - "green" : "0.318", - "red" : "0.247" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueDark800.colorset/Contents.json deleted file mode 100644 index bf615f8..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueDark800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.624", - "green" : "0.247", - "red" : "0.188" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueLight200.colorset/Contents.json deleted file mode 100644 index 1ded918..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.980", - "green" : "0.831", - "red" : "0.506" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueLight300.colorset/Contents.json deleted file mode 100644 index f17585c..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.969", - "green" : "0.765", - "red" : "0.310" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueLight500.colorset/Contents.json deleted file mode 100644 index 9453b24..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.957", - "green" : "0.663", - "red" : "0.012" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/blueLight800.colorset/Contents.json deleted file mode 100644 index 2b85944..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/blueLight800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.820", - "green" : "0.533", - "red" : "0.008" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/brown200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/brown200.colorset/Contents.json deleted file mode 100644 index ce0b7bb..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/brown200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.643", - "green" : "0.667", - "red" : "0.737" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/brown300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/brown300.colorset/Contents.json deleted file mode 100644 index 957f0da..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/brown300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.498", - "green" : "0.533", - "red" : "0.631" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/brown500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/brown500.colorset/Contents.json deleted file mode 100644 index 2926f1b..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/brown500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.282", - "green" : "0.333", - "red" : "0.475" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/brown800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/brown800.colorset/Contents.json deleted file mode 100644 index 70e2f7c..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/brown800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.251", - "red" : "0.365" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark100.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenDark100.colorset/Contents.json deleted file mode 100644 index 72469b0..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark100.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "201", - "green" : "227", - "red" : "199" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenDark200.colorset/Contents.json deleted file mode 100644 index c7b6100..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "167", - "green" : "214", - "red" : "165" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenDark300.colorset/Contents.json deleted file mode 100644 index 0f3b846..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "132", - "green" : "199", - "red" : "129" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenDark500.colorset/Contents.json deleted file mode 100644 index ddfea69..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.314", - "green" : "0.686", - "red" : "0.298" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenDark800.colorset/Contents.json deleted file mode 100644 index 9dbb7a6..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenDark800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.235", - "green" : "0.557", - "red" : "0.220" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenLight200.colorset/Contents.json deleted file mode 100644 index 54f6a97..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.647", - "green" : "0.882", - "red" : "0.773" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenLight300.colorset/Contents.json deleted file mode 100644 index 2c4fe10..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.506", - "green" : "0.835", - "red" : "0.682" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenLight500.colorset/Contents.json deleted file mode 100644 index 89db920..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.290", - "green" : "0.765", - "red" : "0.545" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/greenLight800.colorset/Contents.json deleted file mode 100644 index 1acd954..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/greenLight800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.220", - "green" : "0.624", - "red" : "0.408" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark200.colorset/Contents.json deleted file mode 100644 index ef9328c..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.859", - "green" : "0.616", - "red" : "0.702" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark300.colorset/Contents.json deleted file mode 100644 index 3556135..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.804", - "green" : "0.459", - "red" : "0.584" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark500.colorset/Contents.json deleted file mode 100644 index 00e5075..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.718", - "green" : "0.227", - "red" : "0.404" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark800.colorset/Contents.json deleted file mode 100644 index 748a957..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaDark800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.659", - "green" : "0.176", - "red" : "0.318" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight200.colorset/Contents.json deleted file mode 100644 index 725c54c..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.847", - "green" : "0.576", - "red" : "0.808" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight300.colorset/Contents.json deleted file mode 100644 index d9fbdb8..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.784", - "green" : "0.408", - "red" : "0.729" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight500.colorset/Contents.json deleted file mode 100644 index 99500b7..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.690", - "green" : "0.153", - "red" : "0.612" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight800.colorset/Contents.json deleted file mode 100644 index 2921caf..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/magentaLight800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.635", - "green" : "0.122", - "red" : "0.482" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark200.colorset/Contents.json deleted file mode 100644 index fbe5e38..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.569", - "green" : "0.671", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark300.colorset/Contents.json deleted file mode 100644 index 58e2f9f..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.396", - "green" : "0.541", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark500.colorset/Contents.json deleted file mode 100644 index e219ac8..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.133", - "green" : "0.341", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark800.colorset/Contents.json deleted file mode 100644 index a63dd3e..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeDark800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.098", - "green" : "0.290", - "red" : "0.902" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight200.colorset/Contents.json deleted file mode 100644 index 6e70cd5..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.502", - "green" : "0.800", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight300.colorset/Contents.json deleted file mode 100644 index 799505c..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.302", - "green" : "0.718", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight500.colorset/Contents.json deleted file mode 100644 index 4f0878b..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.000", - "green" : "0.596", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight800.colorset/Contents.json deleted file mode 100644 index dfc0149..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/orangeLight800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.000", - "green" : "0.486", - "red" : "0.961" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/pink200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/pink200.colorset/Contents.json deleted file mode 100644 index 0becef6..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/pink200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.694", - "green" : "0.561", - "red" : "0.957" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/pink300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/pink300.colorset/Contents.json deleted file mode 100644 index 9e9e4b7..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/pink300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.573", - "green" : "0.384", - "red" : "0.941" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/pink500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/pink500.colorset/Contents.json deleted file mode 100644 index ddc3e1d..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/pink500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.388", - "green" : "0.118", - "red" : "0.914" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/pink800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/pink800.colorset/Contents.json deleted file mode 100644 index 463aa83..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/pink800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.357", - "green" : "0.094", - "red" : "0.761" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/red200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/red200.colorset/Contents.json deleted file mode 100644 index 518a736..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/red200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.604", - "green" : "0.604", - "red" : "0.937" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/red300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/red300.colorset/Contents.json deleted file mode 100644 index 94100b6..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/red300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.451", - "green" : "0.451", - "red" : "0.898" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/red500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/red500.colorset/Contents.json deleted file mode 100644 index 7afafeb..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/red500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.212", - "green" : "0.263", - "red" : "0.957" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/red800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/red800.colorset/Contents.json deleted file mode 100644 index 8972c91..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/red800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.184", - "green" : "0.184", - "red" : "0.827" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark200.colorset/Contents.json deleted file mode 100644 index 89f27af..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.769", - "green" : "0.796", - "red" : "0.502" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark300.colorset/Contents.json deleted file mode 100644 index 39d4eca..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.675", - "green" : "0.714", - "red" : "0.302" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark500.colorset/Contents.json deleted file mode 100644 index 13174d8..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.533", - "green" : "0.588", - "red" : "0.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark800.colorset/Contents.json deleted file mode 100644 index 24f01a5..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseDark800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.420", - "green" : "0.475", - "red" : "0.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight200.colorset/Contents.json deleted file mode 100644 index 0f87be6..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.918", - "green" : "0.871", - "red" : "0.502" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight300.colorset/Contents.json deleted file mode 100644 index 5d7af98..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.882", - "green" : "0.816", - "red" : "0.302" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight500.colorset/Contents.json deleted file mode 100644 index 20a4a22..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.831", - "green" : "0.737", - "red" : "0.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight800.colorset/Contents.json deleted file mode 100644 index 68b5f8d..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/tortoiseLight800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.655", - "green" : "0.592", - "red" : "0.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark200.colorset/Contents.json deleted file mode 100644 index 98fa97f..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.510", - "green" : "0.878", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark300.colorset/Contents.json deleted file mode 100644 index 6140117..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.310", - "green" : "0.835", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark500.colorset/Contents.json deleted file mode 100644 index 6ef924c..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.027", - "green" : "0.757", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark800.colorset/Contents.json deleted file mode 100644 index 93e32b7..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowDark800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.000", - "green" : "0.627", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight200.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight200.colorset/Contents.json deleted file mode 100644 index f1b174f..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight200.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.612", - "green" : "0.933", - "red" : "0.902" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight300.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight300.colorset/Contents.json deleted file mode 100644 index 74aa8a8..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight300.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.459", - "green" : "0.906", - "red" : "0.863" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight500.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight500.colorset/Contents.json deleted file mode 100644 index ac7f58f..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight500.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.224", - "green" : "0.863", - "red" : "0.804" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight800.colorset/Contents.json b/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight800.colorset/Contents.json deleted file mode 100644 index 8aa0219..0000000 --- a/old/Resources/Assets/Colors.xcassets/rainbow/yellowLight800.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "srgb", - "components" : { - "alpha" : "1.000", - "blue" : "0.169", - "green" : "0.706", - "red" : "0.686" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Images.xcassets/AppIcon.appiconset/Contents.json b/old/Resources/Assets/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 72c4225..0000000 --- a/old/Resources/Assets/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "images" : [ - { - "filename" : "logo2.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Images.xcassets/AppIcon.appiconset/logo2.png b/old/Resources/Assets/Images.xcassets/AppIcon.appiconset/logo2.png deleted file mode 100644 index 0eb872374a398105b5a417758f59e5c33192f217..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104462 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%0A^IIEwwZ!0%40 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�Y)rwLSF*=5P~`5~ST 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≻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 diff --git a/old/Resources/Assets/Images.xcassets/Contents.json b/old/Resources/Assets/Images.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/old/Resources/Assets/Images.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Assets/Images.xcassets/logo.imageset/Contents.json b/old/Resources/Assets/Images.xcassets/logo.imageset/Contents.json deleted file mode 100644 index aed7690..0000000 --- a/old/Resources/Assets/Images.xcassets/logo.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "logo2_wo_bg.png", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "original" - } -} diff --git a/old/Resources/Assets/Images.xcassets/logo.imageset/logo2_wo_bg.png b/old/Resources/Assets/Images.xcassets/logo.imageset/logo2_wo_bg.png deleted file mode 100644 index e8e80f9052aef5fbd00fec36a9b24e38d1b1d05c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152001 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�hh=E$DE7@ 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�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 jqvBV+@`P8cS+Y|6bHM)t>+&-r diff --git a/old/Resources/Preview Content/Preview Assets.xcassets/Contents.json b/old/Resources/Preview Content/Preview Assets.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/old/Resources/Preview Content/Preview Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/old/Resources/Strings/Localizable.strings b/old/Resources/Strings/Localizable.strings deleted file mode 100644 index 8458afc..0000000 --- a/old/Resources/Strings/Localizable.strings +++ /dev/null @@ -1,76 +0,0 @@ -// MARK: General -"Global.name" = "Conversartions Classic"; -"Global.ok" = "Ok"; -"Global.back" = "Back"; -"Global.cancel" = "Cancel"; -"Global.save" = "Save"; -"Global.Error.title" = "Error"; -"Global.Error.genericText" = "Something went wrong"; -"Global.Error.genericDbError" = "Database error"; - -// MARK: Onboar screen -"Start.subtitle" = "Free and secure messaging and calls between any existed messengers"; -"Start.Btn.login" = "Enter with JID"; -"Start.Btn.register" = "New Account"; -"Login.title" = "Let\'s go!"; -"Login.subtitle" = "Enter your JID, it should looks like email address"; -"Login.Hint.jid" = "user@domain.im"; -"Login.Hint.password" = "password"; -"Login.btn" = "Continue"; -"Login.Error.wrongPassword" = "Wrong password or JID"; -"Login.Error.noServer" = "Server not exists"; -"Login.Error.serverError" = "Server error. Check internet connection"; - -// MARK: Contacts screen -"Contacts.title" = "Contacts"; -"Contacts.sendMessage" = "Send message"; -"Contacts.editContact" = "Edit contact"; -"Contacts.selectContact" = "Select contact"; -"Contacts.deleteContact" = "Delete contact"; -"Contacts.Add.title" = "Add Contact"; -"Contacts.Add.explanation" = "Contact or group/channel name are usually JID in format name@domain.ltd (like email)"; -"Contacts.Add.error" = "Contact not added. Server returns error."; -"Contacts.Delete.title" = "Delete contact"; -"Contacts.Delete.message" = "You can delete contact from this device (contact will be available on other devices), or delete it completely"; -"Contacts.Delete.deleteFromDevice" = "Delete from device"; -"Contacts.Delete.deleteCompletely" = "Delete completely"; -"Contacts.Delete.error" = "Contact not deleted. Server returns error."; - - -// MARK: Chats screen -"Chats.title" = "Chats"; - -"Chat.title" = "Chat"; -"Chat.textfieldPrompt" = "Type a message"; - -"Chats.Create.Main.title" = "Create"; -"Chats.Create.Main.createGroup" = "Create public group"; -"Chats.Create.Main.createPrivateGroup" = "Create private group"; -"Chats.Create.Main.findGroup" = "Find public group"; - -// MARK: Accounts add screen -"Accounts.Add.or" = "or"; -"Accounts.Add.Exist.title" = "Add existing\naccount"; -"Accounts.Add.Exist.Prompt.jid" = "Enter your XMPP ID"; -"Accounts.Add.Exist.Prompt.password" = "Enter password"; -"Accounts.Add.Exist.Hint.jid" = "user@domain.im"; -"Accounts.Add.Exist.Hint.password" = "password"; -"Accounts.Add.Exist.Btn.link" = "create a new one"; -"Accounts.Add.Exist.Btn.main" = "Continue"; -"Accounts.Add.Exist.loginError" = "Wrong login or password"; - -// MARK: Server connecting indicator -"ServerConnectingIndicator.State.connecting" = "Connecting to server"; -"ServerConnectingIndicator.State.connected" = "Connected"; -"ServerConnectingIndicator.State.error" = "Server unreachable. Check internet connection and server name"; - -// MARK: Attachments -"Attachment.Prompt.main" = "Select attachment"; -"Attachment.Tab.media" = "Media"; -"Attachment.Tab.files" = "Files"; -"Attachment.Tab.location" = "Location"; -"Attachment.Tab.contacts" = "Contacts"; -"Attachment.Send.media" = "Send media"; -"Attachment.Send.location" = "Send location"; -"Attachment.Send.contact" = "Send contact"; -"Attachment.Downloading.retry" = "Retry"; diff --git a/old/Resources/launchscreen.storyboard b/old/Resources/launchscreen.storyboard deleted file mode 100644 index ed88f70..0000000 --- a/old/Resources/launchscreen.storyboard +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/old/Resources/server_features.plist b/old/Resources/server_features.plist deleted file mode 100644 index 9fa58d6..0000000 --- a/old/Resources/server_features.plist +++ /dev/null @@ -1,6598 +0,0 @@ - - - - - - xep - XEP-0001 - name - XMPP Extension Protocols - type - Procedural - status - Active - date - 2016-11-16 - description - - xmppId - - - - xep - XEP-0002 - name - Special Interest Groups (SIGs) - type - Procedural - status - Active - date - 2002-01-11 - description - - xmppId - - - - xep - XEP-0003 - name - Proxy Accept Socket Service (PASS) - type - Historical - status - Obsolete - date - 2009-06-03 - description - - xmppId - jabber:iq:pass - - - xep - XEP-0004 - name - Data Forms - type - Standards Track - status - Final - date - 2007-08-13 - description - - xmppId - - - - xep - XEP-0005 - name - Jabber Interest Groups - type - Informational - status - Obsolete - date - 2002-05-08 - description - - xmppId - - - - xep - XEP-0006 - name - Profiles - type - SIG Formation - status - Obsolete - date - 2002-05-08 - description - - xmppId - - - - xep - XEP-0007 - name - Conferencing SIG - type - SIG Proposal - status - Obsolete - date - 2002-05-08 - description - - xmppId - - - - xep - XEP-0008 - name - IQ-Based Avatars - type - Historical - status - Deferred - date - 2005-06-16 - description - - xmppId - jabber:x:avatar - - - xep - XEP-0009 - name - Jabber-RPC - type - Standards Track - status - Final - date - 2011-11-10 - description - - xmppId - jabber:iq:rpc - - - xep - XEP-0010 - name - Whiteboarding SIG - type - SIG Formation - status - Obsolete - date - 2002-05-08 - description - - xmppId - - - - xep - XEP-0011 - name - Jabber Browsing - type - Historical - status - Obsolete - date - 2009-06-03 - description - - xmppId - jabber:iq:browse - - - xep - XEP-0012 - name - Last Activity - type - Standards Track - status - Final - date - 2008-11-26 - description - - xmppId - jabber:iq:last - - - xep - XEP-0013 - name - Flexible Offline Message Retrieval - type - Standards Track - status - Draft - date - 2005-07-14 - description - - xmppId - http://jabber.org/protocol/offline - - - xep - XEP-0014 - name - Message Tone - type - Standards Track - status - Rejected - date - 2002-01-16 - description - - xmppId - jabber:x:tone - - - xep - XEP-0015 - name - Account Transfer - type - Standards Track - status - Rejected - date - 2002-04-18 - description - - xmppId - jabber:iq:accountxfer - - - xep - XEP-0016 - name - Privacy Lists - type - Standards Track - status - Deprecated - date - 2017-05-20 - description - - xmppId - jabber:iq:privacy - - - xep - XEP-0017 - name - Naive Packet Framing Protocol - type - Informational - status - Rejected - date - 2002-02-19 - description - - xmppId - - - - xep - XEP-0018 - name - Invisible Presence - type - Informational - status - Rejected - date - 2003-09-26 - description - - xmppId - - - - xep - XEP-0019 - name - Streamlining the SIGs - type - Procedural - status - Active - date - 2002-03-20 - description - - xmppId - - - - xep - XEP-0020 - name - Feature Negotiation - type - Standards Track - status - Deprecated - date - 2018-03-07 - description - - xmppId - http://jabber.org/protocol/feature-neg - - - xep - XEP-0021 - name - Jabber Event Notification Service (ENS) - type - Standards Track - status - Retracted - date - 2003-04-22 - description - - xmppId - http://xml.cataclysm.cx/jabber/ens/ - - - xep - XEP-0022 - name - Message Events - type - Historical - status - Obsolete - date - 2009-05-27 - description - - xmppId - jabber:x:event - - - xep - XEP-0023 - name - Message Expiration - type - Historical - status - Obsolete - date - 2009-06-03 - description - - xmppId - - - - xep - XEP-0024 - name - Publish/Subscribe - type - Standards Track - status - Retracted - date - 2003-04-22 - description - - xmppId - jabber:iq:pubsub - - - xep - XEP-0025 - name - Jabber HTTP Polling - type - Historical - status - Obsolete - date - 2009-06-03 - description - - xmppId - - - - xep - XEP-0026 - name - Internationalization (I18N) - type - Standards Track - status - Retracted - date - 2003-11-05 - description - - xmppId - - - - xep - XEP-0027 - name - Current Jabber OpenPGP Usage - type - Historical - status - Obsolete - date - 2014-03-14 - description - - xmppId - - - - xep - XEP-0028 - name - No Such XEP - type - Informational - status - Retracted - date - 2001-08-20 - description - - xmppId - - - - xep - XEP-0029 - name - Definition of Jabber Identifiers (JIDs) - type - Standards Track - status - Retracted - date - 2003-10-03 - description - - xmppId - - - - xep - XEP-0030 - name - Service Discovery - type - Standards Track - status - Final - date - 2017-10-03 - description - - xmppId - http://jabber.org/protocol/disco* - - - xep - XEP-0031 - name - A Framework For Securing Jabber Conversations - type - Standards Track - status - Deferred - date - 2002-07-09 - description - - xmppId - - - - xep - XEP-0032 - name - Jabber URI Scheme - type - Standards Track - status - Retracted - date - 2003-09-02 - description - - xmppId - - - - xep - XEP-0033 - name - Extended Stanza Addressing - type - Standards Track - status - Draft - date - 2017-01-11 - description - - xmppId - http://jabber.org/protocol/address - - - xep - XEP-0034 - name - SASL Integration - type - Standards Track - status - Retracted - date - 2003-11-05 - description - - xmppId - - - - xep - XEP-0035 - name - SSL/TLS Integration - type - Standards Track - status - Retracted - date - 2003-11-05 - description - - xmppId - - - - xep - XEP-0036 - name - Pub-Sub Subscriptions - type - Standards Track - status - Retracted - date - 2003-04-22 - description - - xmppId - jabber:iq:pubsub - - - xep - XEP-0037 - name - DSPS - Data Stream Proxy Service - type - Standards Track - status - Rejected - date - 2016-10-04 - description - - xmppId - - - - xep - XEP-0038 - name - Icon Styles - type - Standards Track - status - Deferred - date - 2003-06-02 - description - - xmppId - - - - xep - XEP-0039 - name - Statistics Gathering - type - Standards Track - status - Deferred - date - 2002-11-05 - description - - xmppId - http://jabber.org/protocol/stats - - - xep - XEP-0040 - name - Jabber Robust Publish-Subscribe - type - Standards Track - status - Retracted - date - 2004-07-26 - description - - xmppId - - - - xep - XEP-0041 - name - Reliable Entity Link - type - Standards Track - status - Retracted - date - 2003-09-30 - description - - xmppId - http://jabber.org/protocol/rel - - - xep - XEP-0042 - name - Jabber OOB Broadcast Service (JOBS) - type - Standards Track - status - Retracted - date - 2003-04-11 - description - - xmppId - http://jabber.org/protocol/jobs - - - xep - XEP-0043 - name - Jabber Database Access - type - Standards Track - status - Retracted - date - 2003-10-20 - description - - xmppId - http://openaether.org/projects/jabber_database.html - - - xep - XEP-0044 - name - Full Namespace Support for XML Streams - type - Standards Track - status - Deferred - date - 2002-08-26 - description - - xmppId - - - - xep - XEP-0045 - name - Multi-User Chat - type - Standards Track - status - Draft - date - 2018-07-31 - description - - xmppId - http://jabber.org/protocol/muc - - - xep - XEP-0046 - name - DTCP - type - Standards Track - status - Retracted - date - 2003-04-11 - description - - xmppId - http://jabber.org/protocol/dtcp - - - xep - XEP-0047 - name - In-Band Bytestreams - type - Standards Track - status - Final - date - 2012-06-22 - description - - xmppId - http://jabber.org/protocol/ibb - - - xep - XEP-0048 - name - Bookmarks - type - Standards Track - status - Draft - date - 2007-11-07 - description - - xmppId - storage:bookmarks - - - xep - XEP-0049 - name - Private XML Storage - type - Historical - status - Active - date - 2004-03-01 - description - - xmppId - jabber:iq:private - - - xep - XEP-0050 - name - Ad-Hoc Commands - type - Standards Track - status - Draft - date - 2016-12-03 - description - - xmppId - http://jabber.org/protocol/commands - - - xep - XEP-0051 - name - Connection Transfer - type - Standards Track - status - Deferred - date - 2009-07-07 - description - - xmppId - urn:xmpp:cxfr - - - xep - XEP-0052 - name - File Transfer - type - Standards Track - status - Retracted - date - 2003-09-30 - description - - xmppId - http://jabber.org/protocol/feature-neg - - - xep - XEP-0053 - name - XMPP Registrar Function - type - Procedural - status - Active - date - 2016-12-01 - description - - xmppId - - - - xep - XEP-0054 - name - vcard-temp - type - Historical - status - Active - date - 2008-07-16 - description - - xmppId - vcard-temp - - - xep - XEP-0055 - name - Jabber Search - type - Historical - status - Active - date - 2009-09-15 - description - - xmppId - jabber:iq:search - - - xep - XEP-0056 - name - Business Data Interchange - type - Standards Track - status - Deferred - date - 2002-11-18 - description - - xmppId - http://jabber.org/protocol/ebxml - - - xep - XEP-0057 - name - Extended Roster - type - Standards Track - status - Retracted - date - 2003-04-28 - description - - xmppId - - - - xep - XEP-0058 - name - Multi-User Text Editing - type - Standards Track - status - Deferred - date - 2002-11-12 - description - - xmppId - - - - xep - XEP-0059 - name - Result Set Management - type - Standards Track - status - Draft - date - 2006-09-20 - description - - xmppId - http://jabber.org/protocol/rsm - - - xep - XEP-0060 - name - Publish-Subscribe - type - Standards Track - status - Draft - date - 2018-05-14 - description - - xmppId - http://jabber.org/protocol/pubsub - - - xep - XEP-0061 - name - Shared Notes - type - Informational - status - Deferred - date - 2003-09-30 - description - - xmppId - http://www.jabber.org/protocol/sharednote - - - xep - XEP-0062 - name - Packet Filtering - type - Informational - status - Deferred - date - 2003-09-30 - description - - xmppId - http://jabber.org/protocol/filter - - - xep - XEP-0063 - name - Basic Filtering Operations - type - Informational - status - Deferred - date - 2003-09-30 - description - - xmppId - http://jabber.org/protocol/filter/basic - - - xep - XEP-0064 - name - XPath Filtering - type - Informational - status - Deferred - date - 2003-09-30 - description - - xmppId - http://jabber.org/protocol/filter/xpath - - - xep - XEP-0065 - name - SOCKS5 Bytestreams - type - Standards Track - status - Draft - date - 2015-09-17 - description - - xmppId - http://jabber.org/protocol/bytestreams - - - xep - XEP-0065 - name - Out of Band Data - type - Standards Track - status - Draft - date - 2006-08-15 - description - - xmppId - jabber:x:oob - - - xep - XEP-0066 - name - Out of Band Data - type - Standards Track - status - Draft - date - 2006-08-16 - description - - xmppId - jabber:iq:oob - - - xep - XEP-0067 - name - Stock Data Transmission - type - Standards Track - status - Deferred - date - 2003-07-19 - description - - xmppId - - - - xep - XEP-0068 - name - Field Standardization for Data Forms - type - Informational - status - Active - date - 2012-05-28 - description - - xmppId - - - - xep - XEP-0069 - name - Compliance SIG - type - SIG Formation - status - Deferred - date - 2003-01-29 - description - - xmppId - - - - xep - XEP-0070 - name - Verifying HTTP Requests via XMPP - type - Standards Track - status - Draft - date - 2016-12-09 - description - - xmppId - http://jabber.org/protocol/http-auth - - - xep - XEP-0071 - name - XHTML-IM - type - Standards Track - status - Deprecated - date - 2018-03-08 - description - - xmppId - http://jabber.org/protocol/xhtml-im - - - xep - XEP-0072 - name - SOAP Over XMPP - type - Standards Track - status - Draft - date - 2005-12-14 - description - - xmppId - http://jabber.org/protocol/soap - - - xep - XEP-0073 - name - Basic IM Protocol Suite - type - Standards Track - status - Obsolete - date - 2007-10-30 - description - - xmppId - - - - xep - XEP-0074 - name - Simple Access Control - type - Standards Track - status - Retracted - date - 2003-10-20 - description - - xmppId - http://jabber.org/protocol/sac - - - xep - XEP-0075 - name - Jabber Object Access Protocol (JOAP) - type - Standards Track - status - Deferred - date - 2003-05-22 - description - - xmppId - jabber:iq:joap - - - xep - XEP-0076 - name - Malicious Stanzas - type - Humorous - status - Active - date - 2003-04-01 - description - - xmppId - http://jabber.org/protocol/evil - - - xep - XEP-0077 - name - In-Band Registration - type - Standards Track - status - Final - date - 2012-01-25 - description - - xmppId - jabber:iq:register - - - xep - XEP-0078 - name - Non-SASL Authentication - type - Standards Track - status - Obsolete - date - 2008-10-29 - description - - xmppId - jabber:iq:auth - - - xep - XEP-0079 - name - Advanced Message Processing - type - Standards Track - status - Draft - date - 2005-11-30 - description - - xmppId - http://jabber.org/protocol/amp - - - xep - XEP-0080 - name - User Location - type - Standards Track - status - Draft - date - 2015-12-01 - description - - xmppId - http://jabber.org/protocol/geoloc - - - xep - XEP-0081 - name - Jabber MIME Type - type - Standards Track - status - Retracted - date - 2005-07-19 - description - - xmppId - - - - xep - XEP-0082 - name - XMPP Date and Time Profiles - type - Informational - status - Active - date - 2013-09-26 - description - - xmppId - - - - xep - XEP-0083 - name - Nested Roster Groups - type - Informational - status - Active - date - 2004-10-11 - description - - xmppId - roster:delimiter - - - xep - XEP-0084 - name - User Avatar - type - Standards Track - status - Draft - date - 2016-07-09 - description - - xmppId - - - - xep - XEP-0085 - name - Chat State Notifications - type - Standards Track - status - Final - date - 2009-09-23 - description - - xmppId - http://jabber.org/protocol/chatstates - - - xep - XEP-0086 - name - Error Condition Mappings - type - Informational - status - Deprecated - date - 2004-02-17 - description - - xmppId - - - - xep - XEP-0087 - name - Stream Initiation - type - Standards Track - status - Retracted - date - 2003-05-22 - description - - xmppId - http://jabber.org/protocol/si - - - xep - XEP-0088 - name - Client Webtabs - type - Informational - status - Deferred - date - 2004-03-14 - description - - xmppId - http://jabber.org/protocol/webtab - - - xep - XEP-0089 - name - Generic Alerts - type - Standards Track - status - Deferred - date - 2003-05-16 - description - - xmppId - http://jabber.org/protocol/alert - - - xep - XEP-0090 - name - Legacy Entity Time - type - Historical - status - Obsolete - date - 2009-05-27 - description - - xmppId - jabber:iq:time - - - xep - XEP-0091 - name - Legacy Delayed Delivery - type - Historical - status - Obsolete - date - 2009-05-27 - description - - xmppId - jabber:x:delay - - - xep - XEP-0092 - name - Software Version - type - Standards Track - status - Draft - date - 2007-02-15 - description - - xmppId - jabber:iq:version - - - xep - XEP-0093 - name - Roster Item Exchange - type - Historical - status - Deprecated - date - 2005-08-26 - description - - xmppId - - - - xep - XEP-0094 - name - Agent Information - type - Historical - status - Obsolete - date - 2003-10-08 - description - - xmppId - jabber:iq:agents - - - xep - XEP-0095 - name - Stream Initiation - type - Standards Track - status - Deprecated - date - 2017-11-29 - description - - xmppId - http://jabber.org/protocol/si - - - xep - XEP-0096 - name - SI File Transfer - type - Standards Track - status - Deprecated - date - 2017-11-29 - description - - xmppId - http://jabber.org/protocol/si/profile/file-transfer - - - xep - XEP-0097 - name - iCal Envelope - type - Standards Track - status - Deferred - date - 2003-06-10 - description - - xmppId - http://jabber.org/protocol/gw/ical - - - xep - XEP-0098 - name - Enhanced Private XML Storage - type - Standards Track - status - Deferred - date - 2003-06-25 - description - - xmppId - http://jabber.org/protocol/private-xml - - - xep - XEP-0099 - name - IQ Query Action Protocol - type - Standards Track - status - Deferred - date - 2003-06-25 - description - - xmppId - - - - xep - XEP-0100 - name - Gateway Interaction - type - Informational - status - Active - date - 2005-10-05 - description - - xmppId - - - - xep - XEP-0101 - name - HTTP Authentication using Jabber Tickets - type - Standards Track - status - Deferred - date - 2004-01-18 - description - - xmppId - - - - xep - XEP-0102 - name - Security Extensions - type - Standards Track - status - Deferred - date - 2003-06-25 - description - - xmppId - xmpp:sec - - - xep - XEP-0103 - name - URL Address Information - type - Standards Track - status - Deferred - date - 2004-01-20 - description - - xmppId - - - - xep - XEP-0104 - name - HTTP Scheme for URL Data - type - Standards Track - status - Deferred - date - 2004-01-20 - description - - xmppId - - - - xep - XEP-0105 - name - Tree Transfer Stream Initiation Profile - type - Standards Track - status - Deferred - date - 2003-09-22 - description - - xmppId - - - - xep - XEP-0106 - name - JID Escaping - type - Standards Track - status - Draft - date - 2016-07-08 - description - - xmppId - jid\20escaping - - - xep - XEP-0107 - name - User Mood - type - Standards Track - status - Draft - date - 2018-03-13 - description - - xmppId - http://jabber.org/protocol/mood - - - xep - XEP-0108 - name - User Activity - type - Standards Track - status - Draft - date - 2008-10-29 - description - - xmppId - http://jabber.org/protocol/activity - - - xep - XEP-0109 - name - Out-of-Office Messages - type - Standards Track - status - Deferred - date - 2010-05-24 - description - - xmppId - - - - xep - XEP-0110 - name - Generic Maps - type - Standards Track - status - Deferred - date - 2003-07-28 - description - - xmppId - http://jabber.org/protocol/map - - - xep - XEP-0111 - name - A Transport for Initiating and Negotiating Sessions (TINS) - type - Standards Track - status - Retracted - date - 2005-12-21 - description - - xmppId - http://jabber.org/protocol/tins - - - xep - XEP-0112 - name - User Physical Location - type - Standards Track - status - Obsolete - date - 2004-10-12 - description - - xmppId - http://jabber.org/protocol/physloc - - - xep - XEP-0113 - name - Simple Whiteboarding - type - Informational - status - Deferred - date - 2003-09-07 - description - - xmppId - http://jabber.org/protocol/swb - - - xep - XEP-0114 - name - Jabber Component Protocol - type - Historical - status - Active - date - 2012-01-25 - description - - xmppId - - - - xep - XEP-0115 - name - Entity Capabilities - type - Standards Track - status - Draft - date - 2016-10-06 - description - - xmppId - http://jabber.org/protocol/caps - - - xep - XEP-0116 - name - Encrypted Session Negotiation - type - Standards Track - status - Deferred - date - 2007-05-30 - description - - xmppId - http://www.xmpp.org/extensions/xep-0116.html#ns - - - xep - XEP-0117 - name - Intermediate IM Protocol Suite - type - Standards Track - status - Obsolete - date - 2007-10-30 - description - - xmppId - - - - xep - XEP-0118 - name - User Tune - type - Standards Track - status - Draft - date - 2008-01-30 - description - - xmppId - http://jabber.org/protocol/tune - - - xep - XEP-0119 - name - Extended Presence Protocol Suite - type - Standards Track - status - Retracted - date - 2006-08-08 - description - - xmppId - - - - xep - XEP-0120 - name - Infobits - type - Standards Track - status - Retracted - date - 2004-01-22 - description - - xmppId - http://jabber.org/protocol/infobits - - - xep - XEP-0121 - name - Dublin Core Infobits Mapping - type - Informational - status - Retracted - date - 2003-12-15 - description - - xmppId - - - - xep - XEP-0122 - name - Data Forms Validation - type - Standards Track - status - Draft - date - 2018-03-21 - description - - xmppId - http://jabber.org/protocol/xdata-validate - - - xep - XEP-0123 - name - Entity Metadata - type - Standards Track - status - Retracted - date - 2003-12-16 - description - - xmppId - - - - xep - XEP-0124 - name - Bidirectional-streams Over Synchronous HTTP (BOSH) - type - Standards Track - status - Draft - date - 2016-11-16 - description - - xmppId - - - - xep - XEP-0125 - name - vCard Infobits Mapping - type - Informational - status - Retracted - date - 2003-12-15 - description - - xmppId - - - - xep - XEP-0126 - name - Invisibility - type - Informational - status - Deprecated - date - 2005-08-19 - description - - xmppId - - - - xep - XEP-0127 - name - Common Alerting Protocol (CAP) Over XMPP - type - Informational - status - Active - date - 2004-12-09 - description - - xmppId - http://www.incident.com/cap/1.0 - - - xep - XEP-0128 - name - Service Discovery Extensions - type - Informational - status - Active - date - 2004-10-20 - description - - xmppId - - - - xep - XEP-0129 - name - WebDAV File Transfers - type - Standards Track - status - Deferred - date - 2007-04-19 - description - - xmppId - http://www.xmpp.org/extensions/xep-0129.html#ns - - - xep - XEP-0130 - name - Waiting Lists - type - Historical - status - Deprecated - date - 2012-04-18 - description - - xmppId - http://jabber.org/protocol/waitinglist - - - xep - XEP-0131 - name - Stanza Headers and Internet Metadata - type - Standards Track - status - Draft - date - 2006-07-12 - description - - xmppId - http://jabber.org/protocol/shim - - - xep - XEP-0132 - name - Presence Obtained via Kinesthetic Excitation (POKE) - type - Humorous - status - Active - date - 2004-04-01 - description - - xmppId - http://jabber.org/protocol/poke - - - xep - XEP-0133 - name - Service Administration - type - Informational - status - Active - date - 2017-07-15 - description - - xmppId - - - - xep - XEP-0134 - name - XMPP Design Guidelines - type - Informational - status - Active - date - 2004-12-09 - description - - xmppId - - - - xep - XEP-0135 - name - File Sharing - type - Standards Track - status - Deferred - date - 2004-06-04 - description - - xmppId - http://jabber.org/protocol/files - - - xep - XEP-0136 - name - Message Archiving - type - Standards Track - status - Deprecated - date - 2017-11-15 - description - - xmppId - urn:xmpp:archive* - - - xep - XEP-0137 - name - Publishing Stream Initiation Requests - type - Standards Track - status - Deprecated - date - 2018-02-28 - description - - xmppId - http://jabber.org/protocol/sipub - - - xep - XEP-0138 - name - Stream Compression - type - Standards Track - status - Final - date - 2009-05-27 - description - - xmppId - http://jabber.org/features/compress - - - xep - XEP-0139 - name - Security SIG - type - SIG Formation - status - Retracted - date - 2004-09-15 - description - - xmppId - - - - xep - XEP-0140 - name - Shared Groups - type - Informational - status - Retracted - date - 2004-10-27 - description - - xmppId - - - - xep - XEP-0141 - name - Data Forms Layout - type - Standards Track - status - Draft - date - 2005-05-12 - description - - xmppId - - - - xep - XEP-0142 - name - Workgroup Queues - type - Standards Track - status - Deferred - date - 2005-05-09 - description - - xmppId - http://jabber.org/protocol/workgroup - - - xep - XEP-0143 - name - Guidelines for Authors of XMPP Extension Protocols - type - Procedural - status - Active - date - 2016-12-02 - description - - xmppId - - - - xep - XEP-0144 - name - Roster Item Exchange - type - Standards Track - status - Draft - date - 2017-11-28 - description - - xmppId - http://jabber.org/protocol/rosterx - - - xep - XEP-0145 - name - Annotations - type - Historical - status - Active - date - 2006-03-23 - description - - xmppId - - - - xep - XEP-0146 - name - Remote Controlling Clients - type - Informational - status - Obsolete - date - 2017-11-07 - description - - xmppId - http://jabber.org/protocol/rc* - - - xep - XEP-0147 - name - XMPP URI Scheme Query Components - type - Informational - status - Active - date - 2006-09-13 - description - - xmppId - - - - xep - XEP-0148 - name - Instant Messaging Intelligence Quotient (IM IQ) - type - Humorous - status - Active - date - 2005-04-01 - description - - xmppId - jabber:iq:iq - - - xep - XEP-0149 - name - Time Periods - type - Informational - status - Active - date - 2006-01-24 - description - - xmppId - - - - xep - XEP-0150 - name - Use of Entity Tags in XMPP Extensions - type - Informational - status - Deferred - date - 2005-08-09 - description - - xmppId - - - - xep - XEP-0151 - name - Virtual Presence - type - Standards Track - status - Deferred - date - 2005-07-05 - description - - xmppId - - - - xep - XEP-0152 - name - Reachability Addresses - type - Standards Track - status - Draft - date - 2014-02-25 - description - - xmppId - urn:xmpp:reach:0 - - - xep - XEP-0153 - name - vCard-Based Avatars - type - Historical - status - Active - date - 2018-02-26 - description - - xmppId - - - - xep - XEP-0154 - name - User Profile - type - Standards Track - status - Deferred - date - 2008-04-18 - description - - xmppId - urn:xmpp:tmp:profile - - - xep - XEP-0155 - name - Stanza Session Negotiation - type - Standards Track - status - Draft - date - 2016-01-20 - description - - xmppId - http://jabber.org/protocol/feature-neg - - - xep - XEP-0156 - name - Discovering Alternative XMPP Connection Methods - type - Standards Track - status - Draft - date - 2018-07-21 - description - - xmppId - - - - xep - XEP-0157 - name - Contact Addresses for XMPP Services - type - Informational - status - Active - date - 2018-07-21 - description - - xmppId - - - - xep - XEP-0158 - name - CAPTCHA Forms - type - Standards Track - status - Draft - date - 2008-09-03 - description - - xmppId - - - - xep - XEP-0159 - name - Spim-Blocking Control - type - Standards Track - status - Deferred - date - 2006-07-11 - description - - xmppId - http://www.xmpp.org/extensions/xep-0159.html* - - - xep - XEP-0160 - name - Best Practices for Handling Offline Messages - type - Informational - status - Active - date - 2016-10-07 - description - - xmppId - msgoffline - - - xep - XEP-0161 - name - Abuse Reporting - type - Standards Track - status - Deferred - date - 2007-05-06 - description - - xmppId - urn:xmpp:tmp:abuse - - - xep - XEP-0162 - name - Best Practices for Roster and Subscription Management - type - Informational - status - Deferred - date - 2005-12-06 - description - - xmppId - - - - xep - XEP-0163 - name - Personal Eventing Protocol - type - Standards Track - status - Draft - date - 2018-03-18 - description - - xmppId - - - - xep - XEP-0164 - name - vCard Filtering - type - Standards Track - status - Deferred - date - 2005-11-16 - description - - xmppId - - - - xep - XEP-0165 - name - Best Practices to Discourage JID Mimicking - type - Informational - status - Deferred - date - 2007-12-13 - description - - xmppId - - - - xep - XEP-0166 - name - Jingle - type - Standards Track - status - Draft - date - 2016-05-17 - description - - xmppId - urn:xmpp:jingle:1 - - - xep - XEP-0167 - name - Jingle RTP Sessions - type - Standards Track - status - Draft - date - 2016-07-08 - description - - xmppId - - - - xep - XEP-0168 - name - Resource Application Priority - type - Standards Track - status - Deferred - date - 2008-09-26 - description - - xmppId - urn:xmpp:rap:0 - - - xep - XEP-0169 - name - Twas The Night Before Christmas (Jabber Version) - type - Humorous - status - Active - date - 2009-12-24 - description - - xmppId - - - - xep - XEP-0170 - name - Recommended Order of Stream Feature Negotiation - type - Informational - status - Active - date - 2007-01-04 - description - - xmppId - - - - xep - XEP-0171 - name - Language Translation - type - Standards Track - status - Draft - date - 2015-10-15 - description - - xmppId - urn:xmpp:langtrans - - - xep - XEP-0172 - name - User Nickname - type - Standards Track - status - Draft - date - 2012-03-21 - description - - xmppId - http://jabber.org/protocol/nick - - - xep - XEP-0173 - name - Pubsub Subscription Storage - type - Historical - status - Deferred - date - 2006-02-09 - description - - xmppId - storage:pubsubs - - - xep - XEP-0174 - name - Serverless Messaging - type - Standards Track - status - Final - date - 2018-02-08 - description - - xmppId - - - - xep - XEP-0175 - name - Best Practices for Use of SASL ANONYMOUS - type - Informational - status - Active - date - 2009-09-30 - description - - xmppId - - - - xep - XEP-0176 - name - Jingle ICE-UDP Transport Method - type - Standards Track - status - Draft - date - 2009-06-10 - description - - xmppId - urn:xmpp:jingle:transports:ice-udp* - - - xep - XEP-0177 - name - Jingle Raw UDP Transport Method - type - Standards Track - status - Draft - date - 2009-12-23 - description - - xmppId - urn:xmpp:jingle:transports:raw-udp* - - - xep - XEP-0178 - name - Best Practices for Use of SASL EXTERNAL with Certificates - type - Informational - status - Active - date - 2011-05-25 - description - - xmppId - - - - xep - XEP-0179 - name - Jingle IAX Transport Method - type - Standards Track - status - Deferred - date - 2006-03-23 - description - - xmppId - - - - xep - XEP-0180 - name - Jingle Video via RTP - type - Standards Track - status - Retracted - date - 2008-06-04 - description - - xmppId - urn:xmpp:tmp:jingle:apps:video-rtp - - - xep - XEP-0181 - name - Jingle DTMF - type - Standards Track - status - Deferred - date - 2009-10-02 - description - - xmppId - - - - xep - XEP-0182 - name - Application-Specific Error Conditions - type - Procedural - status - Active - date - 2008-03-05 - description - - xmppId - - - - xep - XEP-0183 - name - Jingle Telepathy Transport - type - Humorous - status - Active - date - 2006-04-01 - description - - xmppId - - - - xep - XEP-0184 - name - Message Delivery Receipts - type - Standards Track - status - Draft - date - 2011-03-01 - description - - xmppId - urn:xmpp:receipts - - - xep - XEP-0185 - name - Dialback Key Generation and Validation - type - Informational - status - Active - date - 2007-02-15 - description - - xmppId - - - - xep - XEP-0186 - name - Invisible Command - type - Standards Track - status - Proposed - date - 2017-11-29 - description - - xmppId - urn:xmpp:invisible:1 - - - xep - XEP-0187 - name - Offline Encrypted Sessions - type - Standards Track - status - Deferred - date - 2007-05-30 - description - - xmppId - http://www.xmpp.org/extensions/xep-0187.html#ns - - - xep - XEP-0188 - name - Cryptographic Design of Encrypted Sessions - type - Informational - status - Deferred - date - 2007-05-30 - description - - xmppId - - - - xep - XEP-0189 - name - Public Key Publishing - type - Standards Track - status - Deferred - date - 2010-07-15 - description - - xmppId - urn:xmpp:pubkey:2 - - - xep - XEP-0190 - name - Best Practice for Closing Idle Streams - type - Informational - status - Obsolete - date - 2012-03-06 - description - - xmppId - - - - xep - XEP-0191 - name - Blocking Command - type - Standards Track - status - Draft - date - 2015-03-12 - description - - xmppId - urn:xmpp:blocking - - - xep - XEP-0192 - name - Proposed Stream Feature Improvements - type - Standards Track - status - Obsolete - date - 2012-02-08 - description - - xmppId - - - - xep - XEP-0193 - name - Proposed Resource Binding Improvements - type - Standards Track - status - Obsolete - date - 2012-02-08 - description - - xmppId - - - - xep - XEP-0194 - name - User Chatting - type - Standards Track - status - Deferred - date - 2008-09-25 - description - - xmppId - urn:xmpp:chatting:0 - - - xep - XEP-0195 - name - User Browsing - type - Standards Track - status - Deferred - date - 2008-09-25 - description - - xmppId - urn:xmpp:browsing:0 - - - xep - XEP-0196 - name - User Gaming - type - Standards Track - status - Deferred - date - 2008-09-25 - description - - xmppId - urn:xmpp:gaming:0 - - - xep - XEP-0197 - name - User Viewing - type - Standards Track - status - Deferred - date - 2008-09-25 - description - - xmppId - urn:xmpp:viewing:0 - - - xep - XEP-0198 - name - Stream Management - type - Standards Track - status - Draft - date - 2018-07-19 - description - - xmppId - urn:xmpp:sm:3 - - - xep - XEP-0199 - name - XMPP Ping - type - Standards Track - status - Final - date - 2009-06-03 - description - - xmppId - urn:xmpp:ping - - - xep - XEP-0200 - name - Stanza Encryption - type - Standards Track - status - Deferred - date - 2007-05-30 - description - - xmppId - http://www.xmpp.org/extensions/xep-0200.html* - - - xep - XEP-0201 - name - Best Practices for Message Threads - type - Informational - status - Active - date - 2010-11-29 - description - - xmppId - - - - xep - XEP-0202 - name - Entity Time - type - Standards Track - status - Final - date - 2009-09-11 - description - - xmppId - urn:xmpp:time - - - xep - XEP-0203 - name - Delayed Delivery - type - Standards Track - status - Final - date - 2009-09-15 - description - - xmppId - urn:xmpp:delay - - - xep - XEP-0204 - name - Collaborative Data Objects - type - Standards Track - status - Deferred - date - 2007-01-17 - description - - xmppId - http://www.xmpp.org/extensions/xep-0204.html* - - - xep - XEP-0205 - name - Best Practices to Discourage Denial of Service Attacks - type - Informational - status - Active - date - 2009-01-07 - description - - xmppId - - - - xep - XEP-0206 - name - XMPP Over BOSH - type - Standards Track - status - Draft - date - 2014-04-09 - description - - xmppId - - - - xep - XEP-0207 - name - XMPP Eventing via Pubsub - type - Humorous - status - Active - date - 2007-04-01 - description - - xmppId - - - - xep - XEP-0208 - name - Bootstrapping Implementation of Jingle - type - Informational - status - Retracted - date - 2009-01-06 - description - - xmppId - - - - xep - XEP-0209 - name - Metacontacts - type - Standards Track - status - Deferred - date - 2007-04-10 - description - - xmppId - - - - xep - XEP-0210 - name - Requirements for Encrypted Sessions - type - Standards Track - status - Deferred - date - 2007-05-30 - description - - xmppId - - - - xep - XEP-0211 - name - XMPP Basic Client 2008 - type - Standards Track - status - Obsolete - date - 2007-07-11 - description - - xmppId - - - - xep - XEP-0212 - name - XMPP Basic Server 2008 - type - Standards Track - status - Obsolete - date - 2007-07-11 - description - - xmppId - - - - xep - XEP-0213 - name - XMPP Intermediate IM Client 2008 - type - Standards Track - status - Obsolete - date - 2007-07-11 - description - - xmppId - - - - xep - XEP-0214 - name - File Repository and Sharing - type - Standards Track - status - Deferred - date - 2009-01-05 - description - - xmppId - - - - xep - XEP-0215 - name - External Service Discovery - type - Standards Track - status - Deferred - date - 2015-10-20 - description - - xmppId - urn:xmpp:extdisco:2 - - - xep - XEP-0216 - name - XMPP Intermediate IM Server 2008 - type - Standards Track - status - Obsolete - date - 2007-07-11 - description - - xmppId - - - - xep - XEP-0217 - name - Simplified Encrypted Session Negotiation - type - Standards Track - status - Deferred - date - 2007-05-30 - description - - xmppId - - - - xep - XEP-0218 - name - Bootstrapping Implementation of Encrypted Sessions - type - Informational - status - Deferred - date - 2007-05-30 - description - - xmppId - - - - xep - XEP-0219 - name - Hop Check - type - Standards Track - status - Retracted - date - 2008-06-12 - description - - xmppId - http://www.xmpp.org/extensions/xep-0219.html#ns - - - xep - XEP-0220 - name - Server Dialback - type - Standards Track - status - Draft - date - 2015-03-12 - description - - xmppId - - - - xep - XEP-0221 - name - Data Forms Media Element - type - Standards Track - status - Draft - date - 2008-09-03 - description - - xmppId - urn:xmpp:media-element - - - xep - XEP-0222 - name - Persistent Storage of Public Data via PubSub - type - Informational - status - Active - date - 2008-09-08 - description - - xmppId - - - - xep - XEP-0223 - name - Persistent Storage of Private Data via PubSub - type - Informational - status - Active - date - 2018-03-28 - description - - xmppId - - - - xep - XEP-0224 - name - Attention - type - Standards Track - status - Draft - date - 2008-11-13 - description - - xmppId - urn:xmpp:attention:0 - - - xep - XEP-0225 - name - Component Connections - type - Standards Track - status - Deferred - date - 2008-10-06 - description - - xmppId - urn:xmpp:component:0 - - - xep - XEP-0226 - name - Message Stanza Profiles - type - Informational - status - Deferred - date - 2008-11-05 - description - - xmppId - - - - xep - XEP-0227 - name - Portable Import/Export Format for XMPP-IM Servers - type - Standards Track - status - Draft - date - 2010-03-12 - description - - xmppId - - - - xep - XEP-0228 - name - Requirements for Shared Editing - type - Standards Track - status - Deferred - date - 2007-08-22 - description - - xmppId - - - - xep - XEP-0229 - name - Stream Compression with LZW - type - Standards Track - status - Draft - date - 2007-09-26 - description - - xmppId - - - - xep - XEP-0230 - name - Service Discovery Notifications - type - Standards Track - status - Deferred - date - 2016-10-04 - description - - xmppId - - - - xep - XEP-0231 - name - Bits of Binary - type - Standards Track - status - Draft - date - 2008-09-03 - description - - xmppId - urn:xmpp:bob - - - xep - XEP-0232 - name - Software Information - type - Standards Track - status - Deferred - date - 2009-02-26 - description - - xmppId - - - - xep - XEP-0233 - name - XMPP Server Registration for use with Kerberos V5 - type - Standards Track - status - Draft - date - 2017-03-16 - description - - xmppId - - - - xep - XEP-0234 - name - Jingle File Transfer - type - Standards Track - status - Proposed - date - 2017-08-24 - description - - xmppId - urn:xmpp:jingle:apps:file-transfer:5 - - - xep - XEP-0235 - name - OAuth Over XMPP - type - Standards Track - status - Deferred - date - 2009-03-24 - description - - xmppId - urn:xmpp:oauth:0 - - - xep - XEP-0236 - name - Abuse Reporting - type - Standards Track - status - Retracted - date - 2008-05-09 - description - - xmppId - urn:xmpp:tmp:abuse - - - xep - XEP-0237 - name - Roster Versioning - type - Standards Track - status - Obsolete - date - 2012-02-08 - description - - xmppId - urn:xmpp:features:rosterver - - - xep - XEP-0238 - name - XMPP Protocol Flows for Inter-Domain Federation - type - Informational - status - Deferred - date - 2008-03-31 - description - - xmppId - - - - xep - XEP-0239 - name - Binary XMPP - type - Humorous - status - Active - date - 2008-04-01 - description - - xmppId - - - - xep - XEP-0240 - name - Auto-Discovery of JabberIDs - type - Standards Track - status - Deferred - date - 2008-04-30 - description - - xmppId - - - - xep - XEP-0241 - name - Encryption of Archived Messages - type - Standards Track - status - Deferred - date - 2008-04-30 - description - - xmppId - urn:xmpp:tmp:archive:encrypt - - - xep - XEP-0242 - name - XMPP Client Compliance 2009 - type - Standards Track - status - Obsolete - date - 2008-09-08 - description - - xmppId - - - - xep - XEP-0243 - name - XMPP Server Compliance 2009 - type - Standards Track - status - Obsolete - date - 2008-09-08 - description - - xmppId - - - - xep - XEP-0244 - name - IO Data - type - Standards Track - status - Deferred - date - 2008-06-18 - description - - xmppId - urn:xmpp:tmp:io-data - - - xep - XEP-0245 - name - The /me Command - type - Informational - status - Active - date - 2009-01-21 - description - - xmppId - - - - xep - XEP-0246 - name - End-to-End XML Streams - type - Standards Track - status - Deferred - date - 2016-01-20 - description - - xmppId - - - - xep - XEP-0247 - name - Jingle XML Streams - type - Standards Track - status - Deferred - date - 2009-02-20 - description - - xmppId - - - - xep - XEP-0248 - name - PubSub Collection Nodes - type - Standards Track - status - Deferred - date - 2010-09-28 - description - - xmppId - http://jabber.org/protocol/pubsub#collections - - - xep - XEP-0249 - name - Direct MUC Invitations - type - Standards Track - status - Draft - date - 2011-09-22 - description - - xmppId - - - - xep - XEP-0250 - name - C2C Authentication Using TLS - type - Standards Track - status - Deferred - date - 2008-09-08 - description - - xmppId - - - - xep - XEP-0251 - name - Jingle Session Transfer - type - Standards Track - status - Deferred - date - 2009-10-05 - description - - xmppId - - - - xep - XEP-0252 - name - BOSH Script Syntax - type - Historical - status - Deferred - date - 2008-10-31 - description - - xmppId - - - - xep - XEP-0253 - name - PubSub Chaining - type - Standards Track - status - Deferred - date - 2009-11-18 - description - - xmppId - http://jabber.org/protocol/pubsub#chaining - - - xep - XEP-0254 - name - PubSub Queueing - type - Standards Track - status - Deferred - date - 2008-11-13 - description - - xmppId - urn:xmpp:pubsub:queueing:0 - - - xep - XEP-0255 - name - Location Query - type - Standards Track - status - Deferred - date - 2009-04-09 - description - - xmppId - urn:xmpp:locationquery:0 - - - xep - XEP-0256 - name - Last Activity in Presence - type - Standards Track - status - Draft - date - 2009-09-15 - description - - xmppId - jabber:iq:last - - - xep - XEP-0257 - name - Client Certificate Management for SASL EXTERNAL - type - Standards Track - status - Deferred - date - 2012-07-18 - description - - xmppId - urn:xmpp:saslcert:1 - - - xep - XEP-0258 - name - Security Labels in XMPP - type - Standards Track - status - Draft - date - 2013-04-08 - description - - xmppId - urn:xmpp:sec-label:0 - - - xep - XEP-0259 - name - Message Mine-ing - type - Standards Track - status - Deferred - date - 2009-01-21 - description - - xmppId - urn:xmpp:tmp:mine:0 - - - xep - XEP-0260 - name - Jingle SOCKS5 Bytestreams Transport Method - type - Standards Track - status - Draft - date - 2018-05-04 - description - - xmppId - urn:xmpp:jingle:transports:s5b:1 - - - xep - XEP-0261 - name - Jingle In-Band Bytestreams Transport Method - type - Standards Track - status - Draft - date - 2011-09-23 - description - - xmppId - urn:xmpp:jingle:transports:ibb:* - - - xep - XEP-0262 - name - Use of ZRTP in Jingle RTP Sessions - type - Standards Track - status - Draft - date - 2011-06-15 - description - - xmppId - urn:xmpp:jingle:apps:rtp:zrtp:* - - - xep - XEP-0263 - name - ECO-XMPP - type - Humorous - status - Active - date - 2009-04-01 - description - - xmppId - - - - xep - XEP-0264 - name - Jingle Content Thumbnails - type - Standards Track - status - Deferred - date - 2015-08-26 - description - - xmppId - urn:xmpp:thumbs:1 - - - xep - XEP-0265 - name - Out-of-Band Stream Data - type - Standards Track - status - Deferred - date - 2009-04-02 - description - - xmppId - urn:xmpp:jingle:apps:out-of-band:0 - - - xep - XEP-0266 - name - Codecs for Jingle Audio - type - Standards Track - status - Draft - date - 2013-03-01 - description - - xmppId - - - - xep - XEP-0267 - name - Server Buddies - type - Standards Track - status - Deferred - date - 2012-05-29 - description - - xmppId - urn:xmpp:server-presence - - - xep - XEP-0268 - name - Incident Handling - type - Standards Track - status - Deferred - date - 2012-05-29 - description - - xmppId - urn:xmpp:incident:2 - - - xep - XEP-0269 - name - Jingle Early Media - type - Standards Track - status - Deferred - date - 2009-05-19 - description - - xmppId - - - - xep - XEP-0270 - name - XMPP Compliance Suites 2010 - type - Standards Track - status - Obsolete - date - 2017-01-28 - description - - xmppId - - - - xep - XEP-0271 - name - XMPP Nodes - type - Informational - status - Deferred - date - 2009-06-26 - description - - xmppId - - - - xep - XEP-0272 - name - Multiparty Jingle (Muji) - type - Standards Track - status - Deferred - date - 2009-09-11 - description - - xmppId - http://telepathy.freedesktop.org/muji - - - xep - XEP-0273 - name - Stanza Interception and Filtering Technology (SIFT) - type - Standards Track - status - Deferred - date - 2011-06-27 - description - - xmppId - urn:xmpp:sift:* - - - xep - XEP-0274 - name - Design Considerations for Digital Signatures in XMPP - type - Informational - status - Deferred - date - 2011-01-28 - description - - xmppId - - - - xep - XEP-0275 - name - Entity Reputation - type - Standards Track - status - Deferred - date - 2012-06-06 - description - - xmppId - urn:xmpp:reputation:0 - - - xep - XEP-0276 - name - Presence Decloaking - type - Standards Track - status - Deferred - date - 2012-07-13 - description - - xmppId - urn:xmpp:decloak:0 - - - xep - XEP-0277 - name - Microblogging over XMPP - type - Standards Track - status - Deferred - date - 2017-11-28 - description - - xmppId - - - - xep - XEP-0278 - name - Jingle Relay Nodes - type - Standards Track - status - Experimental - date - 2017-09-14 - description - - xmppId - http://jabber.org/protocol/jinglenodes* - - - xep - XEP-0279 - name - Server IP Check - type - Standards Track - status - Deferred - date - 2013-04-17 - description - - xmppId - urn:xmpp:sic:1 - - - xep - XEP-0280 - name - Message Carbons - type - Standards Track - status - Proposed - date - 2017-02-16 - description - - xmppId - urn:xmpp:carbons:2 - - - xep - XEP-0281 - name - DMUC1: Distributed Multi-User Chat - type - Standards Track - status - Retracted - date - 2010-07-20 - description - - xmppId - - - - xep - XEP-0282 - name - DMUC2: Distributed MUC - type - Standards Track - status - Deferred - date - 2010-06-11 - description - - xmppId - - - - xep - XEP-0283 - name - Moved - type - Standards Track - status - Experimental - date - 2018-08-06 - description - - xmppId - urn:xmpp:moved:0 - - - xep - XEP-0284 - name - Shared XML Editing - type - Standards Track - status - Deferred - date - 2010-07-02 - description - - xmppId - urn:xmpp:sxe:0 - - - xep - XEP-0285 - name - Encapsulating Digital Signatures in XMPP - type - Standards Track - status - Deferred - date - 2011-01-12 - description - - xmppId - urn:xmpp:signed:0 - - - xep - XEP-0286 - name - Mobile Considerations on LTE Networks - type - Informational - status - Active - date - 2018-01-25 - description - - xmppId - - - - xep - XEP-0287 - name - Spim Markers and Reports - type - Standards Track - status - Deferred - date - 2010-10-03 - description - - xmppId - urn:xmpp:spim-report:0 - - - xep - XEP-0287 - name - Spim Markers and Reports - type - Standards Track - status - Deferred - date - 2010-10-04 - description - - xmppId - urn:xmpp:spim-marker:0 - - - xep - XEP-0288 - name - Bidirectional Server-to-Server Connections - type - Standards Track - status - Draft - date - 2016-10-17 - description - - xmppId - urn:xmpp:bidi - - - xep - XEP-0289 - name - Federated MUC for Constrained Environments - type - Standards Track - status - Deferred - date - 2012-05-29 - description - - xmppId - http://isode.com/protocol/fmuc - - - xep - XEP-0290 - name - Encapsulated Digital Signatures in XMPP - type - Standards Track - status - Deferred - date - 2011-01-28 - description - - xmppId - urn:xmpp:dsig:0 - - - xep - XEP-0291 - name - Service Delegation - type - Standards Track - status - Deferred - date - 2011-01-26 - description - - xmppId - urn:xmpp:tmp:delegate - - - xep - XEP-0292 - name - vCard4 Over XMPP - type - Standards Track - status - Deferred - date - 2013-09-12 - description - - xmppId - urn:ietf:params:xml:ns:vcard-4.0 - - - xep - XEP-0293 - name - Jingle RTP Feedback Negotiation - type - Standards Track - status - Draft - date - 2015-08-11 - description - - xmppId - urn:xmpp:jingle:apps:rtp:rtcp-fb:0 - - - xep - XEP-0294 - name - Jingle RTP Header Extensions Negotiation - type - Standards Track - status - Draft - date - 2015-08-11 - description - - xmppId - urn:xmpp:jingle:apps:rtp:rtp-hdrext:0 - - - xep - XEP-0295 - name - JSON Encodings for XMPP - type - Humorous - status - Active - date - 2011-04-01 - description - - xmppId - - - - xep - XEP-0296 - name - Best Practices for Resource Locking - type - Informational - status - Deferred - date - 2011-08-18 - description - - xmppId - - - - xep - XEP-0297 - name - Stanza Forwarding - type - Standards Track - status - Draft - date - 2013-10-02 - description - - xmppId - urn:xmpp:forward:0 - - - xep - XEP-0298 - name - Delivering Conference Information to Jingle Participants (Coin) - type - Standards Track - status - Deferred - date - 2015-07-02 - description - - xmppId - urn:xmpp:coin:1 - - - xep - XEP-0299 - name - Codecs for Jingle Video - type - Standards Track - status - Deferred - date - 2011-06-12 - description - - xmppId - - - - xep - XEP-0300 - name - Use of Cryptographic Hash Functions in XMPP - type - Standards Track - status - Experimental - date - 2018-02-14 - description - - xmppId - urn:xmpp:hashes:2 - - - xep - XEP-0301 - name - In-Band Real Time Text - type - Standards Track - status - Draft - date - 2013-10-08 - description - - xmppId - urn:xmpp:rtt:0 - - - xep - XEP-0302 - name - XMPP Compliance Suites 2012 - type - Standards Track - status - Obsolete - date - 2011-07-21 - description - - xmppId - - - - xep - XEP-0303 - name - Commenting - type - Standards Track - status - Deferred - date - 2011-07-28 - description - - xmppId - urn:xmpp:tmp:comments:0 - - - xep - XEP-0304 - name - Whitespace Keepalive Negotiation - type - Standards Track - status - Deferred - date - 2011-08-18 - description - - xmppId - urn:xmpp:keepalive:0 - - - xep - XEP-0305 - name - XMPP Quickstart - type - Standards Track - status - Deferred - date - 2013-03-01 - description - - xmppId - - - - xep - XEP-0306 - name - Extensible Status Conditions for Multi-User Chat - type - Standards Track - status - Deferred - date - 2016-06-07 - description - - xmppId - urn:xmpp:muc:conditions:1 - - - xep - XEP-0307 - name - Unique Room Names for Multi-User Chat - type - Standards Track - status - Deferred - date - 2011-11-10 - description - - xmppId - http://jabber.org/protocol/muc#unique - - - xep - XEP-0308 - name - Last Message Correction - type - Standards Track - status - Draft - date - 2013-04-08 - description - - xmppId - urn:xmpp:message-correct:0 - - - xep - XEP-0309 - name - Service Directories - type - Standards Track - status - Deferred - date - 2012-05-29 - description - - xmppId - urn:xmpp:public-server - - - xep - XEP-0310 - name - Presence State Annotations - type - Standards Track - status - Deferred - date - 2012-01-10 - description - - xmppId - urn:xmpp:psa - - - xep - XEP-0311 - name - MUC Fast Reconnect - type - Standards Track - status - Deferred - date - 2012-01-25 - description - - xmppId - urn:xmpp:presence-session:0 - - - xep - XEP-0312 - name - PubSub Since - type - Standards Track - status - Deferred - date - 2012-05-29 - description - - xmppId - http://jabber.org/protocol/pubsub#since - - - xep - XEP-0313 - name - Message Archive Management - type - Standards Track - status - Experimental - date - 2018-07-16 - description - - xmppId - urn:xmpp:mam:2 - - - xep - XEP-0314 - name - Security Labels in PubSub - type - Standards Track - status - Deferred - date - 2012-07-27 - description - - xmppId - - - - xep - XEP-0315 - name - Data Forms XML Element - type - Standards Track - status - Deferred - date - 2012-10-15 - description - - xmppId - - - - xep - XEP-0316 - name - MUC Eventing Protocol - type - Standards Track - status - Deferred - date - 2013-01-03 - description - - xmppId - - - - xep - XEP-0317 - name - Hats - type - Standards Track - status - Deferred - date - 2013-01-03 - description - - xmppId - - - - xep - XEP-0318 - name - Best Practices for Client Initiated Presence Probes - type - Informational - status - Deferred - date - 2013-08-06 - description - - xmppId - - - - xep - XEP-0319 - name - Last User Interaction in Presence - type - Standards Track - status - Draft - date - 2017-07-17 - description - - xmppId - urn:xmpp:idle:1 - - - xep - XEP-0320 - name - Use of DTLS-SRTP in Jingle Sessions - type - Standards Track - status - Deferred - date - 2015-10-15 - description - - xmppId - urn:xmpp:jingle:apps:dtls:0 - - - xep - XEP-0321 - name - Remote Roster Management - type - Standards Track - status - Deferred - date - 2013-04-16 - description - - xmppId - urn:xmpp:tmp:roster-management:0 - - - xep - XEP-0322 - name - Efficient XML Interchange (EXI) Format - type - Standards Track - status - Deferred - date - 2018-01-25 - description - - xmppId - - - - xep - XEP-0323 - name - Internet of Things - Sensor Data - type - Standards Track - status - Retracted - date - 2017-05-20 - description - - xmppId - urn:xmpp:iot:sensordata - - - xep - XEP-0324 - name - Internet of Things - Provisioning - type - Standards Track - status - Retracted - date - 2017-05-20 - description - - xmppId - urn:xmpp:iot:provisioning - - - xep - XEP-0325 - name - Internet of Things - Control - type - Standards Track - status - Retracted - date - 2017-05-20 - description - - xmppId - urn:xmpp:iot:control - - - xep - XEP-0326 - name - Internet of Things - Concentrators - type - Standards Track - status - Retracted - date - 2017-05-20 - description - - xmppId - urn:xmpp:iot:concentrators - - - xep - XEP-0327 - name - Rayo - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:rayo:1 - - - xep - XEP-0328 - name - JID Prep - type - Standards Track - status - Deferred - date - 2013-05-28 - description - - xmppId - urn:xmpp:jidprep:0 - - - xep - XEP-0329 - name - File Information Sharing - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:fis:0 - - - xep - XEP-0330 - name - Pubsub Subscription - type - Standards Track - status - Deferred - date - 2013-06-11 - description - - xmppId - - - - xep - XEP-0331 - name - Data Forms - Color Field Types - type - Standards Track - status - Deferred - date - 2015-11-09 - description - - xmppId - - - - xep - XEP-0332 - name - HTTP over XMPP transport - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:http - - - xep - XEP-0333 - name - Chat Markers - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:chat-markers:0 - - - xep - XEP-0334 - name - Message Processing Hints - type - Standards Track - status - Deferred - date - 2018-01-25 - description - - xmppId - urn:xmpp:hints - - - xep - XEP-0335 - name - JSON Containers - type - Standards Track - status - Deferred - date - 2013-10-25 - description - - xmppId - urn:xmpp:json:0 - - - xep - XEP-0336 - name - Data Forms - Dynamic Forms - type - Standards Track - status - Deferred - date - 2015-11-09 - description - - xmppId - urn:xmpp:xdata:dynamic - - - xep - XEP-0337 - name - Event Logging over XMPP - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:eventlog - - - xep - XEP-0338 - name - Jingle Grouping Framework - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:ietf:rfc:5888 - - - xep - XEP-0339 - name - Source-Specific Media Attributes in Jingle - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:ietf:rfc:5576 - - - xep - XEP-0340 - name - COnferences with LIghtweight BRIdging (COLIBRI) - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - http://jitsi.org/protocol/colibri - - - xep - XEP-0341 - name - Rayo CPA - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:rayo:cpa:0 - - - xep - XEP-0342 - name - Rayo Fax - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:rayo:fax:1 - - - xep - XEP-0343 - name - Signaling WebRTC datachannels in Jingle - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0344 - name - Impact of TLS and DNSSEC on Dialback - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0345 - name - Form of Membership Applications - type - Procedural - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0346 - name - Form Discovery and Publishing - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0347 - name - Internet of Things - Discovery - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:iot:discovery - - - xep - XEP-0348 - name - Signing Forms - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:xdata:signature:oauth1 - - - xep - XEP-0349 - name - Rayo Clustering - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0350 - name - Data Forms Geolocation Element - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0351 - name - Recipient Server Side Notifications Filtering - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0352 - name - Client State Indication - type - Standards Track - status - Proposed - date - 2017-02-18 - description - - xmppId - urn:xmpp:csi:0 - - - xep - XEP-0353 - name - Jingle Message Initiation - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0354 - name - Customizable Message Routing - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:cmr:0 - - - xep - XEP-0355 - name - Namespace Delegation - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:delegation:1 - - - xep - XEP-0356 - name - Privileged Entity - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:privilege:1 - - - xep - XEP-0357 - name - Push Notifications - type - Standards Track - status - Experimental - date - 2017-08-24 - description - - xmppId - urn:xmpp:push:0 - - - xep - XEP-0358 - name - Publishing Available Jingle Sessions - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0359 - name - Unique and Stable Stanza IDs - type - Standards Track - status - Experimental - date - 2017-08-23 - description - - xmppId - urn:xmpp:sid:0 - - - xep - XEP-0360 - name - Nonzas (are not Stanzas) - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0361 - name - Zero Handshake Server to Server Protocol - type - Informational - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0362 - name - Raft over XMPP - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:raft - - - xep - XEP-0363 - name - HTTP File Upload - type - Standards Track - status - Proposed - date - 2018-05-30 - description - - xmppId - urn:xmpp:http:upload:0 - - - xep - XEP-0364 - name - Current Off-the-Record Messaging Usage - type - Informational - status - Deferred - date - 2017-01-28 - description - - xmppId - - - - xep - XEP-0365 - name - Server to Server communication over STANAG 5066 ARQ - type - Standards Track - status - Deferred - date - 2018-07-21 - description - - xmppId - - - - xep - XEP-0366 - name - Entity Versioning - type - Standards Track - status - Deferred - date - 2016-12-21 - description - - xmppId - urn:xmpp:entityver:0 - - - xep - XEP-0367 - name - Message Attaching - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:message-attaching:0 - - - xep - XEP-0368 - name - SRV records for XMPP over TLS - type - Standards Track - status - Draft - date - 2017-03-09 - description - - xmppId - - - - xep - XEP-0369 - name - Mediated Information eXchange (MIX) - type - Standards Track - status - Experimental - date - 2018-06-06 - description - - xmppId - urn:xmpp:mix:core:* - - - xep - XEP-0370 - name - Jingle HTTP Transport Method - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0371 - name - Jingle ICE Transport Method - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0372 - name - References - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:reference:0 - - - xep - XEP-0373 - name - OpenPGP for XMPP - type - Standards Track - status - Experimental - date - 2018-07-30 - description - - xmppId - - - - xep - XEP-0374 - name - OpenPGP for XMPP Instant Messaging - type - Standards Track - status - Deferred - date - 2018-01-25 - description - - xmppId - urn:xmpp:openpgp:im:0 - - - xep - XEP-0375 - name - XMPP Compliance Suites 2016 - type - Standards Track - status - Retracted - date - 2016-07-20 - description - - xmppId - - - - xep - XEP-0376 - name - Pubsub Account Management - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - - - - xep - XEP-0377 - name - Spam Reporting - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:reporting:* - - - xep - XEP-0378 - name - OTR Discovery - type - Standards Track - status - Deferred - date - 2017-09-11 - description - - xmppId - urn:xmpp:otr:0 - - - xep - XEP-0379 - name - Pre-Authenticated Roster Subscription - type - Standards Track - status - Experimental - date - 2017-03-06 - description - - xmppId - - - - xep - XEP-0380 - name - Explicit Message Encryption - type - Standards Track - status - Deferred - date - 2018-01-25 - description - - xmppId - urn:xmpp:eme:0 - - - xep - XEP-0381 - name - Internet of Things Special Interest Group (IoT SIG) - type - Procedural - status - Proposed - date - 2016-11-23 - description - - xmppId - - - - xep - XEP-0382 - name - Spoiler messages - type - Standards Track - status - Deferred - date - 2018-01-25 - description - - xmppId - urn:xmpp:spoiler:0 - - - xep - XEP-0383 - name - Burner JIDs - type - Standards Track - status - Deferred - date - 2017-01-28 - description - - xmppId - urn:xmpp:burner:0 - - - xep - XEP-0384 - name - OMEMO Encryption - type - Standards Track - status - Experimental - date - 2018-05-21 - description - - xmppId - eu.siacs.conversations.axolotl - - - xep - XEP-0385 - name - Stateless Inline Media Sharing (SIMS) - type - Standards Track - status - Experimental - date - 2018-01-25 - description - - xmppId - urn:xmpp:sims:1 - - - xep - XEP-0386 - name - Bind 2.0 - type - Standards Track - status - Deferred - date - 2018-02-08 - description - - xmppId - urn:xmpp:bind2:0 - - - xep - XEP-0387 - name - XMPP Compliance Suites 2018 - type - Standards Track - status - Draft - date - 2018-01-25 - description - - xmppId - - - - xep - XEP-0388 - name - Extensible SASL Profile - type - Standards Track - status - Experimental - date - 2017-08-24 - description - - xmppId - - - - xep - XEP-0389 - name - Extensible In-Band Registration - type - Standards Track - status - Experimental - date - 2017-03-16 - description - - xmppId - - - - xep - XEP-0390 - name - Entity Capabilities 2.0 - type - Standards Track - status - Experimental - date - 2017-06-14 - description - - xmppId - urn:xmpp:caps - - - xep - XEP-0391 - name - Jingle Encrypted Transports - type - Standards Track - status - Experimental - date - 2018-07-31 - description - - xmppId - urn:xmpp:jingle:jet:0 - - - xep - XEP-0392 - name - Consistent Color Generation - type - Standards Track - status - Experimental - date - 2018-07-28 - description - - xmppId - - - - xep - XEP-0393 - name - Message Styling - type - Standards Track - status - Experimental - date - 2018-05-01 - description - - xmppId - - - - xep - XEP-0394 - name - Message Markup - type - Standards Track - status - Experimental - date - 2017-11-22 - description - - xmppId - urn:xmpp:markup:0 - - - xep - XEP-0395 - name - Atomically Compare-And-Publish PubSub Items - type - Standards Track - status - Experimental - date - 2017-11-29 - description - - xmppId - - - - xep - XEP-0396 - name - Jingle Encrypted Transports - OMEMO - type - Standards Track - status - Experimental - date - 2017-11-29 - description - - xmppId - urn:xmpp:jingle:jet-omemo:0 - - - xep - XEP-0397 - name - Instant Stream Resumption - type - Standards Track - status - Experimental - date - 2018-01-22 - description - - xmppId - https://xmpp.org/extensions/isr/0 - - - xep - XEP-0398 - name - User Avatar to vCard-Based Avatars Conversion - type - Standards Track - status - Experimental - date - 2018-08-27 - description - - xmppId - urn:xmpp:pep-vcard-conversion:0 - - - xep - XEP-0399 - name - Client Key Support - type - Standards Track - status - Experimental - date - 2018-01-25 - description - - xmppId - urn:xmpp:client-key:0 - - - xep - XEP-0400 - name - Multi-Factor Authentication with TOTP - type - Standards Track - status - Experimental - date - 2018-01-25 - description - - xmppId - urn:xmpp:mfa:0 - - - xep - XEP-0401 - name - Easy User Onboarding - type - Standards Track - status - Experimental - date - 2018-02-11 - description - - xmppId - - - - xep - XEP-0402 - name - Bookmarks 2 (This Time it's Serious) - type - Standards Track - status - Experimental - date - 2018-07-22 - description - - xmppId - urn:xmpp:bookmarks:0 - - - xep - XEP-0403 - name - Mediated Information eXchange (MIX): Presence Support. - type - Standards Track - status - Experimental - date - 2018-06-06 - description - - xmppId - urn:xmpp:mix:nodes:presence - - - xep - XEP-0404 - name - Mediated Information eXchange (MIX): JID Hidden Channels. - type - Standards Track - status - Experimental - date - 2018-06-06 - description - - xmppId - - - - xep - XEP-0405 - name - Mediated Information eXchange (MIX): Participant Server Requirements - type - Standards Track - status - Experimental - date - 2018-06-06 - description - - xmppId - urn:xmpp:mix:pam:0 - - - xep - XEP-0406 - name - Mediated Information eXchange (MIX): MIX Administration - type - Standards Track - status - Experimental - date - 2018-06-06 - description - - xmppId - - - - xep - XEP-0407 - name - Mediated Information eXchange (MIX): Miscellaneous Capabilities - type - Standards Track - status - Experimental - date - 2018-05-14 - description - - xmppId - urn:xmpp:mix:misc:* - - - xep - XEP-0408 - name - Mediated Information eXchange (MIX): Co-existence with MUC - type - Standards Track - status - Experimental - date - 2018-05-21 - description - - xmppId - - - - xep - XEP-0409 - name - IM Routing-NG - type - Standards Track - status - Experimental - date - 2018-06-05 - description - - xmppId - urn:xmpp:im-ng:0 - - - xep - XEP-0410 - name - MUC Self-Ping (Schrödinger's Chat) - type - Standards Track - status - Experimental - date - 2018-08-31 - description - - xmppId - - - - diff --git a/old/View/BaseNavigationView.swift b/old/View/BaseNavigationView.swift deleted file mode 100644 index 558b471..0000000 --- a/old/View/BaseNavigationView.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Martin -import SwiftUI - -struct BaseNavigationView: View { - @EnvironmentObject var store: AppStore - - public var body: some View { - Group { - switch store.state.currentFlow { - case .start: - switch store.state.startState.navigation { - case .startScreen: - StartScreen() - - case .welcomeScreen: - WelcomeScreen() - } - - case .accounts: - switch store.state.accountsState.navigation { - case .addAccount: - AddAccountScreen() - } - - case .chats: - ChatsListScreen() - - case .contacts: - ContactsScreen() - - case .settings: - SettingsScreen() - - case .conversation: - ConversationScreen() - } - } - } -} diff --git a/old/View/Screens/AddAccountScreen.swift b/old/View/Screens/AddAccountScreen.swift deleted file mode 100644 index 1648429..0000000 --- a/old/View/Screens/AddAccountScreen.swift +++ /dev/null @@ -1,122 +0,0 @@ -import Combine -import Martin -import SwiftUI - -struct AddAccountScreen: View { - @EnvironmentObject var store: AppStore - - enum Field { - case userJid - case password - } - - @FocusState private var focus: Field? - @State private var errorMsg: String = "" - @State private var isShowingAlert = false - @State private var isShowingLoader = false - - #if DEBUG - @State private var jidStr: String = "nartest1@conversations.im" - @State private var pass: String = "nartest12345" - // @State private var jidStr: String = "test1@test.anal.company" - // @State private var pass: String = "12345" - #else - @State private var jidStr: String = "" - @State private var pass: String = "" - #endif - - public var body: some View { - ZStack { - // background - Color.Material.Background.light - .ignoresSafeArea() - - // content - VStack(spacing: 32) { - // icon - Image.logo - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 120, height: 120) - - // texts - VStack(spacing: 10) { - Text(L10n.Login.title) - .font(.head1l) - .foregroundColor(.Material.Text.main) - .fixedSize(horizontal: true, vertical: false) - Text(L10n.Login.subtitle) - .font(.body2) - .foregroundColor(.Material.Text.sub) - .multilineTextAlignment(.center) - .fixedSize(horizontal: false, vertical: true) - } - - VStack(spacing: 16) { - UniversalInputCollection.TextField( - prompt: L10n.Login.Hint.jid, - text: $jidStr, - focus: $focus, - fieldType: .userJid, - contentType: .emailAddress, - keyboardType: .emailAddress, - submitLabel: .next, - action: { - focus = .password - } - ) - UniversalInputCollection.SecureField( - prompt: L10n.Login.Hint.password, - text: $pass, - focus: $focus, - fieldType: .password, - submitLabel: .go, - action: { - focus = nil - } - ) - - Button { - isShowingLoader = true - store.dispatch(.accountsAction(.tryAddAccountWithCredentials(login: jidStr, password: pass))) - } label: { - Text(L10n.Login.btn) - } - .buttonStyle(PrimaryButtonStyle()) - .disabled(!loginInputValid) - - Button { - store.dispatch(.startAction(.goTo(.welcomeScreen))) - store.dispatch(.changeFlow(.start)) - } label: { - Text("\(Image(systemName: "chevron.left")) \(L10n.Global.back)") - .foregroundColor(.Material.Elements.active) - .font(.body2) - } - } - } - .padding(.horizontal, 32) - } - .loadingIndicator(isShowingLoader) - .alert(isPresented: $isShowingAlert) { - Alert( - title: Text(L10n.Global.Error.title), - message: Text(errorMsg), - dismissButton: .default(Text(L10n.Global.ok)) { - store.dispatch(.accountsAction(.addAccountError(jid: jidStr, reason: nil))) - } - ) - } - .onChange(of: store.state.accountsState.addAccountError) { err in - if let err { - isShowingLoader = false - isShowingAlert = true - errorMsg = err - } - } - } - - private var loginInputValid: Bool { - !jidStr.isEmpty && !pass.isEmpty && UniversalInputCollection.Validators.isEmail(jidStr) - } -} diff --git a/old/View/Screens/Chats/ChatsCreateMainScreen.swift b/old/View/Screens/Chats/ChatsCreateMainScreen.swift deleted file mode 100644 index c25b8f8..0000000 --- a/old/View/Screens/Chats/ChatsCreateMainScreen.swift +++ /dev/null @@ -1,182 +0,0 @@ -import SwiftUI - -struct ChatsCreateMainScreen: View { - @Binding var isPresented: Bool - - var body: some View { - ZStack { - // Background color - Color.Material.Background.light - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - SharedNavigationBar( - leftButton: .init( - image: Image(systemName: "xmark"), - action: { - isPresented = false - } - ), - centerText: .init(text: L10n.Chats.Create.Main.title) - ) - - // List - List { - // ChatsCreateRowButton( - // title: L10n.Chats.Create.Main.createGroup, - // image: "person.2.fill", - // action: {} - // ) - // ChatsCreateRowButton( - // title: L10n.Chats.Create.Main.createPrivateGroup, - // image: "person.2.fill", - // action: {} - // ) - // ChatsCreateRowButton( - // title: L10n.Chats.Create.Main.findGroup, - // image: "magnifyingglass", - // action: {} - // ) - - // for contacts list - let rosters = store.state.rostersState.rosters.filter { !$0.locallyDeleted } - if rosters.isEmpty { - ChatsCreateRowSeparator() - } - } - .listStyle(.plain) - - Spacer() - } - } - } -} - -// private struct ChatsCreateRowButton: View { -// var title: String -// var image: String -// var action: () -> Void -// -// var body: some View { -// VStack(alignment: .center, spacing: 0) { -// Spacer() -// HStack(alignment: .center, spacing: 16) { -// Image(systemName: image) -// .font(.head2) -// .foregroundColor(.Material.Elements.active) -// .padding(.leading, 16) -// Text(title) -// .font(.body1) -// .foregroundColor(.Material.Text.main) -// Spacer() -// } -// Spacer() -// Rectangle() -// .frame(maxWidth: .infinity) -// .frame(height: 1) -// .foregroundColor(.Material.Background.dark) -// } -// .sharedListRow() -// .frame(height: 48) -// .onTapGesture { -// action() -// } -// } -// } - -private struct ChatsCreateRowSeparator: View { - var body: some View { - Text("aa") - } -} - -// import SwiftUI -// -// struct CreateConversationMainScreen: View { -// @EnvironmentObject var store: AppStore -// -// var body: some View { -// ZStack { -// // Background color -// Color.Material.Background.light -// .ignoresSafeArea() -// -// // Content -// VStack(spacing: 0) { -// // Header -// CreateConversationHeader() -// -// // Chats list -// // if !store.state.chatsState.chats.isEmpty { -// // List { -// // ForEach(store.state.chatsState.chats) { chat in -// // ChatsRow(chat: chat) -// // } -// // } -// // .listStyle(.plain) -// // .background(Color.Material.Background.light) -// // } else { -// // Spacer() -// // } -// // -// // // Tab bar -// // SharedTabBar() -// } -// } -// } -// } -// -// private struct CreateConversationHeader: View { -// @EnvironmentObject var store: AppStore -// -// var body: some View { -// ZStack { -// // bg -// Color.Material.Background.dark -// .ignoresSafeArea() -// -// HStack(spacing: 0) { -// Image(systemName: "arrow.left") -// .foregroundColor(.Material.Elements.active) -// .padding(.leading, 16) -// .tappablePadding(.symmetric(12)) { -// store.dispatch(.changeFlow(store.state.previousFlow)) -// } -// Spacer() -// } -// -// // title -// Text("New conversation") -// .font(.head2) -// .foregroundColor(Color.Material.Text.main) -// } -// } -// } -// - -// Preview -#if DEBUG - struct ChatsCreateMainScreen_Previews: PreviewProvider { - static var previews: some View { - ChatsCreateMainScreen(isPresented: .constant(true)) - .environmentObject(pStore) - } - - static var pStore: AppStore { - let state = pState - return AppStore(initialState: state, reducer: AppState.reducer, middlewares: []) - } - - static var pState: AppState { - var state = AppState() - - state.rostersState.rosters = [ - .init(contactBareJid: "test@me.com", subscription: "both", ask: true, data: .init(groups: [], annotations: [])) - ] - - return state - } - } -#endif diff --git a/old/View/Screens/Chats/ChatsListScreen.swift b/old/View/Screens/Chats/ChatsListScreen.swift deleted file mode 100644 index 572c23c..0000000 --- a/old/View/Screens/Chats/ChatsListScreen.swift +++ /dev/null @@ -1,61 +0,0 @@ -import SwiftUI - -struct ChatsListScreen: View { - @EnvironmentObject var store: AppStore - - @State private var isCretePanelPresented = false - - var body: some View { - ZStack { - // Background color - Color.Material.Background.light - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - SharedNavigationBar( - centerText: .init(text: L10n.Chats.title), - rightButton: .init( - image: Image(systemName: "square.and.pencil"), - action: { - isCretePanelPresented = true - } - ) - ) - - // Chats list - if !store.state.chatsState.chats.isEmpty { - List { - ForEach(store.state.chatsState.chats) { chat in - ChatsRow(chat: chat) - } - } - .listStyle(.plain) - .background(Color.Material.Background.light) - } else { - Spacer() - } - - // Tab bar - SharedTabBar() - } - } - .fullScreenCover(isPresented: $isCretePanelPresented) { - ChatsCreateMainScreen(isPresented: $isCretePanelPresented) - } - } -} - -private struct ChatsRow: View { - @EnvironmentObject var store: AppStore - - var chat: Chat - - var body: some View { - SharedListRow(iconType: .charCircle(chat.participant), text: chat.participant) - .onTapGesture { - store.dispatch(.chatsAction(.startChat(accountJid: chat.account, participantJid: chat.participant))) - } - } -} diff --git a/old/View/Screens/Contacts/AddContactOrChannelScreen.swift b/old/View/Screens/Contacts/AddContactOrChannelScreen.swift deleted file mode 100644 index 56897f7..0000000 --- a/old/View/Screens/Contacts/AddContactOrChannelScreen.swift +++ /dev/null @@ -1,148 +0,0 @@ -import SwiftUI - -struct AddContactOrChannelScreen: View { - @EnvironmentObject var store: AppStore - - enum Field { - case account - case contact - } - - @FocusState private var focus: Field? - - @Binding var isPresented: Bool - @State private var contactJID: String = "" - @State private var ownerAccount: Account? - - @State private var isShowingLoader = false - @State private var isShowingAlert = false - @State private var errorMsg = "" - - var body: some View { - ZStack { - // Background color - Color.Material.Background.light - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - SharedNavigationBar( - leftButton: .init( - image: Image(systemName: "xmark"), - action: { - isPresented = false - } - ), - centerText: .init(text: L10n.Contacts.Add.title), - rightButton: .init( - image: Image(systemName: "plus.viewfinder"), - action: { - print("Scan QR-code") - } - ) - ) - - VStack(spacing: 16) { - // Explanation text - - Text(L10n.Contacts.Add.explanation) - .font(.body3) - .foregroundColor(.Material.Shape.separator) - .multilineTextAlignment(.center) - .padding(.top, 16) - - // Account selector - HStack(spacing: 0) { - Text("Use account:") - .font(.body2) - .foregroundColor(.Material.Text.main) - .frame(alignment: .leading) - Spacer() - } - UniversalInputCollection.DropDownMenu( - prompt: "Use account", - elements: store.state.accountsState.accounts, - selected: $ownerAccount, - focus: $focus, - fieldType: .account - ) - - // Contact text input - HStack(spacing: 0) { - Text("Contact JID:") - .font(.body2) - .foregroundColor(.Material.Text.main) - .frame(alignment: .leading) - Spacer() - } - UniversalInputCollection.TextField( - prompt: "Contact or channel JID", - text: $contactJID, - focus: $focus, - fieldType: .contact, - contentType: .emailAddress, - keyboardType: .emailAddress, - submitLabel: .done, - action: { - focus = .account - } - ) - - // Save button - Button { - save() - } label: { - Text(L10n.Global.save) - } - .buttonStyle(PrimaryButtonStyle()) - .disabled(!inputValid) - .padding(.top) - Spacer() - } - .padding(.horizontal, 32) - } - } - .onAppear { - if let exists = store.state.accountsState.accounts.first, exists.isActive { - ownerAccount = exists - } - } - .loadingIndicator(isShowingLoader) - .alert(isPresented: $isShowingAlert) { - Alert( - title: Text(L10n.Global.Error.title), - message: Text(errorMsg), - dismissButton: .default(Text(L10n.Global.ok)) - ) - } - .onChange(of: store.state.rostersState.newAddedRosterJid) { jid in - if jid != nil, isShowingLoader { - isShowingLoader = false - isPresented = false - } - } - .onChange(of: store.state.rostersState.newAddedRosterError) { error in - if let error = error, isShowingLoader { - isShowingLoader = false - errorMsg = error - isShowingAlert = true - } - } - } - - private var inputValid: Bool { - ownerAccount != nil && !contactJID.isEmpty && UniversalInputCollection.Validators.isEmail(contactJID) - } - - private func save() { - guard let ownerAccount else { return } - if let exists = store.state.rostersState.rosters.first(where: { $0.bareJid == ownerAccount.bareJid && $0.contactBareJid == contactJID }), exists.locallyDeleted { - store.dispatch(.rostersAction(.unmarkRosterAsLocallyDeleted(ownerJID: ownerAccount.bareJid, contactJID: contactJID))) - isPresented = false - } else { - isShowingLoader = true - store.dispatch(.rostersAction(.addRoster(ownerJID: ownerAccount.bareJid, contactJID: contactJID, name: nil, groups: []))) - } - } -} diff --git a/old/View/Screens/Contacts/ContactsScreen.swift b/old/View/Screens/Contacts/ContactsScreen.swift deleted file mode 100644 index d47c736..0000000 --- a/old/View/Screens/Contacts/ContactsScreen.swift +++ /dev/null @@ -1,172 +0,0 @@ -import SwiftUI - -struct ContactsScreen: View { - @EnvironmentObject var store: AppStore - - @State private var addPanelPresented = false - @State private var isErrorAlertPresented = false - @State private var errorAlertMessage = "" - @State private var isShowingLoader = false - - var body: some View { - ZStack { - // Background color - Color.Material.Background.light - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - SharedNavigationBar( - centerText: .init(text: L10n.Contacts.title), - rightButton: .init( - image: Image(systemName: "plus"), - action: { - addPanelPresented = true - } - ) - ) - - // Contacts list - let rosters = store.state.rostersState.rosters.filter { !$0.locallyDeleted } - if !rosters.isEmpty { - List { - ForEach(rosters) { roster in - ContactsScreenRow( - roster: roster, - isErrorAlertPresented: $isErrorAlertPresented, - errorAlertMessage: $errorAlertMessage, - isShowingLoader: $isShowingLoader - ) - } - } - .listStyle(.plain) - .background(Color.Material.Background.light) - } else { - Spacer() - } - - // Tab bar - SharedTabBar() - } - } - .loadingIndicator(isShowingLoader) - .fullScreenCover(isPresented: $addPanelPresented) { - AddContactOrChannelScreen(isPresented: $addPanelPresented) - } - .alert(isPresented: $isErrorAlertPresented) { - Alert( - title: Text(L10n.Global.Error.title), - message: Text(errorAlertMessage), - dismissButton: .default(Text(L10n.Global.ok)) - ) - } - } -} - -private struct ContactsScreenRow: View { - @EnvironmentObject var store: AppStore - - var roster: Roster - @State private var isShowingMenu = false - @State private var isDeleteAlertPresented = false - - @Binding var isErrorAlertPresented: Bool - @Binding var errorAlertMessage: String - @Binding var isShowingLoader: Bool - - var body: some View { - SharedListRow( - iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter), - text: roster.contactBareJid - ) - // VStack(spacing: 0) { - // HStack(spacing: 8) { - // ZStack { - // Circle() - // .frame(width: 44, height: 44) - // .foregroundColor(.red) - // Text(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter) - // .foregroundColor(.white) - // .font(.body1) - // } - // Text(roster.contactBareJid) - // .foregroundColor(Color.Material.Text.main) - // .font(.body2) - // Spacer() - // } - // .padding(.horizontal, 16) - // .padding(.vertical, 4) - // Rectangle() - // .frame(maxWidth: .infinity) - // .frame(height: 1) - // .foregroundColor(.Material.Background.dark) - // } - // .sharedListRow() - .onTapGesture { - store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid))) - } - .onLongPressGesture { - isShowingMenu.toggle() - } - .swipeActions(edge: .trailing, allowsFullSwipe: false) { - Button { - isDeleteAlertPresented = true - } label: { - Label(L10n.Contacts.sendMessage, systemImage: "trash") - } - .tint(Color.red) - } - .contextMenu { - Button(L10n.Contacts.sendMessage, systemImage: "message") { - store.dispatch(.chatsAction(.startChat(accountJid: roster.bareJid, participantJid: roster.contactBareJid))) - } - Divider() - - Button(L10n.Contacts.editContact) { - print("Edit contact") - } - - Button(L10n.Contacts.selectContact) { - print("Select contact") - } - - Divider() - Button(L10n.Contacts.deleteContact, systemImage: "trash", role: .destructive) { - isDeleteAlertPresented = true - } - } - .actionSheet(isPresented: $isDeleteAlertPresented) { - ActionSheet( - title: Text(L10n.Contacts.Delete.title), - message: Text(L10n.Contacts.Delete.message), - buttons: [ - .destructive(Text(L10n.Contacts.Delete.deleteFromDevice)) { - store.dispatch(.rostersAction(.markRosterAsLocallyDeleted(ownerJID: roster.bareJid, contactJID: roster.contactBareJid))) - }, - .destructive(Text(L10n.Contacts.Delete.deleteCompletely)) { - isShowingLoader = true - store.dispatch(.rostersAction(.deleteRoster(ownerJID: roster.bareJid, contactJID: roster.contactBareJid))) - }, - .cancel(Text(L10n.Global.cancel)) - ] - ) - } - .onChange(of: store.state.rostersState.rosters) { _ in - endOfDeleting() - } - .onChange(of: store.state.rostersState.deleteRosterError) { _ in - endOfDeleting() - } - } - - private func endOfDeleting() { - if isShowingLoader { - isShowingLoader = false - if let error = store.state.rostersState.deleteRosterError { - errorAlertMessage = error - isErrorAlertPresented = true - } - } - } -} diff --git a/old/View/Screens/Conversation/ConversationMessageContainer.swift b/old/View/Screens/Conversation/ConversationMessageContainer.swift deleted file mode 100644 index 0de1616..0000000 --- a/old/View/Screens/Conversation/ConversationMessageContainer.swift +++ /dev/null @@ -1,254 +0,0 @@ -import AVKit -import MapKit -import QuickLook -import SwiftUI - -struct ConversationMessageContainer: View { - let message: Message - let isOutgoing: Bool - - var body: some View { - if let msgText = message.body, msgText.isLocation { - EmbededMapView(location: msgText.getLatLon) - } else if let msgText = message.body, msgText.isContact { - ContactView(message: message) - } else if message.attachmentType != nil { - AttachmentView(message: message) - } else { - Text(message.body ?? "...") - .font(.body2) - .foregroundColor(.Material.Text.main) - .multilineTextAlignment(.leading) - .padding(10) - } - } -} - -struct MessageAttr: View { - let message: Message - - var body: some View { - VStack(alignment: .leading, spacing: 0) { - Text(message.date, style: .time) - .font(.sub2) - .foregroundColor(.Material.Shape.separator) - Spacer() - if message.sentError { - Image(systemName: "exclamationmark.circle") - .font(.body3) - .foregroundColor(.Rainbow.red500) - } else if message.pending { - Image(systemName: "clock") - .font(.body3) - .foregroundColor(.Material.Shape.separator) - } - } - } -} - -private struct EmbededMapView: View { - let location: CLLocationCoordinate2D - - var body: some View { - Map( - coordinateRegion: .constant(MKCoordinateRegion(center: location, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))), - interactionModes: [], - showsUserLocation: false, - userTrackingMode: .none, - annotationItems: [location], - annotationContent: { _ in - MapMarker(coordinate: location, tint: .blue) - } - ) - .frame(width: Const.mapPreviewSize, height: Const.mapPreviewSize) - .onTapGesture { - let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: location)) - mapItem.name = "Location" - mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]) - } - } -} - -private struct ContactView: View { - let message: Message - - var body: some View { - VStack { - ZStack { - Circle() - .frame(width: 44, height: 44) - .foregroundColor(contactName.firstLetterColor) - Text(contactName.firstLetter) - .foregroundColor(.white) - .font(.body1) - } - Text(message.body?.getContactJid ?? "...") - .font(.body2) - .foregroundColor(.Material.Text.main) - .multilineTextAlignment(.leading) - } - .padding() - .onTapGesture { - // TODO: Jump to add roster from here - } - } - - private var contactName: String { - message.body?.getContactJid ?? "?" - } -} - -private struct AttachmentView: View { - let message: Message - - var body: some View { - if message.attachmentDownloadFailed || (message.attachmentLocalName != nil && message.sentError) { - failed - } else { - switch message.attachmentType { - case .image: - if let thumbnail = thumbnail() { - thumbnail - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) - } else { - placeholder - } - - case .movie: - if let file = message.attachmentLocalPath { - VideoPlayerView(url: file) - .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) - } else { - placeholder - } - - case .file: - if let file = message.attachmentLocalPath { - DocumentPreview(url: file) - .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) - } else { - placeholder - } - - default: - placeholder - } - } - } - - @ViewBuilder private var placeholder: some View { - Rectangle() - .foregroundColor(.Material.Background.dark) - .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) - .overlay { - ZStack { - ProgressView() - .scaleEffect(1.5) - .progressViewStyle(CircularProgressViewStyle(tint: .Material.Elements.active)) - let imageName = progressImageName(message.attachmentType ?? .file) - Image(systemName: imageName) - .font(.body1) - .foregroundColor(.Material.Elements.active) - } - } - } - - @ViewBuilder private var failed: some View { - Rectangle() - .foregroundColor(.Material.Background.dark) - .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) - .overlay { - ZStack { - VStack { - Text(L10n.Attachment.Downloading.retry) - .font(.body3) - .foregroundColor(.Rainbow.red500) - Image(systemName: "exclamationmark.arrow.triangle.2.circlepath") - .font(.body1) - .foregroundColor(.Rainbow.red500) - } - } - } - .onTapGesture { - if let url = message.attachmentRemotePath { - store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: url))) - } else if message.attachmentLocalName != nil && message.sentError { - store.dispatch(.sharingAction(.retrySharing(messageId: message.id))) - } - } - } - - private func progressImageName(_ type: MessageAttachmentType) -> String { - switch type { - case .image: - return "photo" - - case .audio: - return "music.note" - - case .movie: - return "film" - - case .file: - return "doc" - } - } - - private func thumbnail() -> Image? { - guard let thumbnailPath = message.attachmentThumbnailPath else { return nil } - guard let uiImage = UIImage(contentsOfFile: thumbnailPath.path()) else { return nil } - return Image(uiImage: uiImage) - } -} - -// TODO: Make video player better! -private struct VideoPlayerView: UIViewControllerRepresentable { - let url: URL - - func makeUIViewController(context _: Context) -> AVPlayerViewController { - let controller = AVPlayerViewController() - controller.player = AVPlayer(url: url) - controller.allowsPictureInPicturePlayback = true - return controller - } - - func updateUIViewController(_: AVPlayerViewController, context _: Context) { - // Update the controller if needed. - } -} - -struct DocumentPreview: UIViewControllerRepresentable { - var url: URL - - func makeUIViewController(context: Context) -> QLPreviewController { - let controller = QLPreviewController() - controller.dataSource = context.coordinator - return controller - } - - func updateUIViewController(_: QLPreviewController, context _: Context) { - // Update the controller if needed. - } - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - class Coordinator: NSObject, QLPreviewControllerDataSource { - var parent: DocumentPreview - - init(_ parent: DocumentPreview) { - self.parent = parent - } - - func numberOfPreviewItems(in _: QLPreviewController) -> Int { - 1 - } - - func previewController(_: QLPreviewController, previewItemAt _: Int) -> QLPreviewItem { - parent.url as QLPreviewItem - } - } -} diff --git a/old/View/Screens/Conversation/ConversationMessageRow.swift b/old/View/Screens/Conversation/ConversationMessageRow.swift deleted file mode 100644 index b3fa2df..0000000 --- a/old/View/Screens/Conversation/ConversationMessageRow.swift +++ /dev/null @@ -1,82 +0,0 @@ -import Foundation -import SwiftUI - -struct ConversationMessageRow: View { - @EnvironmentObject var store: AppStore - - let message: Message - @State private var offset: CGSize = .zero - - var body: some View { - VStack(spacing: 0) { - HStack(spacing: 0) { - if isOutgoing() { - Spacer() - MessageAttr(message: message) - .padding(.trailing, 4) - } - ConversationMessageContainer(message: message, isOutgoing: isOutgoing()) - .background(isOutgoing() ? Color.Material.Shape.alternate : Color.Material.Shape.white) - .clipShape(ConversationMessageBubble(isOutgoing: isOutgoing())) - if !isOutgoing() { - MessageAttr(message: message) - .padding(.leading, 4) - Spacer() - } - } - .padding(.vertical, 10) - .padding(.horizontal, 16) - .background(Color.clearTappable) - .offset(offset) - .gesture( - DragGesture(minimumDistance: 30, coordinateSpace: .local) - .onChanged { value in - var width = value.translation.width - width = width > 0 ? 0 : width - offset = CGSize(width: width, height: 0) - } - .onEnded { value in - let targetWidth: CGFloat = -90 - withAnimation(.easeOut(duration: 0.1)) { - if value.translation.width <= targetWidth { - Vibration.success.vibrate() - DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { - withAnimation(.easeOut(duration: 0.1)) { - offset = .zero - } - } - } else { - offset = .zero - } - } - if value.translation.width <= targetWidth { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) { - store.dispatch(.conversationAction(.setReplyText(message.body ?? ""))) - } - } - } - ) - } - .listRowInsets(.zero) - .listRowSeparator(.hidden) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.Material.Background.light) - } - - private func isOutgoing() -> Bool { - message.from == store.state.conversationsState.currentChat?.account - } -} - -struct ConversationMessageBubble: Shape { - let isOutgoing: Bool - - func path(in rect: CGRect) -> Path { - let path = UIBezierPath( - roundedRect: rect, - byRoundingCorners: isOutgoing ? [.topLeft, .bottomLeft, .bottomRight] : [.topRight, .bottomLeft, .bottomRight], - cornerRadii: CGSize(width: 8, height: 10) - ) - return Path(path.cgPath) - } -} diff --git a/old/View/Screens/Conversation/ConversationScreen.swift b/old/View/Screens/Conversation/ConversationScreen.swift deleted file mode 100644 index 73657bf..0000000 --- a/old/View/Screens/Conversation/ConversationScreen.swift +++ /dev/null @@ -1,198 +0,0 @@ -import Combine -import Foundation -import Martin -import SwiftUI - -struct ConversationScreen: View { - @EnvironmentObject var store: AppStore - - @State private var autoScroll = true - @State private var firstIsVisible = true - - var body: some View { - ZStack { - // Background color - Color.Material.Background.light - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - let name = ( - store.state.conversationsState.currentRoster?.name ?? - store.state.conversationsState.currentRoster?.contactBareJid - ) ?? L10n.Chat.title - SharedNavigationBar( - leftButton: .init( - image: Image(systemName: "chevron.left"), - action: { - store.dispatch(.changeFlow(store.state.previousFlow)) - } - ), - centerText: .init(text: name) - ) - - // Msg list - let messages = store.state.conversationsState.currentMessages - if !messages.isEmpty { - ScrollViewReader { proxy in - List { - ForEach(messages) { message in - ConversationMessageRow(message: message) - .id(message.id) - .onAppear { - if message.id == messages.first?.id { - firstIsVisible = true - autoScroll = true - } - } - .onDisappear { - if message.id == messages.first?.id { - firstIsVisible = false - autoScroll = false - } - } - } - .rotationEffect(.degrees(180)) - } - .rotationEffect(.degrees(180)) - .listStyle(.plain) - .background(Color.Material.Background.light) - .scrollDismissesKeyboard(.immediately) - .scrollIndicators(.hidden) - .onChange(of: autoScroll) { new in - if new, !firstIsVisible { - withAnimation { - proxy.scrollTo(messages.first?.id, anchor: .top) - } - } - } - } - } else { - Spacer() - } - } - .onTapGesture { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } - - // Jump to last button - if !autoScroll { - VStack { - Spacer() - HStack { - Spacer() - Button { - autoScroll = true - } label: { - ZStack { - Circle() - .fill(Color.Material.Shape.white) - Image(systemName: "arrow.down") - .foregroundColor(.Material.Elements.active) - } - .frame(width: 40, height: 40) - .shadow(color: .black.opacity(0.2), radius: 4) - .padding(.trailing, 8) - .padding(.bottom, 8) - } - } - } - } - } - .safeAreaInset(edge: .bottom, spacing: 0) { - ConversationTextInput(autoScroll: $autoScroll) - } - } -} - -// Preview -#if DEBUG - struct ConversationScreen_Previews: PreviewProvider { - static var previews: some View { - ConversationScreen() - .environmentObject(pStore) - } - - static var pStore: AppStore { - let state = pState - return AppStore(initialState: state, reducer: AppState.reducer, middlewares: []) - } - - static var pState: AppState { - var state = AppState() - - let acc = "user@test.com" - let contact = "some@test.com" - - state.conversationsState.currentChat = Chat(id: "1", account: acc, participant: contact, type: .chat) - state.conversationsState.currentMessages = [ - Message( - id: "1", - type: .chat, - contentType: .text, - from: contact, - to: acc, - body: "this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: true, sentError: false - ), - Message( - id: "2", - type: .chat, - contentType: .text, - from: contact, - to: acc, - body: "this is for testsdfsdf sdfsdf sdfs sdf sdffsdf sdf sdf sdf sdf sdf sdff sdfffwwe ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: false, - sentError: false - ), - Message(id: "3", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: true), - Message( - id: "4", - type: .chat, - contentType: .text, - from: acc, - to: contact, - body: "this is for test sdfkjwek jwkjfh jwerf jdfhskjdhf jsdhfjhwefh sjdhfh fsdjhfh sd ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), - pending: false, - sentError: false - ), - Message(id: "5", type: .chat, contentType: .text, from: contact, to: acc, body: "this is for test sdfjkkeke kekkddjw;; w;edkdjfj l kjwekrjfk wef", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "6", type: .chat, contentType: .text, from: acc, to: contact, body: "this is for testsdf dsdkkekkddn wejkjfj ", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message( - id: "7", - type: .chat, - contentType: .text, - from: acc, - to: contact, - - body: "this is for test sdgdsfg dsfg dsfgdg dsfgdfgsdgsdfgdfg sdfgdsfgdfsg dsfgdsfgsdfg dsfgdfgsdg fgf fgfg sdfsdf sdfsdf sdf sdfsdf sdf sdfsdf sdfsdfsdf sdfsdf ", - subject: nil, - thread: nil, - oobUrl: nil, - date: Date(), pending: false, sentError: false - ), - Message(id: "8", type: .chat, contentType: .text, from: acc, to: contact, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "9", type: .chat, contentType: .text, from: contact, to: acc, body: "so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "10", type: .chat, contentType: .text, from: acc, to: contact, body: "so test so test so test", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false), - Message(id: "11", type: .chat, contentType: .text, from: contact, to: acc, body: "xD", subject: nil, thread: nil, oobUrl: nil, date: Date(), pending: false, sentError: false) - ] - - state.conversationsState.replyText = "> Some Text here! And if it a long and very long text sdfsadfsadfsafsadfsadfsadfsadfassadfsadfsafsafdsadfsafdsadfsadfas sdf sdf asdf sdfasdfsd sdfasdf sdfsdfdsasdfsdfa dsafsaf" - - return state - } - } -#endif diff --git a/old/View/Screens/Conversation/ConversationTextInput.swift b/old/View/Screens/Conversation/ConversationTextInput.swift deleted file mode 100644 index a0b089d..0000000 --- a/old/View/Screens/Conversation/ConversationTextInput.swift +++ /dev/null @@ -1,113 +0,0 @@ -import SwiftUI -import UIKit - -struct ConversationTextInput: View { - @EnvironmentObject var store: AppStore - - @State private var messageStr = "" - @FocusState private var isFocused: Bool - @Binding var autoScroll: Bool - - var body: some View { - VStack(spacing: 0) { - Rectangle() - .foregroundColor(.Material.Shape.separator) - .frame(height: 0.5) - .padding(.bottom, 8) - if !replyText.isEmpty { - VStack(spacing: 0) { - HStack(alignment: .top) { - Text(replyText) - .font(.body3) - .foregroundColor(Color.Material.Text.main) - .multilineTextAlignment(.leading) - .lineLimit(3) - .padding(8) - Spacer() - Image(systemName: "xmark") - .font(.title2) - .foregroundColor(.Material.Elements.active) - .padding(.leading, 8) - .tappablePadding(.symmetric(8)) { - store.dispatch(.conversationAction(.setReplyText(""))) - } - .padding(8) - } - .frame(maxWidth: .infinity) - .background(RoundedRectangle(cornerRadius: 4) - .foregroundColor(.Material.Background.light) - .shadow(radius: 0.5) - ) - .padding(.bottom, 8) - .padding(.horizontal, 8) - } - .padding(.horizontal, 8) - } - HStack { - Image(systemName: "paperclip") - .font(.title2) - .foregroundColor(.Material.Elements.active) - .padding(.leading, 8) - .tappablePadding(.symmetric(8)) { - store.dispatch(.sharingAction(.showSharing(true))) - } - TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator)) - .font(.body1) - .foregroundColor(Color.Material.Text.main) - .accentColor(.Material.Shape.black) - .focused($isFocused) - .padding(.horizontal, 8) - .padding(.vertical, 4) - .background(Color.Material.Shape.white) - .clipShape(RoundedRectangle(cornerRadius: 8)) - .padding(.vertical, 4) - let img = messageStr.isEmpty ? "paperplane" : "paperplane.fill" - Image(systemName: img) - .font(.title2) - .foregroundColor(messageStr.isEmpty ? .Material.Elements.inactive : .Material.Elements.active) - .padding(.trailing, 8) - .tappablePadding(.symmetric(8)) { - if !messageStr.isEmpty { - guard let acc = store.state.conversationsState.currentChat?.account else { return } - guard let contact = store.state.conversationsState.currentChat?.participant else { return } - store.dispatch(.conversationAction(.sendMessage( - from: acc, - to: contact, - body: composedMessage - ))) - messageStr = "" - // UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - store.dispatch(.conversationAction(.setReplyText(""))) - autoScroll = true - } - } - } - } - .padding(.bottom, 8) - .background(Color.Material.Background.dark) - .onChange(of: store.state.conversationsState.replyText) { new in - if !new.isEmpty { - isFocused = true - } - } - .fullScreenCover(isPresented: Binding( - get: { store.state.sharingState.sharingShown }, - set: { _ in } - )) { - AttachmentPickerScreen() - } - } - - private var replyText: String { - store.state.conversationsState.replyText - } - - private var composedMessage: String { - var result = "" - if !replyText.isEmpty { - result += replyText + "\n\n" - } - result += messageStr - return result - } -} diff --git a/old/View/Screens/RegistrationScreen.swift b/old/View/Screens/RegistrationScreen.swift deleted file mode 100644 index ccd4d7f..0000000 --- a/old/View/Screens/RegistrationScreen.swift +++ /dev/null @@ -1,20 +0,0 @@ -import SwiftUI - -struct RegistrationScreen: View { - // @EnvironmentObject var state: AppState - - public var body: some View { - ZStack { - Color.Material.Background.light - Button { - // state.flow = .welcome - } label: { - VStack { - Text("Not yet implemented") - Text(L10n.Global.back) - } - } - } - .ignoresSafeArea() - } -} diff --git a/old/View/Screens/Settings/SettingsScreen.swift b/old/View/Screens/Settings/SettingsScreen.swift deleted file mode 100644 index 98ee46c..0000000 --- a/old/View/Screens/Settings/SettingsScreen.swift +++ /dev/null @@ -1,20 +0,0 @@ -import SwiftUI - -struct SettingsScreen: View { - var body: some View { - ZStack { - // bg - Color.Material.Background.light - .ignoresSafeArea() - - // content - Text("under construction...") - - // tab bar - VStack { - Spacer() - SharedTabBar() - } - } - } -} diff --git a/old/View/Screens/Sharing/SharingContactsPickerView.swift b/old/View/Screens/Sharing/SharingContactsPickerView.swift deleted file mode 100644 index 8c7588e..0000000 --- a/old/View/Screens/Sharing/SharingContactsPickerView.swift +++ /dev/null @@ -1,64 +0,0 @@ -import SwiftUI - -struct SharingContactsPickerView: View { - @EnvironmentObject var store: AppStore - @State private var selectedContact: Roster? - - var body: some View { - VStack(spacing: 0) { - // Contacts list - let rosters = store.state.rostersState.rosters.filter { !$0.locallyDeleted } - if !rosters.isEmpty { - List { - ForEach(rosters) { roster in - ContactRow(roster: roster, selectedContact: $selectedContact) - } - } - .listStyle(.plain) - .background(Color.Material.Background.light) - } else { - Spacer() - } - - // Send panel - Rectangle() - .foregroundColor(.Material.Shape.black) - .frame(maxWidth: .infinity) - .frame(height: selectedContact == nil ? 0 : 50) - .overlay { - HStack { - Text(L10n.Attachment.Send.contact) - .foregroundColor(.Material.Text.white) - .font(.body1) - Image(systemName: "arrow.up.circle") - .foregroundColor(.Material.Text.white) - .font(.body1) - .padding(.leading, 8) - } - .padding() - } - .clipped() - .onTapGesture { - if let selectedContact = selectedContact { - store.dispatch(.sharingAction(.shareContact(jid: selectedContact.contactBareJid))) - store.dispatch(.sharingAction(.showSharing(false))) - } - } - } - } -} - -private struct ContactRow: View { - var roster: Roster - @Binding var selectedContact: Roster? - - var body: some View { - SharedListRow( - iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter), - text: roster.contactBareJid - ) - .onTapGesture { - selectedContact = roster - } - } -} diff --git a/old/View/Screens/Sharing/SharingFilesPickerView.swift b/old/View/Screens/Sharing/SharingFilesPickerView.swift deleted file mode 100644 index 5535b02..0000000 --- a/old/View/Screens/Sharing/SharingFilesPickerView.swift +++ /dev/null @@ -1,64 +0,0 @@ -import SwiftUI -import UIKit - -struct SharingFilesPickerView: View { - @EnvironmentObject var store: AppStore - - var body: some View { - DocumentPicker( - completion: { dataArray, extensionsArray in - store.dispatch(.sharingAction(.showSharing(false))) - store.dispatch(.sharingAction(.shareDocuments(dataArray, extensionsArray))) - }, - cancel: { - store.dispatch(.sharingAction(.showSharing(false))) - } - ) - } -} - -struct DocumentPicker: UIViewControllerRepresentable { - let completion: ([Data], [String]) -> Void - let cancel: () -> Void - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIDocumentPickerViewController { - let picker: UIDocumentPickerViewController - picker = UIDocumentPickerViewController(forOpeningContentTypes: [.item], asCopy: true) - picker.delegate = context.coordinator - picker.allowsMultipleSelection = true - return picker - } - - func updateUIViewController(_: UIDocumentPickerViewController, context _: UIViewControllerRepresentableContext) {} - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - class Coordinator: NSObject, UIDocumentPickerDelegate { - var parent: DocumentPicker - - init(_ parent: DocumentPicker) { - self.parent = parent - } - - func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt: [URL]) { - var dataArray = [Data]() - var extensionArray = [String]() - for url in didPickDocumentsAt { - do { - let data = try Data(contentsOf: url) - dataArray.append(data) - extensionArray.append(url.pathExtension) - } catch { - print("Unable to load data from \(url): \(error)") - } - } - parent.completion(dataArray, extensionArray) - } - - func documentPickerWasCancelled(_: UIDocumentPickerViewController) { - parent.cancel() - } - } -} diff --git a/old/View/Screens/Sharing/SharingLocationPickerView.swift b/old/View/Screens/Sharing/SharingLocationPickerView.swift deleted file mode 100644 index def4bff..0000000 --- a/old/View/Screens/Sharing/SharingLocationPickerView.swift +++ /dev/null @@ -1,134 +0,0 @@ -import MapKit -import SwiftUI - -struct SharingLocationPickerView: View { - @StateObject var locationManager = LocationManager() - @State private var region = MKCoordinateRegion() - - var body: some View { - VStack(spacing: 0) { - ZStack { - // MapView - MapView(region: $region) - .onAppear { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - self.region = locationManager.region - } - } - .overlay { - Image(systemName: "mappin") - .foregroundColor(.Material.Elements.active) - .font(.system(size: 30)) - .shadow(color: .white, radius: 2) - } - - // Track button - VStack { - Spacer() - HStack { - Spacer() - Image(systemName: "location.circle") - .resizable() - .frame(width: 40, height: 40) - .foregroundColor(.Material.Elements.active) - .background(Color.Material.Shape.white) - .clipShape(Circle()) - .shadow(color: .white, radius: 2) - .padding(.trailing) - .padding(.bottom, 50) - .tappablePadding(.symmetric(10)) { - self.region = locationManager.region - } - } - } - } - - // Send panel - Rectangle() - .foregroundColor(.Material.Shape.black) - .frame(maxWidth: .infinity) - .frame(height: 50) - .overlay { - HStack { - Text(L10n.Attachment.Send.location) - .foregroundColor(.Material.Text.white) - .font(.body1) - Image(systemName: "arrow.up.circle") - .foregroundColor(.Material.Text.white) - .font(.body1) - .padding(.leading, 8) - } - .padding() - } - .clipped() - .onTapGesture { - store.dispatch(.sharingAction(.shareLocation(lat: region.center.latitude, lon: region.center.longitude))) - store.dispatch(.sharingAction(.showSharing(false))) - } - } - .onAppear { - locationManager.start() - } - } -} - -struct MapView: UIViewRepresentable { - @Binding var region: MKCoordinateRegion - - func makeUIView(context: Context) -> MKMapView { - let mapView = MKMapView() - mapView.delegate = context.coordinator - mapView.showsUserLocation = false - mapView.userTrackingMode = .none - - return mapView - } - - func updateUIView(_ uiView: MKMapView, context _: Context) { - if uiView.region != region { - uiView.setRegion(region, animated: true) - } - } - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - class Coordinator: NSObject, MKMapViewDelegate { - var parent: MapView - - init(_ parent: MapView) { - self.parent = parent - } - } -} - -class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { - private let locationManager = CLLocationManager() - @Published var region: MKCoordinateRegion - - override init() { - region = MKCoordinateRegion() - super.init() - locationManager.delegate = self - locationManager.desiredAccuracy = kCLLocationAccuracyBest - } - - func start() { - locationManager.requestWhenInUseAuthorization() - locationManager.startUpdatingLocation() - } - - func stop() { - locationManager.stopUpdatingLocation() - } - - func locationManager(_: CLLocationManager, didUpdateLocations locations: [CLLocation]) { - if let loc = locations.first { - region = MKCoordinateRegion( - center: loc.coordinate, - span: MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002) - ) - } - } -} diff --git a/old/View/Screens/Sharing/SharingMediaPickerView.swift b/old/View/Screens/Sharing/SharingMediaPickerView.swift deleted file mode 100644 index 17cbed0..0000000 --- a/old/View/Screens/Sharing/SharingMediaPickerView.swift +++ /dev/null @@ -1,289 +0,0 @@ -import AVFoundation -import MobileCoreServices -import Photos -import SwiftUI - -struct SharingMediaPickerView: View { - @EnvironmentObject var store: AppStore - @State private var showCameraPicker = false - @State private var cameraReady = false - - @State private var selectedItems: [String] = [] - - var body: some View { - let columns = Array(repeating: GridItem(.flexible(), spacing: 0), count: 3) - - VStack(spacing: 0) { - // List of media - ScrollView(showsIndicators: false) { - LazyVGrid(columns: columns, spacing: 0) { - // For camera - if store.state.sharingState.isCameraAccessGranted { - if cameraReady { - ZStack { - CameraView() - .aspectRatio(1, contentMode: .fit) - .frame(maxWidth: .infinity) - Image(systemName: "camera") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 40, height: 40) - .foregroundColor(.white) - .padding(8) - .background(Color.black.opacity(0.5)) - .clipShape(Circle()) - .padding(8) - } - .onTapGesture { - showCameraPicker = true - } - } else { - ProgressView() - .frame(maxWidth: .infinity) - .frame(height: 100) - .onAppear { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { - cameraReady = true - } - } - } - } else { - Button { - openAppSettings() - } label: { - ZStack { - Rectangle() - .fill(Color.Material.Background.light) - .overlay { - VStack { - Image(systemName: "camera") - .foregroundColor(.Material.Elements.active) - .font(.system(size: 30)) - Text("Allow camera access") - .foregroundColor(.Material.Text.main) - .font(.body3) - } - } - .frame(height: 100) - } - } - } - - // For gallery - if store.state.sharingState.isGalleryAccessGranted { - ForEach(store.state.sharingState.galleryItems) { item in - GridViewItem(item: item, selected: $selectedItems) - } - } else { - Button { - openAppSettings() - } label: { - ZStack { - Rectangle() - .fill(Color.Material.Background.light) - .overlay { - VStack { - Image(systemName: "photo") - .foregroundColor(.Material.Elements.active) - .font(.system(size: 30)) - Text("Allow gallery access") - .foregroundColor(.Material.Text.main) - .font(.body3) - } - } - .frame(height: 100) - } - } - } - } - } - .fullScreenCover(isPresented: $showCameraPicker) { - CameraPicker(sourceType: .camera) { data, type in - store.dispatch(.sharingAction(.cameraCaptured(media: data, type: type))) - showCameraPicker = false - store.dispatch(.sharingAction(.showSharing(false))) - } - .edgesIgnoringSafeArea(.all) - } - - // Send panel - Rectangle() - .foregroundColor(.Material.Shape.black) - .frame(maxWidth: .infinity) - .frame(height: self.selectedItems.isEmpty ? 0 : 50) - .overlay { - HStack { - Text(L10n.Attachment.Send.media) - .foregroundColor(.Material.Text.white) - .font(.body1) - Image(systemName: "arrow.up.circle") - .foregroundColor(.Material.Text.white) - .font(.body1) - .padding(.leading, 8) - } - .padding() - } - .clipped() - .onTapGesture { - store.dispatch(.sharingAction(.shareMedia(ids: selectedItems))) - store.dispatch(.sharingAction(.showSharing(false))) - } - } - .onAppear { - store.dispatch(.sharingAction(.checkCameraAccess)) - store.dispatch(.sharingAction(.checkGalleryAccess)) - } - .onChange(of: store.state.sharingState.isGalleryAccessGranted) { granted in - if granted { - store.dispatch(.fileAction(.fetchItemsFromGallery)) - } - } - } -} - -private struct GridViewItem: View { - let item: SharingGalleryItem - @Binding var selected: [String] - @State var isSelected = false - - var body: some View { - if let data = item.thumbnail { - ZStack { - Image(uiImage: UIImage(data: data) ?? UIImage()) - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: Const.galleryGridSize, height: Const.galleryGridSize) - .clipped() - if let duration = item.duration { - VStack { - Spacer() - HStack { - Spacer() - Text(duration) - .foregroundColor(.Material.Text.white) - .font(.sub1) - .shadow(color: .black, radius: 2) - .padding(4) - } - } - } - if isSelected { - VStack { - HStack { - Spacer() - Circle() - .frame(width: 30, height: 30) - .shadow(color: .black, radius: 2) - .foregroundColor(.Material.Shape.white) - .overlay { - Image(systemName: "checkmark") - .foregroundColor(.Material.Elements.active) - .font(.body3) - } - .padding(4) - } - Spacer() - } - } - } - .onTapGesture { - isSelected.toggle() - if isSelected { - selected.append(item.id) - } else { - selected.removeAll { $0 == item.id } - } - } - } else { - ZStack { - Rectangle() - .fill(Color.Material.Background.light) - .overlay { - ProgressView() - .foregroundColor(.Material.Elements.active) - } - .frame(width: Const.galleryGridSize, height: Const.galleryGridSize) - } - } - } -} - -class CameraUIView: UIView { - var previewLayer: AVCaptureVideoPreviewLayer? - - override func layoutSubviews() { - super.layoutSubviews() - previewLayer?.frame = bounds - } -} - -struct CameraView: UIViewRepresentable { - func makeUIView(context _: Context) -> CameraUIView { - let view = CameraUIView() - - let captureSession = AVCaptureSession() - guard let captureDevice = AVCaptureDevice.default(for: .video) else { return view } - guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return view } - captureSession.addInput(input) - - let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) - previewLayer.videoGravity = .resizeAspectFill - view.layer.addSublayer(previewLayer) - view.previewLayer = previewLayer - - captureSession.startRunning() - - return view - } - - func updateUIView(_ uiView: CameraUIView, context _: Context) { - uiView.previewLayer?.frame = uiView.bounds - } -} - -struct CameraPicker: UIViewControllerRepresentable { - var sourceType: UIImagePickerController.SourceType - var completionHandler: (Data, SharingCameraMediaType) -> Void - - func makeUIViewController(context: Context) -> UIImagePickerController { - let picker = UIImagePickerController() - picker.sourceType = sourceType - picker.delegate = context.coordinator - picker.mediaTypes = [UTType.movie.identifier, UTType.image.identifier] - picker.videoQuality = .typeHigh - picker.videoMaximumDuration = Const.videoDurationLimit - picker.view.backgroundColor = .clear - return picker - } - - func updateUIViewController(_: UIImagePickerController, context _: Context) {} - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { - let parent: CameraPicker - - init(_ parent: CameraPicker) { - self.parent = parent - } - - func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { - // swiftlint:disable:next force_cast - let mediaType = info[.mediaType] as! String - - if mediaType == UTType.image.identifier { - if let image = info[.originalImage] as? UIImage { - let data = image.jpegData(compressionQuality: 1.0) ?? Data() - parent.completionHandler(data, .photo) - } - } else if mediaType == UTType.movie.identifier { - if let url = info[.mediaURL] as? URL { - let data = try? Data(contentsOf: url) - parent.completionHandler(data ?? Data(), .video) - } - } - } - } -} diff --git a/old/View/Screens/Sharing/SharingPickerScreen.swift b/old/View/Screens/Sharing/SharingPickerScreen.swift deleted file mode 100644 index d67e9ca..0000000 --- a/old/View/Screens/Sharing/SharingPickerScreen.swift +++ /dev/null @@ -1,47 +0,0 @@ -import SwiftUI - -struct AttachmentPickerScreen: View { - @EnvironmentObject var store: AppStore - - @State private var selectedTab: SharingTab = .media - - var body: some View { - ZStack { - // Background color - Color.Material.Background.light - .ignoresSafeArea() - - // Content - VStack(spacing: 0) { - // Header - SharedNavigationBar( - centerText: .init(text: L10n.Attachment.Prompt.main), - rightButton: .init( - image: Image(systemName: "xmark"), - action: { - store.dispatch(.sharingAction(.showSharing(false))) - } - ) - ) - - // Pickers - switch selectedTab { - case .media: - SharingMediaPickerView() - - case .files: - SharingFilesPickerView() - - case .location: - SharingLocationPickerView() - - case .contacts: - SharingContactsPickerView() - } - - // Tab bar - SharingTabBar(selectedTab: $selectedTab) - } - } - } -} diff --git a/old/View/Screens/Sharing/SharingTabBar.swift b/old/View/Screens/Sharing/SharingTabBar.swift deleted file mode 100644 index 770dc04..0000000 --- a/old/View/Screens/Sharing/SharingTabBar.swift +++ /dev/null @@ -1,85 +0,0 @@ -import SwiftUI - -enum SharingTab: Int, CaseIterable { - case media - case files - case location - case contacts -} - -struct SharingTabBar: View { - @Binding var selectedTab: SharingTab - - var body: some View { - VStack(spacing: 0) { - Rectangle() - .frame(maxWidth: .infinity) - .frame(height: 0.2) - .foregroundColor(.Material.Shape.separator) - HStack(spacing: 0) { - SharingTabBarButton(tab: .media, selected: $selectedTab) - SharingTabBarButton(tab: .files, selected: $selectedTab) - SharingTabBarButton(tab: .location, selected: $selectedTab) - SharingTabBarButton(tab: .contacts, selected: $selectedTab) - } - .background(Color.Material.Background.dark) - } - .frame(height: 50) - } -} - -private struct SharingTabBarButton: View { - let tab: SharingTab - @Binding var selected: SharingTab - - var body: some View { - ZStack { - VStack(spacing: 2) { - buttonImg - .foregroundColor(selected == tab ? .Material.Elements.active : .Material.Elements.inactive) - .font(.system(size: 24, weight: .light)) - .symbolRenderingMode(.hierarchical) - Text(buttonTitle) - .font(.sub1) - .foregroundColor(selected == tab ? .Material.Text.main : .Material.Elements.inactive) - } - Rectangle() - .foregroundColor(.white.opacity(0.01)) - .onTapGesture { - selected = tab - } - } - } - - var buttonImg: Image { - switch tab { - case .media: - return Image(systemName: "photo.on.rectangle.angled") - - case .files: - return Image(systemName: "doc.on.doc") - - case .location: - return Image(systemName: "location.circle") - - case .contacts: - return Image(systemName: "person.crop.circle") - } - } - - var buttonTitle: String { - switch tab { - case .media: - return L10n.Attachment.Tab.media - - case .files: - return L10n.Attachment.Tab.files - - case .location: - return L10n.Attachment.Tab.location - - case .contacts: - return L10n.Attachment.Tab.contacts - } - } -} diff --git a/old/View/Screens/StartScreen.swift b/old/View/Screens/StartScreen.swift deleted file mode 100644 index ee7a501..0000000 --- a/old/View/Screens/StartScreen.swift +++ /dev/null @@ -1,19 +0,0 @@ -import SwiftUI - -struct StartScreen: View { - @EnvironmentObject var store: AppStore - - var body: some View { - ZStack { - Color.Material.Background.light - Image.logo - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 200, height: 200) - } - .ignoresSafeArea() - .onAppear { - store.dispatch(.startAction(.loadStoredAccounts)) - } - } -} diff --git a/old/View/Screens/WelcomeScreen.swift b/old/View/Screens/WelcomeScreen.swift deleted file mode 100644 index d7a27f7..0000000 --- a/old/View/Screens/WelcomeScreen.swift +++ /dev/null @@ -1,53 +0,0 @@ -import SwiftUI - -struct WelcomeScreen: View { - @EnvironmentObject var store: AppStore - - public var body: some View { - ZStack { - // background - Color.Material.Background.light - .ignoresSafeArea() - - // content - VStack(spacing: 32) { - // icon - Image.logo - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 120, height: 120) - - // texts - VStack(spacing: 10) { - Text(L10n.Global.name) - .font(.head1r) - .foregroundColor(.Material.Text.main) - .fixedSize(horizontal: true, vertical: false) - Text(L10n.Start.subtitle) - .font(.body2) - .foregroundColor(.Material.Text.sub) - .fixedSize(horizontal: false, vertical: true) - .multilineTextAlignment(.center) - } - - // buttons - VStack(spacing: 16) { - Button { - store.dispatch(.accountsAction(.goTo(.addAccount))) - store.dispatch(.changeFlow(.accounts)) - } label: { - Text(L10n.Start.Btn.login) - } - .buttonStyle(SecondaryButtonStyle()) - Button { - // state.flow = .registration - } label: { - Text(L10n.Start.Btn.register) - } - .buttonStyle(PrimaryButtonStyle()) - } - } - .padding(.horizontal, 32) - } - } -} diff --git a/old/View/SharedComponents/SharedListRow.swift b/old/View/SharedComponents/SharedListRow.swift deleted file mode 100644 index 7e5fa74..0000000 --- a/old/View/SharedComponents/SharedListRow.swift +++ /dev/null @@ -1,59 +0,0 @@ -import SwiftUI - -enum SharedListRowIconType { - case charCircle(String) - case image(Image, Color) -} - -struct SharedListRow: View { - let iconType: SharedListRowIconType - let text: String - - var body: some View { - VStack(spacing: 0) { - HStack(spacing: 8) { - // Icon - switch iconType { - case .charCircle(let str): - let char = str.firstLetter - let color = str.firstLetterColor - ZStack { - Circle() - .frame(width: 44, height: 44) - .foregroundColor(color) - Text(char) - .foregroundColor(.white) - .font(.body1) - } - - case .image(let image, let color): - ZStack { - Circle() - .frame(width: 44, height: 44) - .foregroundColor(.clearTappable) - .overlay { - image - .foregroundColor(color) - } - } - } - - // Text - Text(text) - .foregroundColor(Color.Material.Text.main) - .font(.body2) - Spacer() - } - .padding(.horizontal, 16) - .padding(.vertical, 4) - Rectangle() - .frame(maxWidth: .infinity) - .frame(height: 1) - .foregroundColor(.Material.Background.dark) - } - .listRowInsets(.zero) - .listRowSeparator(.hidden) - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color.Material.Background.light) - } -} diff --git a/old/View/SharedComponents/SharedNavigationBar.swift b/old/View/SharedComponents/SharedNavigationBar.swift deleted file mode 100644 index f6e651a..0000000 --- a/old/View/SharedComponents/SharedNavigationBar.swift +++ /dev/null @@ -1,78 +0,0 @@ -import SwiftUI - -struct SharedNavBarButton: View { - let image: Image? - let action: () -> Void - var isEnabled: Bool = true - - init( - image: Image, - action: @escaping () -> Void, - isEnabled: Bool = true - ) { - self.image = image - self.action = action - self.isEnabled = isEnabled - } - - var body: some View { - Button { - action() - } label: { - image - .foregroundColor(isEnabled ? .Material.Elements.active : .Material.Elements.inactive) - .tappablePadding(.symmetric(12)) { - action() - } - } - .disabled(!isEnabled) - } -} - -struct SharedNavBarText: View { - let text: String - - var body: some View { - Text(text) - .font(.head2) - .foregroundColor(.Material.Text.main) - } -} - -struct SharedNavigationBar: View { - var leftButton: SharedNavBarButton? - var centerText: SharedNavBarText? - var rightButton: SharedNavBarButton? - - var body: some View { - ZStack { - Color.Material.Background.dark - .ignoresSafeArea() - - VStack { - if centerText != nil { - centerText - } - } - Spacer() - - HStack(alignment: .center) { - VStack { - if leftButton != nil { - leftButton?.padding() - } - } - .frame(minWidth: 40) - Spacer() - VStack { - if rightButton != nil { - rightButton? - .padding() - } - } - .frame(minWidth: 40) - } - } - .frame(height: 44) - } -} diff --git a/old/View/SharedComponents/SharedTabBar.swift b/old/View/SharedComponents/SharedTabBar.swift deleted file mode 100644 index 8ca982c..0000000 --- a/old/View/SharedComponents/SharedTabBar.swift +++ /dev/null @@ -1,76 +0,0 @@ -import SwiftUI - -struct SharedTabBar: View { - var body: some View { - VStack(spacing: 0) { - Rectangle() - .frame(maxWidth: .infinity) - .frame(height: 0.2) - .foregroundColor(.Material.Shape.separator) - HStack(spacing: 0) { - SharedTabBarButton(buttonFlow: .contacts) - SharedTabBarButton(buttonFlow: .chats) - SharedTabBarButton(buttonFlow: .settings) - } - .background(Color.Material.Background.dark) - } - .frame(height: 50) - } -} - -private struct SharedTabBarButton: View { - @EnvironmentObject var store: AppStore - - let buttonFlow: AppFlow - - var body: some View { - ZStack { - VStack(spacing: 2) { - buttonImg - .foregroundColor(buttonFlow == store.state.currentFlow ? .Material.Elements.active : .Material.Elements.inactive) - .font(.system(size: 24, weight: .light)) - .symbolRenderingMode(.hierarchical) - Text(buttonTitle) - .font(.sub1) - .foregroundColor(buttonFlow == store.state.currentFlow ? .Material.Text.main : .Material.Elements.inactive) - } - Rectangle() - .foregroundColor(.white.opacity(0.01)) - .onTapGesture { - store.dispatch(.changeFlow(buttonFlow)) - } - } - } - - var buttonImg: Image { - switch buttonFlow { - case .contacts: - return Image(systemName: "person.2.fill") - - case .chats: - return Image(systemName: "bubble.left.fill") - - case .settings: - return Image(systemName: "gearshape.fill") - - default: - return Image(systemName: "questionmark.circle") - } - } - - var buttonTitle: String { - switch buttonFlow { - case .contacts: - return "Contacts" - - case .chats: - return "Chats" - - case .settings: - return "Settings" - - default: - return "Unknown" - } - } -} diff --git a/old/View/SharedComponents/UniversalInputCollection.swift b/old/View/SharedComponents/UniversalInputCollection.swift deleted file mode 100644 index fb8b5f8..0000000 --- a/old/View/SharedComponents/UniversalInputCollection.swift +++ /dev/null @@ -1,203 +0,0 @@ -import SwiftUI - -// MARK: Public -protocol UniversalInputSelectionElement: Identifiable, Equatable, Hashable { - var icon: Image? { get } - var text: String? { get } -} - -public enum UniversalInputCollection { - struct TextField { - let prompt: String - @Binding var text: String - var focus: FocusState.Binding - var fieldType: T - let contentType: UITextContentType - let keyboardType: UIKeyboardType - let submitLabel: SubmitLabel - let action: () -> Void - } - - struct SecureField { - let prompt: String - @Binding var text: String - var focus: FocusState.Binding - var fieldType: T - let submitLabel: SubmitLabel - let action: () -> Void - } - - struct DropDownMenu { - let prompt: String - let elements: [E] - @Binding var selected: E? - var focus: FocusState.Binding - var fieldType: T - } -} - -// MARK: Inputs implementations -extension UniversalInputCollection.TextField: View { - var body: some View { - TextField("", text: $text) - .padding(.horizontal, 8) - .focused(focus, equals: fieldType) - .font(.body2) - .foregroundColor(.Material.Text.main) - .autocorrectionDisabled(true) - .autocapitalization(.none) - .textContentType(contentType) - .keyboardType(keyboardType) - .submitLabel(submitLabel) - .textSelection(.enabled) - .onSubmit { - action() - } - .modifier(UniversalInputModifier( - prompt: prompt, - focus: focus, - fieldType: fieldType, - isActive: isFilled - )) - } - - var isFilled: Bool { - !text.isEmpty || focus.wrappedValue == fieldType - } -} - -extension UniversalInputCollection.SecureField: View { - var body: some View { - SecureField("", text: $text) - .padding(.horizontal, 8) - .focused(focus, equals: fieldType) - .font(.body2) - .foregroundColor(.Material.Text.main) - .autocorrectionDisabled(true) - .autocapitalization(.none) - .textContentType(.password) - .submitLabel(submitLabel) - .textSelection(.disabled) - .onSubmit { - action() - } - .modifier(UniversalInputModifier( - prompt: prompt, - focus: focus, - fieldType: fieldType, - isActive: isFilled - )) - } - - var isFilled: Bool { - !text.isEmpty || focus.wrappedValue == fieldType - } -} - -extension UniversalInputCollection.DropDownMenu: View { - var body: some View { - ZStack { - HStack { - Text(text) - .font(.body2) - .foregroundColor(.Material.Text.main) - .padding(.leading, 8) - Spacer() - } - .modifier(UniversalInputModifier( - prompt: prompt, - focus: focus, - fieldType: fieldType, - isActive: selected != nil - )) - - Menu { - ForEach(elements, id: \.self.id) { element in - Button { - selected = element - } label: { - Text(element.text ?? "") - } - } - } label: { - Label("", image: "") - .labelStyle(TitleOnlyLabelStyle()) - .padding(.vertical) - .frame(height: 48) - .frame(maxWidth: .infinity) - } - } - } - - var text: String { - if let text = selected?.text { - return text - } else { - return "" - } - } -} - -// MARK: Modifiers -private struct UniversalInputModifier: ViewModifier { - let prompt: String - var focus: FocusState.Binding - var fieldType: T - let isActive: Bool - var promptBackground: Color? - var isCentered: Bool? - var customTapAction: (() -> Void)? - - func body(content: Content) -> some View { - VStack(spacing: 0) { - ZStack { - HStack { - Text(isActive ? "" : prompt) - .font(.body2) - .foregroundColor(.Material.Shape.separator) - .padding(8) - Spacer() - } - content - .frame(height: 48) - } - } - .frame(height: 48) - .background { - ZStack { - RoundedRectangle(cornerRadius: 4) - .foregroundColor(.Material.Shape.white) - RoundedRectangle(cornerRadius: 4) - .stroke(Color.Material.Shape.separator) - } - } - .contentShape(Rectangle()) - .onTapGesture { - if let customTapAction { - customTapAction() - } else { - if focus.wrappedValue != fieldType { - focus.wrappedValue = fieldType - } - } - } - } -} - -// MARK: Validators -extension UniversalInputCollection { - enum Validators { - static func isEmail(_ input: String) -> Bool { - if !input.isEmpty { - let mailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" - if !NSPredicate(format: "SELF MATCHES %@", mailRegex).evaluate(with: input) { - return false - } else { - return true - } - } else { - return true - } - } - } -} diff --git a/old/View/UIToolkit/Binding+Extensions.swift b/old/View/UIToolkit/Binding+Extensions.swift deleted file mode 100644 index 6a2a796..0000000 --- a/old/View/UIToolkit/Binding+Extensions.swift +++ /dev/null @@ -1,12 +0,0 @@ -import SwiftUI - -extension Binding where Value == String { - func max(_ limit: Int) -> Self { - if wrappedValue.count > limit { - DispatchQueue.main.async { - wrappedValue = String(wrappedValue.dropLast()) - } - } - return self - } -} diff --git a/old/View/UIToolkit/ButtonStyles.swift b/old/View/UIToolkit/ButtonStyles.swift deleted file mode 100644 index 62c59ab..0000000 --- a/old/View/UIToolkit/ButtonStyles.swift +++ /dev/null @@ -1,50 +0,0 @@ -import SwiftUI - -private enum ButtonSizes { - static let padding = 16.0 - static let cornerRadius = 4.0 - static let scaleEffect: CGFloat = 0.9 - static let opacity: Double = 0.6 -} - -struct PrimaryButtonStyle: ButtonStyle { - @Environment(\.isEnabled) private var isEnabled - - func makeBody(configuration: Configuration) -> some View { - configuration - .label - .font(.head2) - .padding(ButtonSizes.padding) - .frame(maxWidth: .infinity) - .foregroundColor(.Material.Shape.white) - .background { - RoundedRectangle(cornerRadius: ButtonSizes.cornerRadius) - .foregroundColor(isEnabled ? .Material.Elements.active : .Material.Shape.separator) - } - .contentShape(Rectangle()) - .scaleEffect(configuration.isPressed ? ButtonSizes.scaleEffect : 1.0) - .opacity(configuration.isPressed ? ButtonSizes.opacity : 1.0) - .animation(.easeInOut(duration: 0.1), value: configuration.isPressed) - } -} - -struct SecondaryButtonStyle: ButtonStyle { - @Environment(\.isEnabled) private var isEnabled - - func makeBody(configuration: Configuration) -> some View { - configuration - .label - .font(.head2) - .padding(ButtonSizes.padding) - .frame(maxWidth: .infinity) - .foregroundColor(isEnabled ? .Material.Elements.active : .Material.Shape.separator) - .background { - RoundedRectangle(cornerRadius: ButtonSizes.cornerRadius) - .stroke(isEnabled ? Color.Material.Elements.active : Color.Material.Shape.separator) - } - .contentShape(Rectangle()) - .scaleEffect(configuration.isPressed ? ButtonSizes.scaleEffect : 1.0) - .opacity(configuration.isPressed ? ButtonSizes.opacity : 1.0) - .animation(.easeInOut(duration: 0.1), value: configuration.isPressed) - } -} diff --git a/old/View/UIToolkit/Colors+Tappable.swift b/old/View/UIToolkit/Colors+Tappable.swift deleted file mode 100644 index 718a3df..0000000 --- a/old/View/UIToolkit/Colors+Tappable.swift +++ /dev/null @@ -1,13 +0,0 @@ -import SwiftUI - -public extension Color { - static let clearTappable = Color.white.opacity(0.0001) - // static func random(randomOpacity: Bool = false) -> Color { - // Color( - // red: .random(in: 0 ... 1), - // green: .random(in: 0 ... 1), - // blue: .random(in: 0 ... 1), - // opacity: randomOpacity ? .random(in: 0 ... 1) : 1 - // ) - // } -} diff --git a/old/View/UIToolkit/EdgeInsets+Extensions.swift b/old/View/UIToolkit/EdgeInsets+Extensions.swift deleted file mode 100644 index 65f5311..0000000 --- a/old/View/UIToolkit/EdgeInsets+Extensions.swift +++ /dev/null @@ -1,15 +0,0 @@ -import SwiftUI - -extension EdgeInsets { - var inverted: EdgeInsets { - .init(top: -top, leading: -leading, bottom: -bottom, trailing: -trailing) - } - - static var zero: EdgeInsets { - .init(top: 0, leading: 0, bottom: 0, trailing: 0) - } - - static func symmetric(_ value: CGFloat) -> EdgeInsets { - .init(top: value, leading: value, bottom: value, trailing: value) - } -} diff --git a/old/View/UIToolkit/KeyboardDisposableModifier.swift b/old/View/UIToolkit/KeyboardDisposableModifier.swift deleted file mode 100644 index 8b372fd..0000000 --- a/old/View/UIToolkit/KeyboardDisposableModifier.swift +++ /dev/null @@ -1,22 +0,0 @@ -import SwiftUI - -private struct ContentBlockModifier: ViewModifier { - var focus: FocusState.Binding - - func body(content: Content) -> some View { - content - .background { - Rectangle() - .foregroundColor(.white.opacity(0.01)) - .onTapGesture { - focus.wrappedValue = nil - } - } - } -} - -extension View { - func keyboardUnfocus(_ focus: FocusState.Binding) -> some View { - self.modifier(ContentBlockModifier(focus: focus)) - } -} diff --git a/old/View/UIToolkit/Typography.swift b/old/View/UIToolkit/Typography.swift deleted file mode 100644 index db856f3..0000000 --- a/old/View/UIToolkit/Typography.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation -import SwiftUI - -extension Font { - static let head1l = Font.system(size: 34, weight: .light, design: .rounded) - static let head1r = Font.system(size: 34, weight: .regular, design: .rounded) - static let head2 = Font.system(size: 20, weight: .regular, design: .rounded) - static let body1 = Font.system(size: 18, weight: .regular, design: .rounded) - static let body2 = Font.system(size: 16, weight: .regular, design: .rounded) - static let body3 = Font.system(size: 14, weight: .regular, design: .rounded) - static let sub1 = Font.system(size: 10, weight: .regular, design: .rounded) - static let sub2 = Font.system(size: 8, weight: .regular, design: .rounded) -} diff --git a/old/View/UIToolkit/UIImage+Crop.swift b/old/View/UIToolkit/UIImage+Crop.swift deleted file mode 100644 index 1bccefd..0000000 --- a/old/View/UIToolkit/UIImage+Crop.swift +++ /dev/null @@ -1,42 +0,0 @@ -import UIKit - -extension UIImage { - func scaleAndCropImage(toExampleSize _: CGSize, completion: @escaping (UIImage?) -> Void) { - DispatchQueue.global(qos: .background).async { - guard let cgImage = self.cgImage else { - DispatchQueue.main.async { - completion(nil) - } - return - } - let contextImage: UIImage = .init(cgImage: cgImage) - var contextSize: CGSize = contextImage.size - - var posX: CGFloat = 0.0 - var posY: CGFloat = 0.0 - let cgwidth: CGFloat = self.size.width - let cgheight: CGFloat = self.size.height - - // Check and handle if the image is wider than the requested size - if contextSize.width > contextSize.height { - posX = ((contextSize.width - contextSize.height) / 2) - contextSize.width = contextSize.height - } else if contextSize.width < contextSize.height { - // Check and handle if the image is taller than the requested size - posY = ((contextSize.height - contextSize.width) / 2) - contextSize.height = contextSize.width - } - - let rect: CGRect = .init(x: posX, y: posY, width: cgwidth, height: cgheight) - guard let contextCg = contextImage.cgImage, let imgRef = contextCg.cropping(to: rect) else { - DispatchQueue.main.async { - completion(nil) - } - return - } - let image: UIImage = .init(cgImage: imgRef, scale: self.scale, orientation: self.imageOrientation) - - completion(image) - } - } -} diff --git a/old/View/UIToolkit/Vibration.swift b/old/View/UIToolkit/Vibration.swift deleted file mode 100644 index 3eee66b..0000000 --- a/old/View/UIToolkit/Vibration.swift +++ /dev/null @@ -1,17 +0,0 @@ -import SwiftUI -import UIKit - -enum Vibration: String { - case error - case success - - public func vibrate() { - switch self { - case .error: - UINotificationFeedbackGenerator().notificationOccurred(.error) - - case .success: - UINotificationFeedbackGenerator().notificationOccurred(.success) - } - } -} diff --git a/old/View/UIToolkit/View+Debug.swift b/old/View/UIToolkit/View+Debug.swift deleted file mode 100644 index 34f7c65..0000000 --- a/old/View/UIToolkit/View+Debug.swift +++ /dev/null @@ -1,35 +0,0 @@ -import SwiftUI - -#if DEBUG - private let rainbowDebugColors = [ - Color.purple, - Color.blue, - Color.green, - Color.yellow, - Color.orange, - Color.red, - Color.pink, - Color.black.opacity(0.5), - Color.teal, - Color.gray, - Color.mint, - Color.cyan - ] - - public extension Color { - static func random(randomOpacity: Bool = false) -> Color { - Color( - red: .random(in: 0 ... 1), - green: .random(in: 0 ... 1), - blue: .random(in: 0 ... 1), - opacity: randomOpacity ? .random(in: 0 ... 1) : 1 - ) - } - } - - extension View { - func rainbowDebug() -> some View { - background(Color.random()) - } - } -#endif diff --git a/old/View/UIToolkit/View+If.swift b/old/View/UIToolkit/View+If.swift deleted file mode 100644 index f6611ca..0000000 --- a/old/View/UIToolkit/View+If.swift +++ /dev/null @@ -1,11 +0,0 @@ -import SwiftUI - -public extension View { - @ViewBuilder func `if`(_ condition: @autoclosure () -> Bool, transform: (Self) -> Content) -> some View { - if condition() { - transform(self) - } else { - self - } - } -} diff --git a/old/View/UIToolkit/View+Loader.swift b/old/View/UIToolkit/View+Loader.swift deleted file mode 100644 index 3d0a76c..0000000 --- a/old/View/UIToolkit/View+Loader.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Foundation -import SwiftUI - -public extension View { - func loadingIndicator(_ isShowing: Bool) -> some View { - modifier(LoadingIndicator(isShowing: isShowing)) - } -} - -struct LoadingIndicator: ViewModifier { - var isShowing: Bool - - func body(content: Content) -> some View { - ZStack { - content - if isShowing { - loadingView - } - } - } - - private var loadingView: some View { - GeometryReader { proxyReader in - ZStack { - Color.Material.Elements.active.opacity(0.3) - .frame(maxWidth: .infinity, maxHeight: .infinity) - - // loader - ProgressView() - .progressViewStyle( - CircularProgressViewStyle(tint: .Material.Elements.active) - ) - .position(x: proxyReader.size.width / 2, y: proxyReader.size.height / 2) - .controlSize(.large) - } - } - .ignoresSafeArea() - .transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.1))) - } -} diff --git a/old/View/UIToolkit/View+OnLoad.swift b/old/View/UIToolkit/View+OnLoad.swift deleted file mode 100644 index 4206bff..0000000 --- a/old/View/UIToolkit/View+OnLoad.swift +++ /dev/null @@ -1,27 +0,0 @@ -import SwiftUI - -// MARK: - On load -extension View { - func onLoad(_ action: @escaping () -> Void) -> some View { - modifier(ViewDidLoadModifier(action)) - } -} - -private struct ViewDidLoadModifier: ViewModifier { - private let action: () -> Void - - @State private var didLoad = false - - init(_ action: @escaping () -> Void) { - self.action = action - } - - func body(content: Content) -> some View { - content.onAppear { - if !didLoad { - didLoad.toggle() - action() - } - } - } -} diff --git a/old/View/UIToolkit/View+TappableArea.swift b/old/View/UIToolkit/View+TappableArea.swift deleted file mode 100644 index 8c659d4..0000000 --- a/old/View/UIToolkit/View+TappableArea.swift +++ /dev/null @@ -1,27 +0,0 @@ -import SwiftUI - -extension View { - func tappablePadding(_ insets: EdgeInsets, onTap: @escaping () -> Void) -> some View { - modifier(TappablePadding(insets: insets, onTap: onTap)) - } -} - -struct TappablePadding: ViewModifier { - let insets: EdgeInsets - let onTap: () -> Void - - public init(insets: EdgeInsets, onTap: @escaping () -> Void) { - self.insets = insets - self.onTap = onTap - } - - public func body(content: Content) -> some View { - content - .padding(insets) - .contentShape(Rectangle()) - .onTapGesture { - onTap() - } - .padding(insets.inverted) - } -} diff --git a/project.yml b/project.yml index a920fc2..f90cf15 100644 --- a/project.yml +++ b/project.yml @@ -61,7 +61,6 @@ targets: - path: ConversationsClassic excludes: - .nvim - - old settings: TARGETED_DEVICE_FAMILY: 1 DEBUG_INFORMATION_FORMAT: dwarf-with-dsym