diff --git a/Frameworks/NynjaUIKit/NynjaUIKit.xcodeproj/project.pbxproj b/Frameworks/NynjaUIKit/NynjaUIKit.xcodeproj/project.pbxproj index 7b09f72343802f8e252f3b72b4142130de4341f3..4b37699eec6e4ffcb4841a7193948e4d8df98971 100644 --- a/Frameworks/NynjaUIKit/NynjaUIKit.xcodeproj/project.pbxproj +++ b/Frameworks/NynjaUIKit/NynjaUIKit.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ /* Begin PBXFileReference section */ 1820AD65D6897E3E306C16A2 /* Pods-NynjaUIKit.translate.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.translate.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.translate.xcconfig"; sourceTree = ""; }; + 600B9308D041B8E4DE0DBEF1 /* Pods-NynjaUIKit.loaddb.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.loaddb.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.loaddb.xcconfig"; sourceTree = ""; }; 7336042AC840197E622730FD /* Pods-NynjaUIKit.prerelease.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.prerelease.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.prerelease.xcconfig"; sourceTree = ""; }; 8514D4C120EE27080002378A /* NynjaUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NynjaUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8514D4C420EE27080002378A /* NynjaUIKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NynjaUIKit.h; sourceTree = ""; }; @@ -66,7 +67,6 @@ B90E6396110C47D18FB00838 /* Pods-NynjaUIKit.dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.dev.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.dev.xcconfig"; sourceTree = ""; }; C6C80841C9BA48F16147BAAE /* Pods_NynjaUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NynjaUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C90742AD8E6E2E817F7DB1E9 /* Pods-NynjaUIKit.channels.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.channels.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.channels.xcconfig"; sourceTree = ""; }; - DA270E65F48C8FD1EF3BF945 /* Pods-NynjaUIKit.spotify.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.spotify.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.spotify.xcconfig"; sourceTree = ""; }; E966C049045184395EBB9166 /* Pods-NynjaUIKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.release.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.release.xcconfig"; sourceTree = ""; }; F6A55196057E1D4A2F24AC17 /* Pods-NynjaUIKit.devautotests.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUIKit.devautotests.xcconfig"; path = "../../Pods/Target Support Files/Pods-NynjaUIKit/Pods-NynjaUIKit.devautotests.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -92,7 +92,7 @@ F6A55196057E1D4A2F24AC17 /* Pods-NynjaUIKit.devautotests.xcconfig */, E966C049045184395EBB9166 /* Pods-NynjaUIKit.release.xcconfig */, 7336042AC840197E622730FD /* Pods-NynjaUIKit.prerelease.xcconfig */, - DA270E65F48C8FD1EF3BF945 /* Pods-NynjaUIKit.spotify.xcconfig */, + 600B9308D041B8E4DE0DBEF1 /* Pods-NynjaUIKit.loaddb.xcconfig */, ); name = Pods; sourceTree = ""; @@ -436,7 +436,7 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 5B4DFF722191A0C100E89D17 /* Spotify */ = { + 2611CEEC21807A6E00FFD4DD /* LoadDB */ = { isa = XCBuildConfiguration; baseConfigurationReference = B90E6396110C47D18FB00838 /* Pods-NynjaUIKit.dev.xcconfig */; buildSettings = { @@ -492,11 +492,11 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Spotify; + name = LoadDB; }; - 5B4DFF732191A0C100E89D17 /* Spotify */ = { + 2611CEED21807A6E00FFD4DD /* LoadDB */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DA270E65F48C8FD1EF3BF945 /* Pods-NynjaUIKit.spotify.xcconfig */; + baseConfigurationReference = 600B9308D041B8E4DE0DBEF1 /* Pods-NynjaUIKit.loaddb.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Manual; @@ -519,7 +519,7 @@ SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; - name = Spotify; + name = LoadDB; }; 8514D4C820EE27080002378A /* Dev */ = { isa = XCBuildConfiguration; @@ -861,176 +861,6 @@ }; name = DevAutoTests; }; - 85631BF620EFC7EA0002BE51 /* Channels */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = C90742AD8E6E2E817F7DB1E9 /* Pods-NynjaUIKit.channels.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Channels; - }; - 85631BF720EFC7EA0002BE51 /* Channels */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = C90742AD8E6E2E817F7DB1E9 /* Pods-NynjaUIKit.channels.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Manual; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = NynjaUIKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.nynja.mobile.communicator.NynjaUIKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Channels; - }; - 85631BFC20EFC95E0002BE51 /* Translate */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 1820AD65D6897E3E306C16A2 /* Pods-NynjaUIKit.translate.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Translate; - }; - 85631BFD20EFC95E0002BE51 /* Translate */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 1820AD65D6897E3E306C16A2 /* Pods-NynjaUIKit.translate.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Manual; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = NynjaUIKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.nynja.mobile.communicator.NynjaUIKit; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Translate; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1038,9 +868,7 @@ isa = XCConfigurationList; buildConfigurations = ( 8514D4C820EE27080002378A /* Dev */, - 5B4DFF722191A0C100E89D17 /* Spotify */, - 85631BFC20EFC95E0002BE51 /* Translate */, - 85631BF620EFC7EA0002BE51 /* Channels */, + 2611CEEC21807A6E00FFD4DD /* LoadDB */, 85631BF220EFC50F0002BE51 /* DevAutoTests */, 85631BF020EFC4FC0002BE51 /* Release */, 85631BEE20EFC4F30002BE51 /* Prerelease */, @@ -1052,9 +880,7 @@ isa = XCConfigurationList; buildConfigurations = ( 8514D4CB20EE27080002378A /* Dev */, - 5B4DFF732191A0C100E89D17 /* Spotify */, - 85631BFD20EFC95E0002BE51 /* Translate */, - 85631BF720EFC7EA0002BE51 /* Channels */, + 2611CEED21807A6E00FFD4DD /* LoadDB */, 85631BF320EFC50F0002BE51 /* DevAutoTests */, 85631BF120EFC4FC0002BE51 /* Release */, 85631BEF20EFC4F30002BE51 /* Prerelease */, diff --git a/Nynja-Share/Resources/Info.plist b/Nynja-Share/Resources/Info.plist index 7c5b3060fa8c4ee81507b16e568168c3874b0154..1cd90a1436e8978f550f23eb39e08405e9fbd3ef 100644 --- a/Nynja-Share/Resources/Info.plist +++ b/Nynja-Share/Resources/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 0.5.4.Dev + 0.5.4.Load Config $(Config) ModelsVersion diff --git a/Nynja.xcodeproj/project.pbxproj b/Nynja.xcodeproj/project.pbxproj index 6db4b540859e6cf7969385d28cccac069bc9c80d..762c283e46d7c3be97af03481f0e6d645e5c6c56 100644 --- a/Nynja.xcodeproj/project.pbxproj +++ b/Nynja.xcodeproj/project.pbxproj @@ -147,6 +147,10 @@ 260629712056EF2800CB8F65 /* LinksCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260629702056EF2800CB8F65 /* LinksCell.swift */; }; 2606F3BC20BFE20500CF7F15 /* MessageInteractor+Translation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2606F3BB20BFE20400CF7F15 /* MessageInteractor+Translation.swift */; }; 2610D4642076516900E6E2B2 /* Array+Feature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DCB25320692237001EF0AB /* Array+Feature.swift */; }; + 2611CEF72182090900FFD4DD /* LogWriterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2611CEF62182090900FFD4DD /* LogWriterProtocol.swift */; }; + 2611CEF82182090900FFD4DD /* LogWriterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2611CEF62182090900FFD4DD /* LogWriterProtocol.swift */; }; + 2611CEF92182090900FFD4DD /* LogWriterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2611CEF62182090900FFD4DD /* LogWriterProtocol.swift */; }; + 2611CEFA2182090900FFD4DD /* LogWriterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2611CEF62182090900FFD4DD /* LogWriterProtocol.swift */; }; 26131E02210399BA00BE94F9 /* TranscribeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26131E01210399BA00BE94F9 /* TranscribeService.swift */; }; 26142B1120472ECD004E5FE4 /* MessageLinkTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26142B1020472ECD004E5FE4 /* MessageLinkTable.swift */; }; 26142B1320473BFD004E5FE4 /* DBMessageLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26142B1220473BFD004E5FE4 /* DBMessageLink.swift */; }; @@ -570,9 +574,9 @@ 4B1D7E112029FF5000703228 /* Array+WheelItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7E102029FF5000703228 /* Array+WheelItemModel.swift */; }; 4B1D7E14202A0A0200703228 /* GroupMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7E13202A0A0200703228 /* GroupMode.swift */; }; 4B1F1230203C8DDE00D61D21 /* JobTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1F122F203C8DDE00D61D21 /* JobTable.swift */; }; + 4B2B1558218F5423000E4916 /* SharedColumn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B1557218F5423000E4916 /* SharedColumn.swift */; }; 4B2D063A202DDA2000010A0C /* BackSwipable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D0639202DDA2000010A0C /* BackSwipable.swift */; }; 4B2D063C202E1A1500010A0C /* ContactsExpandedItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2D063B202E1A1500010A0C /* ContactsExpandedItemsFactory.swift */; }; - 4B348FD62163668500CCB0E3 /* LogServiceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090B421635B2E00DCCA5C /* LogServiceStub.swift */; }; 4B348FD7216366A900CCB0E3 /* LogServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090B821635B4700DCCA5C /* LogServiceProtocol.swift */; }; 4B348FD8216366AE00CCB0E3 /* LogServiceTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */; }; 4B348FF22163808300CCB0E3 /* DeletedIndexesCalculatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B348FF12163808300CCB0E3 /* DeletedIndexesCalculatorTests.swift */; }; @@ -643,6 +647,14 @@ 4B7E93382170D1BC001558CF /* RootNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7E93372170D1BC001558CF /* RootNavigationController.swift */; }; 4B7E933B2170D410001558CF /* ForwardSelectorWireFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7E933A2170D410001558CF /* ForwardSelectorWireFrame.swift */; }; 4B7E933E2170D4FF001558CF /* ServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7E933D2170D4FF001558CF /* ServiceFactory.swift */; }; + 4B86C562219C12840006A192 /* DAO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B86C561219C12840006A192 /* DAO.swift */; }; + 4B87712F2192F6940014AD09 /* ColumnDefinitionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B87712E2192F6940014AD09 /* ColumnDefinitionExtension.swift */; }; + 4B877131219312570014AD09 /* ColumnExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B877130219312570014AD09 /* ColumnExtension.swift */; }; + 4B877133219314D50014AD09 /* TypedRequestExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B877132219314D50014AD09 /* TypedRequestExtension.swift */; }; + 4B8771352193154E0014AD09 /* DBExtendedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8771342193154E0014AD09 /* DBExtendedModel.swift */; }; + 4B877137219315770014AD09 /* QueryInterfaceRequestExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B877136219315770014AD09 /* QueryInterfaceRequestExtension.swift */; }; + 4B877139219315AA0014AD09 /* SercerModelConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B877138219315AA0014AD09 /* SercerModelConvertible.swift */; }; + 4B87713B219328780014AD09 /* QueryArgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B87713A219328780014AD09 /* QueryArgs.swift */; }; 4B8996C8204ECE9B00DCB183 /* ContactDAO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8996C7204ECE9B00DCB183 /* ContactDAO.swift */; }; 4B8996CA204ECEA700DCB183 /* ContactDAOProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8996C9204ECEA700DCB183 /* ContactDAOProtocol.swift */; }; 4B8996CD204ED33400DCB183 /* StarDAOProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8996CC204ED33400DCB183 /* StarDAOProtocol.swift */; }; @@ -678,9 +690,13 @@ 4BB0EFBB2151347900704136 /* AlertImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB0EFB82151347900704136 /* AlertImageViewController.swift */; }; 4BB0EFBC2151347900704136 /* AlertImageViewControllerConstraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB0EFB92151347900704136 /* AlertImageViewControllerConstraints.swift */; }; 4BB0EFBD2151347900704136 /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB0EFBA2151347900704136 /* AlertManager.swift */; }; + 4BB35E23219AF46E0007C18E /* RosterRelatedQueryArgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB35E22219AF46E0007C18E /* RosterRelatedQueryArgs.swift */; }; + 4BC8B38D2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC8B38C2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift */; }; 4BD53BF4202C8BCA00569C1A /* AVURLAsset+Duration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E77FBDDC1FFE828400BDB255 /* AVURLAsset+Duration.swift */; }; 4BDC7E61203492CA00BCD381 /* TopSwipable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC7E60203492CA00BCD381 /* TopSwipable.swift */; }; 4BDC7E63203494C000BCD381 /* ScheduleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC7E62203494C000BCD381 /* ScheduleButton.swift */; }; + 4BDDAAE9218CA28300F775A7 /* HomeDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDAAE8218CA28300F775A7 /* HomeDataProvider.swift */; }; + 4BDDAAEB218CA2C700F775A7 /* HomeDataProviderImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDAAEA218CA2C700F775A7 /* HomeDataProviderImpl.swift */; }; 4BE2C5D92142EAC500A73DD9 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5D02142EAC500A73DD9 /* AudioPlayer.swift */; }; 4BE2C5DA2142EAC500A73DD9 /* AudioSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5D22142EAC500A73DD9 /* AudioSessionManager.swift */; }; 4BE2C5DB2142EAC500A73DD9 /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5D42142EAC500A73DD9 /* AudioRecorder.swift */; }; @@ -692,7 +708,6 @@ 4BE2C5E72142EB5A00A73DD9 /* NynjaCommunicatorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5E52142EB5A00A73DD9 /* NynjaCommunicatorService.swift */; }; 4BE2C5E82142EB5A00A73DD9 /* NynjaRingingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5E62142EB5A00A73DD9 /* NynjaRingingService.swift */; }; 4BEE89D69CACB85ABEE9046F /* QRCodeGeneratorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFAB7D8D9024C26FA51BF783 /* QRCodeGeneratorPresenter.swift */; }; - 4BF090B621635B3000DCCA5C /* LogServiceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090B421635B2E00DCCA5C /* LogServiceStub.swift */; }; 4BF090B921635B4700DCCA5C /* LogServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090B821635B4700DCCA5C /* LogServiceProtocol.swift */; }; 4BF090BB21635B6600DCCA5C /* LogServiceTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */; }; 4BF090BC21635B8000DCCA5C /* LogServiceTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */; }; @@ -715,6 +730,8 @@ 4BF2C3E42188BABC00E59F6C /* UIDeviceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A77FD71FACC360004AE609 /* UIDeviceExtension.swift */; }; 4BF2C3E92189B49500E59F6C /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D485DE41F0AD96D00E12FB1 /* Localizable.swift */; }; 4BF2C3F02189F58F00E59F6C /* ServerSignal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF2C3EF2189F58F00E59F6C /* ServerSignal.swift */; }; + 4BF2C3FC218AFE9D00E59F6C /* FullNameRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF2C3FB218AFE9D00E59F6C /* FullNameRepresentable.swift */; }; + 4BF2C3FD218AFF6300E59F6C /* FullNameRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF2C3FB218AFE9D00E59F6C /* FullNameRepresentable.swift */; }; 4C5EEA13EBC6A8398F08DCD1 /* MainWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AAB8F770774CE3AE3FD6E1 /* MainWireframe.swift */; }; 4D53FE7454959323B1CCFD96 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D270F638DBB2D8FC1BDEB633 /* ProfileViewController.swift */; }; 4DAEBCF361B86B0AD3C98749 /* EditUsernameInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBE3BAC9B7EA418FB463EF04 /* EditUsernameInteractor.swift */; }; @@ -1946,7 +1963,7 @@ E7598F6C1FA1D8B90082FBE7 /* ProfileContactCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7598F651FA1D8B80082FBE7 /* ProfileContactCellLayout.swift */; }; E761A0D91F8B8CF000C088E0 /* EditProfileViewControllerLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E761A0D81F8B8CF000C088E0 /* EditProfileViewControllerLayout.swift */; }; E761A0DC1F8B8F3900C088E0 /* NynjaButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E761A0DB1F8B8F3900C088E0 /* NynjaButton.swift */; }; - E76462891FCD64790091FC2E /* DBModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76462881FCD64790091FC2E /* DBModelProtocol.swift */; }; + E76462891FCD64790091FC2E /* DBModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76462881FCD64790091FC2E /* DBModel.swift */; }; E764628C1FCD67AC0091FC2E /* DBModelConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = E764628B1FCD67AC0091FC2E /* DBModelConvertible.swift */; }; E76491961F7A529D001E741C /* WheelContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76491951F7A529D001E741C /* WheelContainer.swift */; }; E764919B1F7A5485001E741C /* MainWheelContainerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76491991F7A5485001E741C /* MainWheelContainerDelegate.swift */; }; @@ -2511,6 +2528,7 @@ 260552A51F9E1CD100D68DE6 /* SearchHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SearchHandler.swift; path = Services/HandleServices/SearchHandler.swift; sourceTree = ""; }; 260629702056EF2800CB8F65 /* LinksCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinksCell.swift; sourceTree = ""; }; 2606F3BB20BFE20400CF7F15 /* MessageInteractor+Translation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageInteractor+Translation.swift"; sourceTree = ""; }; + 2611CEF62182090900FFD4DD /* LogWriterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogWriterProtocol.swift; sourceTree = ""; }; 26131E01210399BA00BE94F9 /* TranscribeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscribeService.swift; sourceTree = ""; }; 26142B1020472ECD004E5FE4 /* MessageLinkTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageLinkTable.swift; sourceTree = ""; }; 26142B1220473BFD004E5FE4 /* DBMessageLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBMessageLink.swift; sourceTree = ""; }; @@ -2525,6 +2543,7 @@ 2625DBF720EFC5DE00E01C05 /* FourCharCode+StringLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FourCharCode+StringLiteralConvertible.swift"; sourceTree = ""; }; 2625F29E212463E8007C42B5 /* ProgressIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressIdentifier.swift; sourceTree = ""; }; 262D43862033417F002F1E45 /* FriendExtansion+BERT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FriendExtansion+BERT.swift"; sourceTree = ""; }; + 26305F702180765E00400DB0 /* LoadDBConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = LoadDBConfig.xcconfig; sourceTree = ""; }; 2632139020D797F500C31144 /* TranslationViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslationViewProtocol.swift; sourceTree = ""; }; 2633EF6D205212F700DB3868 /* MemberDAOProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDAOProtocol.swift; sourceTree = ""; }; 2633EF6F2052130400DB3868 /* MemberDAO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDAO.swift; sourceTree = ""; }; @@ -2851,6 +2870,7 @@ 4B1D7E102029FF5000703228 /* Array+WheelItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+WheelItemModel.swift"; sourceTree = ""; }; 4B1D7E13202A0A0200703228 /* GroupMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMode.swift; sourceTree = ""; }; 4B1F122F203C8DDE00D61D21 /* JobTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JobTable.swift; sourceTree = ""; }; + 4B2B1557218F5423000E4916 /* SharedColumn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedColumn.swift; sourceTree = ""; }; 4B2D0639202DDA2000010A0C /* BackSwipable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackSwipable.swift; sourceTree = ""; }; 4B2D063B202E1A1500010A0C /* ContactsExpandedItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsExpandedItemsFactory.swift; sourceTree = ""; }; 4B348FF12163808300CCB0E3 /* DeletedIndexesCalculatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedIndexesCalculatorTests.swift; sourceTree = ""; }; @@ -2909,6 +2929,14 @@ 4B7E93372170D1BC001558CF /* RootNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootNavigationController.swift; sourceTree = ""; }; 4B7E933A2170D410001558CF /* ForwardSelectorWireFrame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardSelectorWireFrame.swift; sourceTree = ""; }; 4B7E933D2170D4FF001558CF /* ServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceFactory.swift; sourceTree = ""; }; + 4B86C561219C12840006A192 /* DAO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DAO.swift; sourceTree = ""; }; + 4B87712E2192F6940014AD09 /* ColumnDefinitionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColumnDefinitionExtension.swift; sourceTree = ""; }; + 4B877130219312570014AD09 /* ColumnExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColumnExtension.swift; sourceTree = ""; }; + 4B877132219314D50014AD09 /* TypedRequestExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedRequestExtension.swift; sourceTree = ""; }; + 4B8771342193154E0014AD09 /* DBExtendedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBExtendedModel.swift; sourceTree = ""; }; + 4B877136219315770014AD09 /* QueryInterfaceRequestExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryInterfaceRequestExtension.swift; sourceTree = ""; }; + 4B877138219315AA0014AD09 /* SercerModelConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SercerModelConvertible.swift; sourceTree = ""; }; + 4B87713A219328780014AD09 /* QueryArgs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryArgs.swift; sourceTree = ""; }; 4B8996C7204ECE9B00DCB183 /* ContactDAO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDAO.swift; sourceTree = ""; }; 4B8996C9204ECEA700DCB183 /* ContactDAOProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDAOProtocol.swift; sourceTree = ""; }; 4B8996CC204ED33400DCB183 /* StarDAOProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarDAOProtocol.swift; sourceTree = ""; }; @@ -2938,8 +2966,12 @@ 4BB0EFB82151347900704136 /* AlertImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertImageViewController.swift; sourceTree = ""; }; 4BB0EFB92151347900704136 /* AlertImageViewControllerConstraints.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertImageViewControllerConstraints.swift; sourceTree = ""; }; 4BB0EFBA2151347900704136 /* AlertManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertManager.swift; sourceTree = ""; }; + 4BB35E22219AF46E0007C18E /* RosterRelatedQueryArgs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RosterRelatedQueryArgs.swift; sourceTree = ""; }; + 4BC8B38C2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsProvidingFetchingArgs.swift; sourceTree = ""; }; 4BDC7E60203492CA00BCD381 /* TopSwipable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopSwipable.swift; sourceTree = ""; }; 4BDC7E62203494C000BCD381 /* ScheduleButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleButton.swift; sourceTree = ""; }; + 4BDDAAE8218CA28300F775A7 /* HomeDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeDataProvider.swift; sourceTree = ""; }; + 4BDDAAEA218CA2C700F775A7 /* HomeDataProviderImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeDataProviderImpl.swift; sourceTree = ""; }; 4BE2C5D02142EAC500A73DD9 /* AudioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; 4BE2C5D22142EAC500A73DD9 /* AudioSessionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioSessionManager.swift; sourceTree = ""; }; 4BE2C5D42142EAC500A73DD9 /* AudioRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioRecorder.swift; sourceTree = ""; }; @@ -2950,7 +2982,6 @@ 4BE2C5E12142EB0E00A73DD9 /* AudioManagerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioManagerDelegate.swift; sourceTree = ""; }; 4BE2C5E52142EB5A00A73DD9 /* NynjaCommunicatorService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NynjaCommunicatorService.swift; sourceTree = ""; }; 4BE2C5E62142EB5A00A73DD9 /* NynjaRingingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NynjaRingingService.swift; sourceTree = ""; }; - 4BF090B421635B2E00DCCA5C /* LogServiceStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogServiceStub.swift; sourceTree = ""; }; 4BF090B821635B4700DCCA5C /* LogServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogServiceProtocol.swift; sourceTree = ""; }; 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogServiceTopic.swift; sourceTree = ""; }; 4BF090C421635E8600DCCA5C /* Message+LinkedId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+LinkedId.swift"; sourceTree = ""; }; @@ -2958,6 +2989,7 @@ 4BF090CB21635FDC00DCCA5C /* Message+Type.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+Type.swift"; sourceTree = ""; }; 4BF2C3DF2188B27500E59F6C /* Injectable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Injectable.swift; sourceTree = ""; }; 4BF2C3EF2189F58F00E59F6C /* ServerSignal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSignal.swift; sourceTree = ""; }; + 4BF2C3FB218AFE9D00E59F6C /* FullNameRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullNameRepresentable.swift; sourceTree = ""; }; 4CDA2BE900351F21464CE687 /* DateTimePickerInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DateTimePickerInteractor.swift; sourceTree = ""; }; 4D247CBC45C1C1267BBBB289 /* QRCodeReaderInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = QRCodeReaderInteractor.swift; sourceTree = ""; }; 4F7C039B61A0663D43BE5AE5 /* SelectCountryProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectCountryProtocols.swift; sourceTree = ""; }; @@ -3938,6 +3970,7 @@ D1D5302025583482829BBF2E /* GroupStorageViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GroupStorageViewController.swift; sourceTree = ""; }; D270F638DBB2D8FC1BDEB633 /* ProfileViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; D4B94201A3DDCB11C62D6A16 /* AddContactViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddContactViewController.swift; sourceTree = ""; }; + D55BAC5832CAFB50A4F64387 /* Pods-Nynja.loaddb.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja.loaddb.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja/Pods-Nynja.loaddb.xcconfig"; sourceTree = ""; }; D7956526150F4211DE78173E /* AddContactViaPhoneInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddContactViaPhoneInteractor.swift; sourceTree = ""; }; D8AC83D4F29DA35FEFDFBC65 /* QRCodeGeneratorViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = QRCodeGeneratorViewController.swift; sourceTree = ""; }; D8F8C8AFEB81C734967FE902 /* EditGroupNameViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditGroupNameViewController.swift; sourceTree = ""; }; @@ -4005,7 +4038,7 @@ E7598F651FA1D8B80082FBE7 /* ProfileContactCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileContactCellLayout.swift; sourceTree = ""; }; E761A0D81F8B8CF000C088E0 /* EditProfileViewControllerLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfileViewControllerLayout.swift; sourceTree = ""; }; E761A0DB1F8B8F3900C088E0 /* NynjaButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NynjaButton.swift; sourceTree = ""; }; - E76462881FCD64790091FC2E /* DBModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBModelProtocol.swift; sourceTree = ""; }; + E76462881FCD64790091FC2E /* DBModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBModel.swift; sourceTree = ""; }; E764628B1FCD67AC0091FC2E /* DBModelConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBModelConvertible.swift; sourceTree = ""; }; E76491951F7A529D001E741C /* WheelContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WheelContainer.swift; sourceTree = ""; }; E76491991F7A5485001E741C /* MainWheelContainerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWheelContainerDelegate.swift; sourceTree = ""; }; @@ -4086,6 +4119,7 @@ EE1EF22666DC92AE739E2DA5 /* Pods-Nynja.stickers.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja.stickers.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja/Pods-Nynja.stickers.xcconfig"; sourceTree = ""; }; EE2260535ED2762F80FA7A38 /* MapProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MapProtocols.swift; sourceTree = ""; }; EE63F9D9E7D7D9B4CAF2FE90 /* TopUpAccountPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TopUpAccountPresenter.swift; sourceTree = ""; }; + EF57CF149EF8224DA702DEB9 /* Pods-Nynja-Share.loaddb.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja-Share.loaddb.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja-Share/Pods-Nynja-Share.loaddb.xcconfig"; sourceTree = ""; }; EF74AC6D4879E4DA38B3C352 /* AddContactByUsernameWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddContactByUsernameWireframe.swift; sourceTree = ""; }; EFF6A30BDE89BF7887B67DA0 /* ProfileInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ProfileInteractor.swift; sourceTree = ""; }; F01F3338177726EB10E0D040 /* LoginViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; @@ -4196,6 +4230,7 @@ F1D4A49F20762A1D00F31089 /* Configurable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configurable.swift; sourceTree = ""; }; F1EED41420C57C30001060C4 /* PhotoPreviewSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPreviewSource.swift; sourceTree = ""; }; F1F219FC7966064C555AC2A4 /* TopUpAccountViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TopUpAccountViewController.swift; sourceTree = ""; }; + F437803397DA4D6AA4459469 /* Pods-NynjaUnitTests.loaddb.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUnitTests.loaddb.xcconfig"; path = "Pods/Target Support Files/Pods-NynjaUnitTests/Pods-NynjaUnitTests.loaddb.xcconfig"; sourceTree = ""; }; F46A5D92A279FA0A509DA508 /* Pods-NynjaUnitTests.translate.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NynjaUnitTests.translate.xcconfig"; path = "Pods/Target Support Files/Pods-NynjaUnitTests/Pods-NynjaUnitTests.translate.xcconfig"; sourceTree = ""; }; F56141F2CF85255940EA304F /* EditPhotoWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditPhotoWireframe.swift; sourceTree = ""; }; F79C9355E1AA4B373567F765 /* LanguageSettingsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LanguageSettingsInteractor.swift; sourceTree = ""; }; @@ -5961,6 +5996,7 @@ 266AE8C2203496B60096A12C /* AsyncOperation.swift */, F112B18F20E0FBE800B06E3E /* AsyncBlockOperation.swift */, 263C04E82132E2FF00B8F0BE /* WrappedTaskOperation.swift */, + 4BF2C3FB218AFE9D00E59F6C /* FullNameRepresentable.swift */, ); name = Library; sourceTree = ""; @@ -6181,6 +6217,7 @@ 3A22662B1EFEF31E00D6A867 /* Assets.xcassets */, 6D36F8E41F0ADBD300FA1AC8 /* Localizable.strings */, F1313AFE20888CAB00E04092 /* DevConfig.xcconfig */, + 26305F702180765E00400DB0 /* LoadDBConfig.xcconfig */, F10AFE9A20EF8B9A00C7CE83 /* DevAutoTests.xcconfig */, F1313AFF20888CB800E04092 /* PrereleaseConfig.xcconfig */, F1313B0020888CC400E04092 /* ReleaseConfig.xcconfig */, @@ -7072,6 +7109,23 @@ path = AlertImageViewController; sourceTree = ""; }; + 4BC8B38B2191AC200086DC6C /* Entity */ = { + isa = PBXGroup; + children = ( + 4BC8B38C2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift */, + ); + name = Entity; + sourceTree = ""; + }; + 4BDDAAE7218CA27200F775A7 /* HomeDataProvider */ = { + isa = PBXGroup; + children = ( + 4BDDAAE8218CA28300F775A7 /* HomeDataProvider.swift */, + 4BDDAAEA218CA2C700F775A7 /* HomeDataProviderImpl.swift */, + ); + path = HomeDataProvider; + sourceTree = ""; + }; 4BE2C5CE2142EAC500A73DD9 /* Audio */ = { isa = PBXGroup; children = ( @@ -7144,8 +7198,8 @@ isa = PBXGroup; children = ( 4B7C73EF215A5508007924DB /* LogService.swift */, - 4BF090B421635B2E00DCCA5C /* LogServiceStub.swift */, 4BF090B821635B4700DCCA5C /* LogServiceProtocol.swift */, + 2611CEF62182090900FFD4DD /* LogWriterProtocol.swift */, 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */, ); path = LogService; @@ -7207,6 +7261,7 @@ 50D9FF79FEBFA4AFE9A2791A /* Interactor */ = { isa = PBXGroup; children = ( + 4BDDAAE7218CA27200F775A7 /* HomeDataProvider */, EFF6A30BDE89BF7887B67DA0 /* ProfileInteractor.swift */, ); path = Interactor; @@ -7538,6 +7593,9 @@ 61CB12AA514912C6B8E4F670 /* Pods-Nynja.devautotests.xcconfig */, 3A8C12DDFD0D831F21959665 /* Pods-Nynja-Share.devautotests.xcconfig */, CB70AD73977CD00AD11C287C /* Pods-NynjaUnitTests.devautotests.xcconfig */, + D55BAC5832CAFB50A4F64387 /* Pods-Nynja.loaddb.xcconfig */, + EF57CF149EF8224DA702DEB9 /* Pods-Nynja-Share.loaddb.xcconfig */, + F437803397DA4D6AA4459469 /* Pods-NynjaUnitTests.loaddb.xcconfig */, 7ADCB0C891B31AF691307B4F /* Pods-Nynja.spotify.xcconfig */, 7F7FC209C7703E3E7617D782 /* Pods-Nynja-Share.spotify.xcconfig */, A0A57BD401783039D49B7B75 /* Pods-NynjaUnitTests.spotify.xcconfig */, @@ -9994,6 +10052,7 @@ A433D99F20A5C17600C946F9 /* ContactsProvider */ = { isa = PBXGroup; children = ( + 4BC8B38B2191AC200086DC6C /* Entity */, A433D9A220A5C19600C946F9 /* ContactsProviding.swift */, A433D9A020A5C18C00C946F9 /* ContactsProvider.swift */, ); @@ -10203,6 +10262,7 @@ A4166F5F205FEA120008F231 /* MessageLink.swift */, 26588E6620A20E49000D3E1A /* Customizable.swift */, 2651093E20ADB81100F1B38B /* NotificationSettingProtocol.swift */, + 4B877138219315AA0014AD09 /* SercerModelConvertible.swift */, ); path = ServerModel; sourceTree = ""; @@ -11920,10 +11980,13 @@ E7417E961FBED8FD00E5C124 /* DB */ = { isa = PBXGroup; children = ( + 4B86C561219C12840006A192 /* DAO.swift */, E764628D1FCD68020091FC2E /* Protocols */, E74FD69B1FC5D04A00656611 /* Extensions */, E73CEF0F1FC2F52200246066 /* Models */, E7417E971FBED90600E5C124 /* Tables */, + 4B87713A219328780014AD09 /* QueryArgs.swift */, + 4BB35E22219AF46E0007C18E /* RosterRelatedQueryArgs.swift */, ); path = DB; sourceTree = ""; @@ -12020,9 +12083,13 @@ children = ( E745A24A20061AD400D7EF42 /* DatabaseExtension.swift */, E70938401FBEE488006CCDC6 /* TableDefinitionExtension.swift */, + 4B87712E2192F6940014AD09 /* ColumnDefinitionExtension.swift */, 8509FC802158E11000734D93 /* TableAlternationExtension.swift */, E74FD69C1FC5D06200656611 /* TransactionObserverExtension.swift */, A48BF1C120A1CA390076D892 /* Array+Table.swift */, + 4B877130219312570014AD09 /* ColumnExtension.swift */, + 4B877132219314D50014AD09 /* TypedRequestExtension.swift */, + 4B877136219315770014AD09 /* QueryInterfaceRequestExtension.swift */, ); path = Extensions; sourceTree = ""; @@ -12110,7 +12177,8 @@ children = ( E7C9CEC91FCC27A30090C2E0 /* FeedProtocol.swift */, E7AE41651FCC498800C3ED5D /* FeedType.swift */, - E76462881FCD64790091FC2E /* DBModelProtocol.swift */, + E76462881FCD64790091FC2E /* DBModel.swift */, + 4B8771342193154E0014AD09 /* DBExtendedModel.swift */, ); path = Base; sourceTree = ""; @@ -12260,6 +12328,7 @@ E7417E981FBED91100E5C124 /* Table.swift */, 85B0013121270DEC000C89FE /* TableOrder.swift */, E709383E1FBEE41D006CCDC6 /* Describable.swift */, + 4B2B1557218F5423000E4916 /* SharedColumn.swift */, ); path = Base; sourceTree = ""; @@ -14631,6 +14700,7 @@ A42CE5B020692EDB000889CC /* TypeSpec.swift in Sources */, 26B32B971FE20BB500888A0A /* DescExtension+BERT.swift in Sources */, A42CE54220692EDA000889CC /* muc.swift in Sources */, + 2611CEF82182090900FFD4DD /* LogWriterProtocol.swift in Sources */, A45F115620B4226600F45004 /* RawRepresentable+Localized.swift in Sources */, 4BD53BF4202C8BCA00569C1A /* AVURLAsset+Duration.swift in Sources */, B767F48D215D1C2500FA9B27 /* ComingSoonProtocol.swift in Sources */, @@ -14758,6 +14828,7 @@ A4330A6F2109EBA70060BD93 /* CountriesProvider.swift in Sources */, A42CE54820692EDB000889CC /* reader.swift in Sources */, A42CE60A20692EDB000889CC /* Index_Spec.swift in Sources */, + 4BF2C3FD218AFF6300E59F6C /* FullNameRepresentable.swift in Sources */, 26352916207572AA00DC6FBD /* JobExtension.swift in Sources */, 8566BB12215BC39D00320E15 /* FetchType.swift in Sources */, 8520040120D4672E007C0036 /* StickerPack.swift in Sources */, @@ -14826,6 +14897,7 @@ 6D6234F61F1E150600EF375F /* HistoryTableDS.swift in Sources */, FBE3885D2118849000149721 /* AlertActionWrapper.swift in Sources */, F119E66E20D24BBF0043A532 /* MultiplePreviewWireframe.swift in Sources */, + 2611CEF72182090900FFD4DD /* LogWriterProtocol.swift in Sources */, 2648C40F2069B52100863614 /* ChangeNumberStep3Presenter.swift in Sources */, A42D51A0206A361400EEB952 /* reader.swift in Sources */, A42D52BB206A53AA00EEB952 /* Vox_Spec.swift in Sources */, @@ -14840,6 +14912,7 @@ 262D43872033417F002F1E45 /* FriendExtansion+BERT.swift in Sources */, 2600CCC1216D47DC00EDC9C3 /* OptionallyActionCellViewModel.swift in Sources */, FE58F9B1208F00FE004AFDD3 /* MessageEditActionTable.swift in Sources */, + 4B87713B219328780014AD09 /* QueryArgs.swift in Sources */, F105C6A0209F71BF0091786A /* CameraInteractor.swift in Sources */, 4B4266BA204D898900194BC1 /* ForwardSelectorDisplayMode.swift in Sources */, 8572C3B92092364C00E4840C /* StickerPackageDataSource.swift in Sources */, @@ -15205,6 +15278,7 @@ 267BE2AF1FE13AB600C47E18 /* ParticipantsPresenter.swift in Sources */, 2648C4112069B52100863614 /* ChangeNumberCodeView.swift in Sources */, 35F2DA611F73CAD400777920 /* NotificationManager.swift in Sources */, + 4B86C562219C12840006A192 /* DAO.swift in Sources */, 26C1A3ED2031D3030009F7F0 /* OtherUserContainerViewController.swift in Sources */, FB16E79920EFAFA8009FA203 /* Money.swift in Sources */, BA982E458F95A7A5AB4A8A73 /* TutorialViewController.swift in Sources */, @@ -15220,6 +15294,7 @@ 2C95C06FF47CF32C3B35FF4F /* TutorialInteractor.swift in Sources */, 8EBFF1692004033F00CC4C25 /* GroupAudiosCell.swift in Sources */, 855AC540208E45AA00DC2335 /* StickerCellModel.swift in Sources */, + 4B877131219312570014AD09 /* ColumnExtension.swift in Sources */, 3A2A99831EFAD2FB002749B3 /* PageControl.swift in Sources */, E784388156A5228026955A54 /* TutorialWireframe.swift in Sources */, E73315F21FB0BB0300C273FF /* Array+Contact.swift in Sources */, @@ -15578,7 +15653,7 @@ 8ED0F3D01FBC5CF2004916AB /* GroupsListTableDS.swift in Sources */, 260225DD20F379EF004FC238 /* MessageConvertionView.swift in Sources */, A45F111F20B4218D00F45004 /* InfoView.swift in Sources */, - E76462891FCD64790091FC2E /* DBModelProtocol.swift in Sources */, + E76462891FCD64790091FC2E /* DBModel.swift in Sources */, A418DA3120ED092F00FE780B /* InfoChannelView.swift in Sources */, E71AB31E1F70188C00A0CF5A /* WheelItemViewFactory.swift in Sources */, 8580BACE20BD98CF00239D9D /* UpdateResult.swift in Sources */, @@ -15651,6 +15726,7 @@ A4688DFC20652DE30013660D /* StorageChange.swift in Sources */, 5683555B8382F7F37FEE1AF5 /* ProfileWireframe.swift in Sources */, A42D51AC206A361400EEB952 /* Auth.swift in Sources */, + 4B877139219315AA0014AD09 /* SercerModelConvertible.swift in Sources */, A42D52CD206A53AB00EEB952 /* chain_Spec.swift in Sources */, 8580BACA20BD983400239D9D /* MentionTransitionProtocol.swift in Sources */, A44B4D5B20CE9BDF00CA700A /* ImageCell.swift in Sources */, @@ -15702,6 +15778,7 @@ A45F112220B4218D00F45004 /* MessageVideoView.swift in Sources */, A42D51A8206A361400EEB952 /* Index.swift in Sources */, 859B862D204820DC003272B2 /* ThemePickerViewController.swift in Sources */, + 4BDDAAE9218CA28300F775A7 /* HomeDataProvider.swift in Sources */, 855AC533208E441500DC2335 /* StickersInputViewController.swift in Sources */, 00F7B34A202B350A00E443E1 /* TimeZoneManager.swift in Sources */, A94B03A70E016BDA759B0703 /* EditProfileViewController.swift in Sources */, @@ -15711,6 +15788,7 @@ F105C6BE20A1347E0091786A /* PhotoPreviewInteractor.swift in Sources */, F18AEAFD20C15792004FE01C /* SelectAvatarCoordinator.swift in Sources */, 85D66A1220BD965300FBD803 /* UserMentionTableViewCell.swift in Sources */, + 4BB35E23219AF46E0007C18E /* RosterRelatedQueryArgs.swift in Sources */, 2657BE51201233E300F21935 /* ImageFilledItemModel.swift in Sources */, 85BA176120BEA7BD001EF8AC /* StickerPreviewContainerView.swift in Sources */, 85CB25DF20D7325500D5E565 /* StickerPackExtension.swift in Sources */, @@ -15743,6 +15821,7 @@ 85458CED212D74B400BA8814 /* P2P+Opponent.swift in Sources */, E79061B41FBF10AA009FD83A /* MessageTable.swift in Sources */, 00EB7872206E286A00E3FB03 /* WCReusableViews.swift in Sources */, + 4BC8B38D2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift in Sources */, 8ED0F3C11FBC5CB1004916AB /* Contact+DialogCellModel.swift in Sources */, 8EE9BC1A1FFE79FF00ECBBC7 /* GroupStorageCell.swift in Sources */, FEA655E02167777E00B44029 /* SeedBackupWalletPresenter.swift in Sources */, @@ -15793,6 +15872,7 @@ A4679B8920B2DA550021FE9C /* Array+ChannelSubscriber.swift in Sources */, A4ED79AC20C7056C00A41F67 /* AllChannelsItemsFactory.swift in Sources */, E707C4AF1FA0F6E700B86137 /* ProfileActionCell.swift in Sources */, + 4B877137219315770014AD09 /* QueryInterfaceRequestExtension.swift in Sources */, 2648C4172069B52100863614 /* ChangeNumberStep2Wireframe.swift in Sources */, A45F111A20B4218D00F45004 /* MessageImageView.swift in Sources */, 8520040420D4F311007C0036 /* StickerPreviewAnimator.swift in Sources */, @@ -15934,6 +16014,7 @@ 00102F42202C914400A877A9 /* NynjaCalendarCell.swift in Sources */, 853FB0662049B193000996C5 /* SupportPresenter.swift in Sources */, 267BE2BA1FE13AB600C47E18 /* ParticipantsWireframe.swift in Sources */, + 4B8771352193154E0014AD09 /* DBExtendedModel.swift in Sources */, F11786CC20A8E4FD007A9A1B /* CameraVideoPreviewViewController.swift in Sources */, A408A0BA20C174040029F54B /* ChannelsListPresenter.swift in Sources */, 850FC60F203310D200832D87 /* SelectionAvatarView.swift in Sources */, @@ -16027,6 +16108,7 @@ 8524C4D6217772C8003BF374 /* Member+Construct.swift in Sources */, A44B4D5A20CE9BDF00CA700A /* SwitchCell.swift in Sources */, F1607B3020B2FD5A00BDF60A /* QRNotificationVIew.swift in Sources */, + 4BF2C3FC218AFE9D00E59F6C /* FullNameRepresentable.swift in Sources */, FEA655CB2167777E00B44029 /* SeedVerificationWalletPresenter.swift in Sources */, 260313A420A0A4BA009AC66D /* DirectableActionCellViewModel.swift in Sources */, 859773232087965700B03B4A /* NynjaControlContainerView.swift in Sources */, @@ -16069,6 +16151,7 @@ 5BC1D38120D3B54B002A44B3 /* CallInfoView.swift in Sources */, 264638291FFFE835002590E6 /* RepliesInteractor.swift in Sources */, 85D66A2220BD970400FBD803 /* BBCodeElement.swift in Sources */, + 4B87712F2192F6940014AD09 /* ColumnDefinitionExtension.swift in Sources */, B723C634204DA54200884FFD /* SettingsDataAndStorageTableDataSource.swift in Sources */, FEA655E72167777E00B44029 /* SeedBackupWalletOutputParams.swift in Sources */, 851EBD7F20B418890065C644 /* StickersInputView.swift in Sources */, @@ -16246,6 +16329,8 @@ 4B1D7E092029D86600703228 /* CreateGroupItemsFactory.swift in Sources */, 85052E5720D1A90D00BCC386 /* StickerImagePreviewView.swift in Sources */, 8580BACC20BD984500239D9D /* MessageEditInfo.swift in Sources */, + 4B877133219314D50014AD09 /* TypedRequestExtension.swift in Sources */, + 4B2B1558218F5423000E4916 /* SharedColumn.swift in Sources */, 850FC5FA2032F64100832D87 /* ForwardSelectorWireFrame.swift in Sources */, 3AA4E6ACDBCB060172A7A279 /* FavoritesProtocols.swift in Sources */, 9B81AD92215A5EEA00993A8C /* ActiveSpeakerView.swift in Sources */, @@ -16254,6 +16339,7 @@ 85D77807211D9B980044E72F /* ScrollPosition.swift in Sources */, FEA655F22167777E00B44029 /* PaymentWireFrame.swift in Sources */, DF55CCC682DAB5392F2A763D /* FavoritesPresenter.swift in Sources */, + 4BDDAAEB218CA2C700F775A7 /* HomeDataProviderImpl.swift in Sources */, 002FFCE1202DE8BE003CCB26 /* Date+Extension.swift in Sources */, B723C626204D86AF00884FFD /* SettingsDataAndStorageViewController.swift in Sources */, A4494C7E2080F26600223B06 /* ChannelsItemsFactory.swift in Sources */, @@ -16654,7 +16740,6 @@ FB816EF020B5B36D00093DCD /* HistoryRequestModelTests.swift in Sources */, 85458CEA212D742300BA8814 /* muc.swift in Sources */, A4CB153B21039C1100C3B68B /* JailbreakDetectorProtocol.swift in Sources */, - 4BF090B621635B3000DCCA5C /* LogServiceStub.swift in Sources */, 4B8C05952164A9D60034D8F3 /* ChatCellModelMock.swift in Sources */, 85458D01212D7C1A00BA8814 /* StringAtomExtension.swift in Sources */, A4AB8E522105EC46005F9B0C /* TextField.swift in Sources */, @@ -16675,6 +16760,7 @@ 4BF090CE21635FEE00DCCA5C /* Message+Type.swift in Sources */, A49EE6D7210B110800B700B1 /* Link.swift in Sources */, 4B8FC31C2163CD8C00602D6B /* ChatCellModel.swift in Sources */, + 2611CEF92182090900FFD4DD /* LogWriterProtocol.swift in Sources */, 85458CE4212D731300BA8814 /* MessageIdentifiers.swift in Sources */, FB61D651214FEC8200CB2A1F /* LocalizableConstants.swift in Sources */, A4330A562109D60D0060BD93 /* QueryFactoryProtocol.swift in Sources */, @@ -16721,12 +16807,12 @@ buildActionMask = 2147483647; files = ( 4B348FD8216366AE00CCB0E3 /* LogServiceTopic.swift in Sources */, + 2611CEFA2182090900FFD4DD /* LogWriterProtocol.swift in Sources */, FE21ACB92113AB3C006010A0 /* KeychainServiceTest.swift in Sources */, FE21ACBC2113AB92006010A0 /* QueryFactoryProtocol.swift in Sources */, 4B348FD7216366A900CCB0E3 /* LogServiceProtocol.swift in Sources */, FE21ACBD2113ABBF006010A0 /* DictionaryExtension.swift in Sources */, FE21ACBA2113AB4B006010A0 /* KeychainService.swift in Sources */, - 4B348FD62163668500CCB0E3 /* LogServiceStub.swift in Sources */, 4BF2C3E92189B49500E59F6C /* Localizable.swift in Sources */, 85458CDC212D6FFF00BA8814 /* String+Split.swift in Sources */, FB61D652214FEC8300CB2A1F /* LocalizableConstants.swift in Sources */, @@ -16809,6 +16895,267 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 26305F6B2180763600400DB0 /* LoadDB */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 26305F702180765E00400DB0 /* LoadDBConfig.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = LoadDB; + }; + 26305F6C2180763600400DB0 /* LoadDB */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D55BAC5832CAFB50A4F64387 /* Pods-Nynja.loaddb.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIconSpotify; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Nynja/Resources/Nynja.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 9GKQ5AMF2B; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "$(SRCROOT)/Nynja/Resources/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_SWIFT_FLAGS = "$(inherited) -D SQLITE_HAS_CODEC -D GRDBCIPHER $(inherited) \"-D\" \"COCOAPODS\" -Xfrontend -debug-time-function-bodies -Xfrontend -warn-long-expression-type-checking=20 -Xfrontend -warn-long-function-bodies=20"; + PRODUCT_BUNDLE_IDENTIFIER = "$(BundleIdentifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "84763be4-0d2a-4728-9e67-b65eb99614ad"; + PROVISIONING_PROFILE_SPECIFIER = DevBundle_Dev; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OBJC_BRIDGING_HEADER = "Nynja-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 4.0; + SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + }; + name = LoadDB; + }; + 26305F6D2180763600400DB0 /* LoadDB */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EF57CF149EF8224DA702DEB9 /* Pods-Nynja-Share.loaddb.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = "Nynja-Share/Resources/Nynja-Share.entitlements"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 9GKQ5AMF2B; + ENABLE_BITCODE = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Nynja-Share/Resources/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DSHARE_EXTENSION -Xfrontend -warn-long-expression-type-checking=20 -Xfrontend -warn-long-function-bodies=20"; + PRODUCT_BUNDLE_IDENTIFIER = "$(ExtensionBundleIdentifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "ee586ed5-2bed-44bc-ab45-42f41bfa7316"; + PROVISIONING_PROFILE_SPECIFIER = DevBundle_DevExt; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = LoadDB; + }; + 26305F6E2180763600400DB0 /* LoadDB */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F437803397DA4D6AA4459469 /* Pods-NynjaUnitTests.loaddb.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 9GKQ5AMF2B; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = NynjaUnitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.nynja.mobile.communicator.NynjaUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = LoadDB; + }; + 26305F6F2180763600400DB0 /* LoadDB */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 9GKQ5AMF2B; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = NynjaIntegrationTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.nynja.dev.mobile.communicator.NynjaIntegrationTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Nynja.app/Nynja"; + }; + name = LoadDB; + }; 357809AE1F9765CF00C9680C /* Dev */ = { isa = XCBuildConfiguration; baseConfigurationReference = A169D8E4AB2003F96040DD7A /* Pods-Nynja-Share.dev.xcconfig */; @@ -17898,6 +18245,7 @@ isa = XCConfigurationList; buildConfigurations = ( 357809AE1F9765CF00C9680C /* Dev */, + 26305F6D2180763600400DB0 /* LoadDB */, 5B4DFF6F2191A08E00E89D17 /* Spotify */, F10AFE9E20EF8BBE00C7CE83 /* DevAutoTests */, F1313AFD20888BD300E04092 /* Prerelease */, @@ -17910,6 +18258,7 @@ isa = XCConfigurationList; buildConfigurations = ( 3ABCE8FD1EC9330D00A80B15 /* Dev */, + 26305F6B2180763600400DB0 /* LoadDB */, 5B4DFF6D2191A08E00E89D17 /* Spotify */, F10AFE9C20EF8BBE00C7CE83 /* DevAutoTests */, F1313AFB20888BD300E04092 /* Prerelease */, @@ -17922,6 +18271,7 @@ isa = XCConfigurationList; buildConfigurations = ( 3ABCE9001EC9330D00A80B15 /* Dev */, + 26305F6C2180763600400DB0 /* LoadDB */, 5B4DFF6E2191A08E00E89D17 /* Spotify */, F10AFE9D20EF8BBE00C7CE83 /* DevAutoTests */, F1313AFC20888BD300E04092 /* Prerelease */, @@ -17934,6 +18284,7 @@ isa = XCConfigurationList; buildConfigurations = ( F1C37AB0209A1BF4005EA197 /* Dev */, + 26305F6E2180763600400DB0 /* LoadDB */, 5B4DFF702191A08E00E89D17 /* Spotify */, F10AFE9F20EF8BBE00C7CE83 /* DevAutoTests */, F1C37AB1209A1BF4005EA197 /* Prerelease */, @@ -17946,6 +18297,7 @@ isa = XCConfigurationList; buildConfigurations = ( FE21ACAE2113AA7F006010A0 /* Dev */, + 26305F6F2180763600400DB0 /* LoadDB */, 5B4DFF712191A08E00E89D17 /* Spotify */, FE21ACB02113AA7F006010A0 /* DevAutoTests */, FE21ACB32113AA7F006010A0 /* Prerelease */, diff --git a/Nynja.xcodeproj/xcshareddata/xcschemes/LoadDB.xcscheme b/Nynja.xcodeproj/xcshareddata/xcschemes/LoadDB.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..2243a6445c6258a41d59591dbd0b1595a2ed693a --- /dev/null +++ b/Nynja.xcodeproj/xcshareddata/xcschemes/LoadDB.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Nynja/BadgeNumberService.swift b/Nynja/BadgeNumberService.swift index 1d913c53c4775fa2209fb742ebfbe89a30a09769..f86d18afc3f0d43a54293c74e215acc32d4c5280 100644 --- a/Nynja/BadgeNumberService.swift +++ b/Nynja/BadgeNumberService.swift @@ -6,44 +6,42 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // -class BadgeNumberService: BadgeNumberServiceProtocol, StorageSubscriber { +final class BadgeNumberService: BadgeNumberServiceProtocol, StorageSubscriber { typealias BadgeHandler = (_ badgeNumber: Int64) -> Void + // MARK: - Singleton + static let shared = BadgeNumberService() + // MARK: - Properties - private(set) var badgeNumber: Int64 = 0 + + private var badgeNumber: Int64 = 0 private var counters: [String: Int64] = [:] private var subscribers: [AnyWeakSubscriber] = [] - private let conversationsProvider = ConversationsProvider() + private let conversationsProvider = ServiceFactory().makeConversationsProvider() + // MARK: - Init & deinit + private init() { subscribe() } func initCounters() { - var badgeNumber: Int64 = 0 - - conversationsProvider - .fetchAllConversations() - .forEach { chat in - guard let id = chat.id else { return } - counters[id] = chat.unreadCount - badgeNumber += chat.unreadCount - } - - self.badgeNumber = badgeNumber + self.badgeNumber = conversationsProvider.fetchUnreadMessagesCount() } deinit { unsubscribe() } + // MARK: - Subscription + private func subscribe() { subscribeTypes.forEach { DBObserver.default.register(subscriber: self, type: $0) @@ -54,8 +52,10 @@ class BadgeNumberService: BadgeNumberServiceProtocol, StorageSubscriber { DBObserver.default.unregister(subscriber: self) } + // MARK: - Register subscribers // TODO: sync + func observeBadgeNumber(_ object: AnyObject, notifyImmediately: Bool = true, handler: @escaping BadgeHandler) { let subscriber = AnyWeakSubscriber(object: object, handler: handler) subscribers.append(subscriber) @@ -71,6 +71,7 @@ class BadgeNumberService: BadgeNumberServiceProtocol, StorageSubscriber { func clean() { badgeNumber = 0 + counters = [:] subscribers.forEach { $0.handler(badgeNumber) } } @@ -116,5 +117,4 @@ class BadgeNumberService: BadgeNumberServiceProtocol, StorageSubscriber { subscribers.forEach { $0.handler(badgeNumber) } } - } diff --git a/Nynja/BadgeNumberServiceProtocol.swift b/Nynja/BadgeNumberServiceProtocol.swift index 83255461a28ee10db99c1089ddcedd5e4e4041bf..f7021e3e7c16351117574f5b2eb6a7ab14428396 100644 --- a/Nynja/BadgeNumberServiceProtocol.swift +++ b/Nynja/BadgeNumberServiceProtocol.swift @@ -12,9 +12,6 @@ typealias BadgeHandler = (_ badgeNumber: Int64) -> Void /// Service which provide access to badge number and capability to observe changes protocol BadgeNumberServiceProtocol { - /// Represents badge number which should show in the app icon - var badgeNumber: Int64 { get } - // MARK: - Register subscribers /// Add subscriber which observe changes of 'badgeNumber' property func observeBadgeNumber(_ object: AnyObject, notifyImmediately: Bool, handler: @escaping BadgeHandler) diff --git a/Nynja/ContactDAO.swift b/Nynja/ContactDAO.swift index d7ce86b923554462c8de74ea1d36e22b3e4b7cab..27b611e7731476f6b63779d0c77fa3c2f12ecada 100644 --- a/Nynja/ContactDAO.swift +++ b/Nynja/ContactDAO.swift @@ -15,6 +15,7 @@ import GRDBCipher class ContactDAO: ContactDAOProtocol { + // MARK: - Fetch // MARK: -- Contact static var currentContact: Contact? { @@ -34,120 +35,108 @@ class ContactDAO: ContactDAOProtocol { } } - static func findContactBy(phone: String) -> Contact? { - let phoneIdColumn = Column(ContactTable.Column.phoneId.title) - - guard let contact = dbManager.fetch({ db in - return try DBContact.filter(phoneIdColumn.like("\(phone)%")).fetchOne(db) - }) else { - return nil - } - - return Contact(contact: contact) + static func findPlainContactBy(phone: String) -> Contact? { + return dbManager.fetch { db in + return try DBContact + .filter(Column.phoneId.like("\(phone)%")) + .fetchOne(db) + }?.serverModel } static func findContactBy(phoneId: String) -> Contact? { - guard let dbContact = fetchContact(by: phoneId) else { return nil } - return Contact(contact: dbContact) + return fetchContact(by: phoneId)?.serverModel } - static func findContactBy(username: String) -> Contact? { - let nickColumn = Column(ContactTable.Column.nick.title) - - guard let contact = dbManager.fetch({ db in - return try DBContact.filter(nickColumn == username).fetchOne(db) - }) else { - return nil - } - - return Contact(contact: contact) + static func findPlainContactBy(username: String) -> Contact? { + return dbManager.fetch { db in + return try DBContact + .filter(Column.nick == username) + .fetchOne(db) + }?.serverModel } - static func findContactBy(voxId: String) -> Contact? { - let serviceIdColumn = Column(ServiceTable.Column.id.title) - let serviceTypeColumn = Column(ServiceTable.Column.type.title) - let serviceTargetTypeColumn = Column(ServiceTable.Column.targetType.title) - let contactIdColumn = Column(ContactTable.Column.phoneId.title) - let voxType = "vox" - - let predicate = serviceIdColumn == voxId && - serviceTypeColumn == voxType && - serviceTargetTypeColumn == DBService.TargetType.contact.rawValue - - guard - let service = dbManager.fetch({ db in - return try DBService.filter(predicate).fetchOne(db) - }), let contact = dbManager.fetch({ (db) in - return try DBContact.filter(contactIdColumn == service.targetId).fetchOne(db) - }) else { - return nil - } - - return Contact(contact: contact) - } // MARK: -- Contacts - static func fetchContacts() -> [Contact] { - guard let rosterId = StorageService.sharedInstance.rosterId else { return [] } - - let contacts = dbManager.fetch { db -> [DBContact] in - return try DBContact.contacts(from: db, rosterId: rosterId) + + static func fetchPlainContacts() -> [Contact] { + guard let rosterId = StorageService.sharedInstance.rosterId else { + return [] } - return contacts.map { Contact(contact: $0) } + return dbManager.fetch { db -> [DBContact] in + return try DBContact + .filter(Column.rosterId == rosterId) + .fetchAll(db) + }.serverModels } - static func fetchContactWithoutSelf() -> [Contact] { + static func fetchPlainContactsWithoutSelf() -> [Contact] { var contacts: [Contact] = [] if let phoneId = StorageService.sharedInstance.phoneId { - contacts = fetchContacts(with: [phoneId], isExcluded: true) + contacts = fetchPlainContacts(with: [phoneId], isExcluded: true) } else { - contacts = fetchContacts() + contacts = fetchPlainContacts() } return contacts } - static func fetchContacts(with phoneIds: [String], isExcluded: Bool = false) -> [Contact] { - let contacts = dbManager.fetch { db -> [DBContact] in - let phoneIdColumn = Column(ContactTable.Column.phoneId.title) - - var predicate = phoneIds.contains(phoneIdColumn) + static func fetchPlainContacts(with phoneIds: [String], isExcluded: Bool = false) -> [Contact] { + return dbManager.fetch { db -> [DBContact] in + var predicate = phoneIds.contains(Column.phoneId) if isExcluded { predicate = !predicate } - // TODO: need to think - let contacts = try DBContact.filter(predicate).fetchAll(db) - try contacts.forEach { try $0.construct(db) } - return contacts - } - - return contacts.map { Contact(contact: $0) } + return try DBContact.filter(predicate).fetchAll(db) + }.serverModels } - static func fetchContacts(with statuses: [Contact.Status]) -> [Contact] { + static func fetchPlainContacts(with statuses: [Contact.Status]) -> [Contact] { let statuses = statuses.map { $0.rawValue } - let statusColumn = Column(ContactTable.Column.status.title) - - let contacts = dbManager.fetch { db -> [DBContact] in - // TODO: need to think - let contacts = try DBContact.filter(statuses.contains(statusColumn)).fetchAll(db) - try contacts.forEach { try $0.construct(db) } - return contacts - } + return dbManager.fetch { db -> [DBContact] in + return try DBContact + .filter(statuses.contains(Column.status)) + .fetchAll(db) + }.serverModels + } + + static func fetchContacts(with args: RosterRelatedQueryArgs) -> [Contact] { + return dbManager.fetch { db in + return try args.makeTypedRequest().fetchAllConstructed(db) + }.serverModels + } + + static func fetchPlainContacts( + with args: RosterRelatedQueryArgs, + excludingIds ids: [String], + excludingStatuses statuses: [Contact.Status]?) -> [Contact] { - return contacts.map { Contact(contact: $0) } + return dbManager.fetch { db in + return try args + .makeTypedRequest() + .filter(!ids.contains(Column.phoneId)) + .performIfValueExists(statuses) { $0.filter(!$1.strings.contains(Column.status)) } + .fetchAll(db) + }.serverModels + } + + static func fetchChats(with args: DBContact.RequestArgs) -> [Contact] { + return dbManager.fetch { db in + return try DBContact + .request(with: args) + .fetchAllConstructed(db) + }.serverModels } // MARK: -- Reader static func fetchReader(for phoneId: String, kind: ReaderKind) -> Int64? { let readersString = dbManager.fetch{ db in return try DBContact - .filter(Column(ContactTable.Column.phoneId.title) == phoneId) - .select([Column(ContactTable.Column.reader.title)]) + .filter(Column.phoneId == phoneId) + .select([Column.reader]) .asRequest(of: String.self) .fetchOne(db) } @@ -183,5 +172,4 @@ class ContactDAO: ContactDAOProtocol { try? dbManager.perform(action: .updateColumns([ContactTable.Column.reader.title]), with: contact) } - } diff --git a/Nynja/ContactDAOProtocol.swift b/Nynja/ContactDAOProtocol.swift index f97c190fe12ccf4db05e5a77a3e3a5de6ac89ca7..4543120ad3e3d14144237b091c9480e995f3aa02 100644 --- a/Nynja/ContactDAOProtocol.swift +++ b/Nynja/ContactDAOProtocol.swift @@ -10,28 +10,43 @@ protocol ContactDAOProtocol: DAOProtocol { // MARK: - Fetch // MARK: -- Contact + static var currentContact: Contact? { get } static func fetchContact(by id: String) -> DBContact? static func fetchContact(by rowId: Int64) -> DBContact? + static func findPlainContactBy(phone: String) -> Contact? static func findContactBy(phoneId: String) -> Contact? - static func findContactBy(username: String) -> Contact? - static func findContactBy(voxId: String) -> Contact? + static func findPlainContactBy(username: String) -> Contact? + // MARK: -- Contacts - static func fetchContacts() -> [Contact] - static func fetchContactWithoutSelf() -> [Contact] - static func fetchContacts(with phoneIds: [String], isExcluded: Bool) -> [Contact] - static func fetchContacts(with statuses: [Contact.Status]) -> [Contact] + + static func fetchPlainContacts() -> [Contact] + static func fetchPlainContactsWithoutSelf() -> [Contact] + static func fetchPlainContacts(with phoneIds: [String], isExcluded: Bool) -> [Contact] + static func fetchPlainContacts(with statuses: [Contact.Status]) -> [Contact] + + static func fetchContacts(with args: RosterRelatedQueryArgs) -> [Contact] + static func fetchPlainContacts(with args: RosterRelatedQueryArgs, + excludingIds ids: [String], + excludingStatuses statuses: [Contact.Status]?) -> [Contact] + + static func fetchChats(with args: DBContact.RequestArgs) -> [Contact] + // MARK: -- Reader + static func fetchReader(for phoneId: String, kind: ReaderKind) -> Int64? + // MARK: - Update + static func updateColumns(_ columns: Set, contact: Contact) + // MARK: -- Fields - static func updateReader(_ reader: Int64, phoneId: String, kind: ReaderKind) + static func updateReader(_ reader: Int64, phoneId: String, kind: ReaderKind) } diff --git a/Nynja/ContactsProvider.swift b/Nynja/ContactsProvider.swift index 84ffbbafda5cbd134ccb5b1bd8aedf47e1177b9c..16c6c5f0ea59ef17eb27500a3410eeeb65ad209a 100644 --- a/Nynja/ContactsProvider.swift +++ b/Nynja/ContactsProvider.swift @@ -6,36 +6,36 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // -class ContactsProvider: ContactsProviding { +import GRDBCipher + +final class ContactsProvider: ContactsProviding { + typealias FetchingArgs = ContactsProvidingFetchingArgs - func fetchHistory() -> [Contact] { - return ContactDAO - .fetchContactWithoutSelf() - .sorted { - $0.create > $1.create - } + private let orderColumns = [Column.created.desc] + + func fetchHistory(with args: FetchingArgs) -> [Contact] { + let daoArgs = makeRosterRelatedQueryArgs(from: args) + return ContactDAO.fetchPlainContacts(with: daoArgs, + excludingIds: [args.phoneId], + excludingStatuses: args.statuses) } - func fetchHistory(without statuses: [Contact.Status]) -> [Contact] { - return fetchHistory().filter { contact in - if let status = contact.originalStatus { - return !statuses.contains(status) - } - - return true - } + private func makeRosterRelatedQueryArgs(from args: FetchingArgs) -> RosterRelatedQueryArgs { + return RosterRelatedQueryArgs( + rosterId: args.rosterId, + args: .init(limit: args.limit, + orderingTerms: orderColumns)) } func fetchFriends() -> [Contact] { return ContactDAO - .fetchContacts(with: [.friend, .banned, .ban]) + .fetchPlainContacts(with: [.friend, .banned, .ban]) .withoutSelf } func fetchFriendsWithoutBlocked() -> [Contact] { return ContactDAO - .fetchContacts(with: [.friend]) + .fetchPlainContacts(with: [.friend]) .withoutSelf } - } diff --git a/Nynja/ContactsProviding.swift b/Nynja/ContactsProviding.swift index 5fedf5cc2bb2434417d8b0abc7b140bee1eec18e..2913cd0f61158ee4a20017dab51e9a79ee48240a 100644 --- a/Nynja/ContactsProviding.swift +++ b/Nynja/ContactsProviding.swift @@ -8,10 +8,8 @@ protocol ContactsProviding { - func fetchHistory() -> [Contact] - func fetchHistory(without statuses: [Contact.Status]) -> [Contact] + func fetchHistory(with args: ContactsProvidingFetchingArgs) -> [Contact] func fetchFriends() -> [Contact] func fetchFriendsWithoutBlocked() -> [Contact] - } diff --git a/Nynja/ContactsProvidingFetchingArgs.swift b/Nynja/ContactsProvidingFetchingArgs.swift new file mode 100644 index 0000000000000000000000000000000000000000..3e49f1db59cdd0f33a9b83bc6d336b0f17dba536 --- /dev/null +++ b/Nynja/ContactsProvidingFetchingArgs.swift @@ -0,0 +1,25 @@ +// +// ContactsProvidingFetchingArgs.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/6/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + + +struct ContactsProvidingFetchingArgs { + let rosterId: Int64 + let phoneId: String + let statuses: [Contact.Status]? + let limit: Int? + + init(rosterId: Int64, + phoneId: String, + statuses: [Contact.Status]? = nil, + limit: Int? = nil) { + self.rosterId = rosterId + self.phoneId = phoneId + self.statuses = statuses + self.limit = limit + } +} diff --git a/Nynja/ConversationsProvider.swift b/Nynja/ConversationsProvider.swift index c7b497524e1a497f29ca4a9fb27e7d2265199551..f5d011edfcf0a3f7988d9c86873ac737e5206ba7 100644 --- a/Nynja/ConversationsProvider.swift +++ b/Nynja/ConversationsProvider.swift @@ -6,67 +6,103 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // -class ConversationsProvider: ConversationsProviding { +import GRDBCipher + +class ConversationsProvider: ConversationsProviding, InitializeInjectable { + + private let dbManager: DBManagerProtocol + + required init(dependencies: Dependencies) { + self.dbManager = dependencies.dbManager + } // MARK: - Chats - func fetchChats() -> [Contact] { - return ContactDAO - .fetchContacts(with: [.friend, .banned, .ban]) - .sorted(by: comparator) + func fetchChats(with args: FetchingArgs) -> [Contact] { + return ContactDAO.fetchChats(with: args) } // MARK: - Groups - func fetchGroups() -> [Room] { - return RoomDAO - .fetchRooms(kind: .group) - .sorted(by: comparator) + func fetchGroups(with args: FetchingArgs) -> [Room] { + let groupRequestArgs = makeGroupsRequestArgs(from: args, kind: .group) + return RoomDAO.fetchPlainRooms(with: groupRequestArgs) } // MARK: - Channels - func fetchChannels() -> [Room] { - return RoomDAO - .fetchRooms(kind: .channel) - .sorted(by: comparator) + func fetchChannels(with args: ConversationsProviding.FetchingArgs) -> [Room] { + let channelRequestArgs = makeGroupsRequestArgs(from: args, kind: .channel) + return RoomDAO.fetchPlainRooms(with: channelRequestArgs) } - func fetchMyChannels() -> [Room] { - guard let phoneId = StorageService.sharedInstance.phoneId else { - return [] - } - - return RoomDAO - .fetchUserRooms(with: phoneId, isAdmin: true, kind: .channel) - .sorted(by: comparator) + func fetchMyChannels(with args: ConversationsProviding.FetchingArgs, ownerId: String) -> [Room] { + let channelRequestArgs = makeGroupsRequestArgs(from: args, kind: .channel, ownerId: ownerId) + return RoomDAO.fetchPlainRooms(with: channelRequestArgs) + } + + private func makeGroupsRequestArgs(from args: FetchingArgs, kind: Room.Kind, ownerId: String? = nil) -> DBRoom.RequestArgs { + return .init( + rosterId: args.rosterId, + type: kind.rawValue, + onlyUnread: args.onlyUnread, + ownerId: ownerId, + limit: args.limit, + offset: args.offset) + } + + func comparator(lhs: ChatModel, rhs: ChatModel) -> Bool { + let created1 = lhs.last_msg?.created ?? 0 + let created2 = rhs.last_msg?.created ?? 0 + return created1 > created2 } // MARK: - All - func fetchAllConversations() -> [ChatModel] { - var chatModels: [ChatModel] = [] + func fetchUnreadMessagesCount() -> Int64 { + return dbManager.fetch { db in + return try makeUnreadCountRequest().fetchOne(db) + } ?? 0 + } + + private func makeUnreadCountRequest() -> AnyTypedRequest { + let unreadAlias = "unread" - let contacts = ContactDAO.fetchContactWithoutSelf() as [ChatModel] - chatModels.append(contentsOf: contacts) + let contactSql = makeUnreadCountSQL(for: ContactTable.name, unreadAlias: unreadAlias) + let roomSql = makeUnreadCountSQL(for: RoomTable.name, unreadAlias: unreadAlias) - let rooms = RoomDAO.fetchRooms() as [ChatModel] - chatModels.append(contentsOf: rooms) + let sql = """ + select sum(\(unreadAlias)) + from + (\(contactSql) + union + \(roomSql)) + """ - return chatModels + return SQLRequest(sql).asRequest(of: Int64.self) } - - // MARK: - Comparator - - func comparator(lhs: ChatModel, rhs: ChatModel) -> Bool { - let created1 = lhs.last_msg?.created ?? 0 - let created2 = rhs.last_msg?.created ?? 0 - return created1 > created2 + private func makeUnreadCountSQL(for tableName: String, unreadAlias: String) -> String { + let unreadColumn = "\(tableName).\(Column.unread)" + + return """ + select sum(\(unreadColumn)) as '\(unreadAlias)' + from \(tableName) + where \(unreadColumn) > 0 + """ } +} + + +// MARK: - InitInitializable + +extension ConversationsProvider { + struct Dependencies { + let dbManager: DBManagerProtocol + } } diff --git a/Nynja/ConversationsProviding.swift b/Nynja/ConversationsProviding.swift index a4f130a74206ec55c8fc50c2a4ef08dedc938c4d..10bf1bb955f721ec0ae074d7df4fb179e8d90357 100644 --- a/Nynja/ConversationsProviding.swift +++ b/Nynja/ConversationsProviding.swift @@ -6,15 +6,18 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // + protocol ConversationsProviding { + typealias FetchingArgs = DBContact.RequestArgs + + func fetchChats(with args: FetchingArgs) -> [Contact] - func fetchChats() -> [Contact] - func fetchGroups() -> [Room] - - func fetchChannels() -> [Room] - func fetchMyChannels() -> [Room] + func fetchGroups(with args: FetchingArgs) -> [Room] - func fetchAllConversations() -> [ChatModel] + func fetchChannels(with args: FetchingArgs) -> [Room] + func fetchMyChannels(with args: FetchingArgs, ownerId: String) -> [Room] func comparator(lhs: ChatModel, rhs: ChatModel) -> Bool + + func fetchUnreadMessagesCount() -> Int64 } diff --git a/Nynja/DB/DAO.swift b/Nynja/DB/DAO.swift new file mode 100644 index 0000000000000000000000000000000000000000..d9b7fe91c02a8a6f018262f7a7b6bdee4fb6d75a --- /dev/null +++ b/Nynja/DB/DAO.swift @@ -0,0 +1,18 @@ +// +// DAO.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/13/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + + +class DAO { + let dbManager = StorageService.sharedInstance + + func fetch(with maker: U, kind: DBModelFetchingKind = .constructed) -> [T] where U.Model == T { + return dbManager.fetch { db in + return try maker.makeTypedRequest().fetchAll(db, kind: kind) + } + } +} diff --git a/Nynja/DB/Extensions/Array+Table.swift b/Nynja/DB/Extensions/Array+Table.swift index c85191d9d0d10aabcfffc3da4fac7a539755637d..1cd7aa1ad1e9f3583ef47c2a6a385a6e745300de 100644 --- a/Nynja/DB/Extensions/Array+Table.swift +++ b/Nynja/DB/Extensions/Array+Table.swift @@ -11,5 +11,4 @@ extension Array where Element == Table.Type { var names: [String] { return self.map { $0.name } } - } diff --git a/Nynja/DB/Extensions/ColumnDefinitionExtension.swift b/Nynja/DB/Extensions/ColumnDefinitionExtension.swift new file mode 100644 index 0000000000000000000000000000000000000000..6d6ce23996f2ea4230659d8235afef9445a2142f --- /dev/null +++ b/Nynja/DB/Extensions/ColumnDefinitionExtension.swift @@ -0,0 +1,22 @@ +// +// ColumnDefinitionExtension.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +extension ColumnDefinition { + + @discardableResult + func references(_ table: String, column: Column, onDelete deleteAction: Database.ForeignKeyAction? = nil, onUpdate updateAction: Database.ForeignKeyAction? = nil, deferred: Bool = false) -> ColumnDefinition { + return self.references( + table, + column: column.name, + onDelete: deleteAction, + onUpdate: updateAction, + deferred: deferred) + } +} diff --git a/Nynja/DB/Extensions/ColumnExtension.swift b/Nynja/DB/Extensions/ColumnExtension.swift new file mode 100644 index 0000000000000000000000000000000000000000..298d228552adb4ea0cf61ba321bcc44585682df9 --- /dev/null +++ b/Nynja/DB/Extensions/ColumnExtension.swift @@ -0,0 +1,16 @@ +// +// ColumnExtension.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +extension Column: CustomStringConvertible { + + public var description: String { + return name + } +} diff --git a/Nynja/DB/Extensions/QueryInterfaceRequestExtension.swift b/Nynja/DB/Extensions/QueryInterfaceRequestExtension.swift new file mode 100644 index 0000000000000000000000000000000000000000..65f82c70765092fbb6dd4dd9128aee3a1a33aeb0 --- /dev/null +++ b/Nynja/DB/Extensions/QueryInterfaceRequestExtension.swift @@ -0,0 +1,23 @@ +// +// QueryInterfaceRequestExtension.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +extension QueryInterfaceRequest { + + func performIfValueExists( + _ value: V?, + closure: (QueryInterfaceRequest, V) -> QueryInterfaceRequest) -> QueryInterfaceRequest { + + guard let value = value else { + return self + } + + return closure(self, value) + } +} diff --git a/Nynja/DB/Extensions/TableDefinitionExtension.swift b/Nynja/DB/Extensions/TableDefinitionExtension.swift index 7a82d62550fff1c9465cfab317917eec6cad35dd..9fc91a0bae67a02847c64ef7c7f266a99dfdd882 100644 --- a/Nynja/DB/Extensions/TableDefinitionExtension.swift +++ b/Nynja/DB/Extensions/TableDefinitionExtension.swift @@ -10,8 +10,14 @@ import GRDBCipher extension TableDefinition { + @available(*, deprecated, message: "Use `func column(_ column: Column, _ type: Database.ColumnType? = nil) -> ColumnDefinition` instead") @discardableResult func column(_ desc: Describable, _ type: Database.ColumnType? = nil) -> ColumnDefinition { return column(desc.title, type) } + + @discardableResult + func column(_ column: Column, _ type: Database.ColumnType? = nil) -> ColumnDefinition { + return self.column(column.name, type) + } } diff --git a/Nynja/DB/Extensions/TransactionObserverExtension.swift b/Nynja/DB/Extensions/TransactionObserverExtension.swift index 56355cff3a48d5371afb9e40fef091bb426e5211..8fb5bf20d5198b0b93c00f0d9e497388ca22a001 100644 --- a/Nynja/DB/Extensions/TransactionObserverExtension.swift +++ b/Nynja/DB/Extensions/TransactionObserverExtension.swift @@ -13,5 +13,4 @@ extension TransactionObserver { func databaseWillCommit() throws {} func databaseDidCommit(_ db: Database) {} func databaseDidRollback(_ db: Database) {} - } diff --git a/Nynja/DB/Extensions/TypedRequestExtension.swift b/Nynja/DB/Extensions/TypedRequestExtension.swift new file mode 100644 index 0000000000000000000000000000000000000000..8f527dc788b4173df4f0fda09c68cadc59308cc9 --- /dev/null +++ b/Nynja/DB/Extensions/TypedRequestExtension.swift @@ -0,0 +1,41 @@ +// +// TypedRequestExtension.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +enum DBModelFetchingKind { + case plain + case constructed +} + +extension TypedRequest where RowDecoder: DBModel { + + func fetchAllConstructed(_ db: Database) throws -> [RowDecoder] { + return try fetchAll(db, kind: .constructed) + } + + func fetchOneConstructed(_ db: Database) throws -> RowDecoder? { + return try fetchOne(db, kind: .constructed) + } + + func fetchAll(_ db: Database, kind: DBModelFetchingKind) throws -> [RowDecoder] { + let models = try self.fetchAll(db) + if kind == .constructed { + try models.construct(db) + } + return models + } + + func fetchOne(_ db: Database, kind: DBModelFetchingKind) throws -> RowDecoder? { + let model = try self.fetchOne(db) + if kind == .constructed { + try model?.construct(db) + } + return model + } +} diff --git a/Nynja/DB/Models/Base/DBExtendedModel.swift b/Nynja/DB/Models/Base/DBExtendedModel.swift new file mode 100644 index 0000000000000000000000000000000000000000..a07fd4c4872a4c2456d59f720cd0c14aba8ddb1b --- /dev/null +++ b/Nynja/DB/Models/Base/DBExtendedModel.swift @@ -0,0 +1,11 @@ +// +// DBExtendedModel.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +protocol DBExtendedModel: DBModel, ServerModelConvertible { + +} diff --git a/Nynja/DB/Models/Base/DBModelProtocol.swift b/Nynja/DB/Models/Base/DBModel.swift similarity index 60% rename from Nynja/DB/Models/Base/DBModelProtocol.swift rename to Nynja/DB/Models/Base/DBModel.swift index 10f019eb5fd79cc45bd5f3cb55740eb051727edf..c6dabaf5939f79ba77e108008031b367d747d6aa 100644 --- a/Nynja/DB/Models/Base/DBModelProtocol.swift +++ b/Nynja/DB/Models/Base/DBModel.swift @@ -1,5 +1,5 @@ // -// DBModelProtocol.swift +// DBModel.swift // Nynja // // Created by Volodymyr Hryhoriev on 11/28/17. @@ -8,15 +8,17 @@ import GRDBCipher -protocol DBModelProtocol: Persistable, RowConvertible { +protocol DBModel: Persistable, RowConvertible { func saveAggregate(_ db: Database) throws @discardableResult func deleteAggregate(_ db: Database) throws -> Bool + + func construct(_ db: Database) throws } -extension DBModelProtocol { +extension DBModel { func saveAggregate(_ db: Database) throws { try save(db) @@ -27,4 +29,13 @@ extension DBModelProtocol { try delete(db) return false } + + func construct(_ db: Database) throws {} +} + +extension Array where Element: DBModel { + + func construct(_ db: Database) throws { + try forEach { try $0.construct(db) } + } } diff --git a/Nynja/DB/Models/Base/FeedProtocol.swift b/Nynja/DB/Models/Base/FeedProtocol.swift index fd843bbac83292306201f969618c2663eaed4219..bd113fc650aa75eae59d22982af4106b5638534e 100644 --- a/Nynja/DB/Models/Base/FeedProtocol.swift +++ b/Nynja/DB/Models/Base/FeedProtocol.swift @@ -8,7 +8,7 @@ import GRDBCipher -protocol FeedProtocol: DBModelProtocol { +protocol FeedProtocol: DBModel { var id: Int64? { get set } var type: FeedType { get } diff --git a/Nynja/DB/Models/DBChatCheckpoint.swift b/Nynja/DB/Models/DBChatCheckpoint.swift index a43295c0477f4e1a1f1e42b4c202b26896bb92a6..33086746192fc7ca253810ea24959c1833c743f7 100644 --- a/Nynja/DB/Models/DBChatCheckpoint.swift +++ b/Nynja/DB/Models/DBChatCheckpoint.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBChatCheckpoint : Record, DBModelProtocol { +final class DBChatCheckpoint : Record, DBModel { var feedId: Int64 var feedType: Int @@ -49,7 +49,7 @@ class DBChatCheckpoint : Record, DBModelProtocol { container[ChatCheckpointTable.Column.topOffset.title] = topOffset } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { try self.save(db) } diff --git a/Nynja/DB/Models/DBContact.swift b/Nynja/DB/Models/DBContact.swift index f58a43005a16b7f6e8d3100fc83cd460a3bf0be5..9dc20c5a2d0c6ada403712993870d98a55d54439 100644 --- a/Nynja/DB/Models/DBContact.swift +++ b/Nynja/DB/Models/DBContact.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBContact: Record, DBModelProtocol { +final class DBContact: Record, DBExtendedModel { var phoneId: String var avatar: String? @@ -25,10 +25,18 @@ class DBContact: Record, DBModelProtocol { var messageId: String? var rosterId: Int64? - var message: DBMessage? + var message: DBMessage? { + didSet { + messageId = message?.localId + } + } var features: [DBFeature] = [] var services: [DBService] = [] + var serverModel: Contact { + return Contact(contact: self) + } + init?(contact: Contact, rosterId: Int64?) { guard let phoneId = contact.phone_id else { return nil } @@ -46,7 +54,7 @@ class DBContact: Record, DBModelProtocol { if let message = contact.message { self.message = DBMessage(message: message) - self.messageId = message.msg_id + self.messageId = self.message?.localId } else { self.messageId = contact.lastMessageId } @@ -130,11 +138,6 @@ class DBContact: Record, DBModelProtocol { // MARK: - Modification func saveAggregate(_ db: Database) throws { try message?.saveAggregate(db) - - if message != nil || messageId == nil { - messageId = message?.localId - } - try save(db) try features.forEach { try $0.save(db) } @@ -143,13 +146,13 @@ class DBContact: Record, DBModelProtocol { @discardableResult func deleteAggregate(_ db: Database) throws -> Bool { - try DBContact.request(targetId: self.phoneId).deleteAll(db) - - try DBService.request(targetId: self.phoneId, targetType: .contact).deleteAll(db) + try DBFeature.deleteAll(db, targetId: phoneId, targetType: .contact) + try DBService.deleteAll(db, targetId: phoneId, targetType: .contact) if let phoneId = StorageService.sharedInstance.phoneId { - try DBP2p.delete(db, firstId: self.phoneId, secondId: phoneId) + try DBP2p.delete(db, firstId: phoneId, secondId: phoneId) } + return try self.delete(db) } @@ -179,11 +182,6 @@ class DBContact: Record, DBModelProtocol { return try contacts(db, predicate: predicate) } - static func contacts(_ db: Database, ids: [String]) throws -> [DBContact] { - let phoneIdColumn = Column(ContactTable.Column.phoneId.title) - return try contacts(db, predicate: ids.contains(phoneIdColumn)) - } - private static func contacts(_ db: Database, predicate: SQLExpressible) throws -> [DBContact] { let contacts = try DBContact.filter(predicate).fetchAll(db) try contacts.forEach { try $0.construct(db) } @@ -195,17 +193,70 @@ class DBContact: Record, DBModelProtocol { message = try DBMessage.message(db, localId: messageId) } - features = (try? DBContact.request(targetId: self.phoneId).fetchAll(db)) ?? [] - services = try DBService.request(targetId: self.phoneId, targetType: .contact).fetchAll(db) + features = (try? DBFeature.request(targetId: phoneId, targetType: .contact).fetchAll(db)) ?? [] + services = try DBService.request(targetId: phoneId, targetType: .contact).fetchAll(db) } // MARK: - Request - static private func request(targetId: String) -> QueryInterfaceRequest { - return DBFeature.request(targetId: targetId, targetType: DBFeature.TargetType.contact) - } static func request(phoneId: String) -> QueryInterfaceRequest { return DBContact.filter(Column(ContactTable.Column.phoneId.title) == phoneId) } + + static func request(with args: RequestArgs) -> AnyTypedRequest { + let contactTable = ContactTable.name + let messageTable = MessageTable.name + + let messageIdColumn = "\(contactTable).\(Column.messageId)" + let localIdColumn = "\(messageTable).\(Column.localId)" + + let rosterIdColumn = "\(contactTable).\(Column.rosterId)" + let unreadColumn = "\(contactTable).\(Column.unread)" + let statusColumn = "\(contactTable).\(Column.status)" + + let createdColumn = "\(messageTable).\(Column.created)" + + let unreadCondition = args.onlyUnread ? "and \(unreadColumn) > 0" : "" + + var sql = """ + select \(contactTable).* + from \(contactTable) left join \(messageTable) + on \(messageIdColumn) == \(localIdColumn) + where \(rosterIdColumn) == \(args.rosterId) + \(unreadCondition) + and \(statusColumn) in ('friend', 'ban', 'banned') + order by \(createdColumn) desc + """ + + if let limit = args.limit { + sql.append(" limit \(limit)") + } + + if let offset = args.offset { + sql.append(" offset \(offset)") + } + + return SQLRequest(sql).asRequest(of: DBContact.self) + } } + +extension DBContact { + + struct RequestArgs { + let rosterId: Int64 + let onlyUnread: Bool + let limit: Int? + let offset: Int? + + public init(rosterId: Int64, + onlyUnread: Bool = false, + limit: Int? = nil, + offset: Int? = nil) { + self.rosterId = rosterId + self.onlyUnread = onlyUnread + self.limit = limit + self.offset = offset + } + } +} diff --git a/Nynja/DB/Models/DBConvertMessage.swift b/Nynja/DB/Models/DBConvertMessage.swift index e64ac6c909a0ef1e57d7802b8463e120a443d45b..b68e1d05fe86d90cb57b6813989d7af128cde81e 100644 --- a/Nynja/DB/Models/DBConvertMessage.swift +++ b/Nynja/DB/Models/DBConvertMessage.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBConvertMessage: Record, DBModelProtocol { +final class DBConvertMessage: Record, DBModel { var messageId: String var type: Int @@ -75,7 +75,7 @@ class DBConvertMessage: Record, DBModelProtocol { } - //MARK: - DBModelProtocol + //MARK: - DBModel func saveAggregate(_ db: Database) throws { try self.save(db) } diff --git a/Nynja/DB/Models/DBDesc.swift b/Nynja/DB/Models/DBDesc.swift index 3871fba2bb6630150ce1481e3c5d142912c7028b..eb003f7b14363a5e2f3f456dae651d07d0694b23 100644 --- a/Nynja/DB/Models/DBDesc.swift +++ b/Nynja/DB/Models/DBDesc.swift @@ -8,7 +8,7 @@ import GRDBCipher -final class DBDesc: Record, DBModelProtocol { +final class DBDesc: Record, DBModel { let serverId: String let mime: String @@ -106,7 +106,7 @@ final class DBDesc: Record, DBModelProtocol { private func deleteFeatures(_ db: Database) throws { let featureTarget = DBDesc.featureTarget(for: targetType) - try DBFeature.request(targetId: serverId, targetType: featureTarget).deleteAll(db) + try DBFeature.deleteAll(db, targetId: serverId, targetType: featureTarget) } static func deleteAll(_ db: Database, targetId: String, targetType: TargetType) throws { diff --git a/Nynja/DB/Models/DBFeature.swift b/Nynja/DB/Models/DBFeature.swift index 90116c1c8852a17904badb7ed25c927641475320..260150295d568d339661debc276d77b59d42689f 100644 --- a/Nynja/DB/Models/DBFeature.swift +++ b/Nynja/DB/Models/DBFeature.swift @@ -30,10 +30,7 @@ final class DBFeature: Codable { } static func deleteAll(_ db: Database, targetId: String, targetType: TargetType) throws { - let targetIdColumn = Column(FeatureTable.Column.targetId.title) - let targetTypeColumn = Column(FeatureTable.Column.targetType.title) - - try DBFeature.filter(targetIdColumn == targetId && targetTypeColumn == targetType.rawValue).deleteAll(db) + try request(targetId: targetId, targetType: targetType).deleteAll(db) } } diff --git a/Nynja/DB/Models/DBJob.swift b/Nynja/DB/Models/DBJob.swift index 80586f4a47a6f4b7acfcbed228a12d5188745186..199ef98d4ab1cad76c1cf888ea602c454175c688 100644 --- a/Nynja/DB/Models/DBJob.swift +++ b/Nynja/DB/Models/DBJob.swift @@ -9,7 +9,7 @@ import Foundation import GRDBCipher -class DBJob: Record, DBModelProtocol { +final class DBJob: Record, DBExtendedModel { enum JobType: Int { case schedule = 0 @@ -28,8 +28,13 @@ class DBJob: Record, DBModelProtocol { var features : [DBFeature] = [] var type: JobType = .schedule + var serverModel: Job { + return Job(job: self) + } + // MARK: - Mapping + init?(job: Job) { super.init() @@ -47,15 +52,15 @@ class DBJob: Record, DBModelProtocol { } required init(row: Row) { - self.id = row[JobTable.Column.id.title] - self.serverId = row[JobTable.Column.serverId.title] - self.container = row[JobTable.Column.container.title] - self.feedId = row[JobTable.Column.feedId.title] - self.prev = row[JobTable.Column.prev.title] - self.next = row[JobTable.Column.next.title] - self.time = row[JobTable.Column.time.title] - self.status = row[JobTable.Column.status.title] - let jobType: Int? = row[JobTable.Column.type.title] + self.id = row[Column.id] + self.serverId = row[Column.serverId] + self.container = row[Column.container] + self.feedId = row[Column.feedId] + self.prev = row[Column.prev] + self.next = row[Column.next] + self.time = row[Column.time] + self.status = row[Column.status] + let jobType: Int? = row[Column.type] if let jobType = jobType, let type = JobType(rawValue: jobType) { self.type = type } @@ -68,15 +73,15 @@ class DBJob: Record, DBModelProtocol { } override func encode(to container: inout PersistenceContainer) { - container[JobTable.Column.id.title] = self.id - container[JobTable.Column.serverId.title] = self.serverId - container[JobTable.Column.container.title] = self.container - container[JobTable.Column.feedId.title] = self.feedId - container[JobTable.Column.prev.title] = self.prev - container[JobTable.Column.next.title] = self.next - container[JobTable.Column.time.title] = self.time - container[JobTable.Column.status.title] = self.status - container[JobTable.Column.type.title] = self.type.rawValue + container[Column.id] = self.id + container[Column.serverId] = self.serverId + container[Column.container] = self.container + container[Column.feedId] = self.feedId + container[Column.prev] = self.prev + container[Column.next] = self.next + container[Column.time] = self.time + container[Column.status] = self.status + container[Column.type] = self.type.rawValue } override func didInsert(with rowID: Int64, for column: String?) { @@ -85,26 +90,21 @@ class DBJob: Record, DBModelProtocol { // MARK: - Fetch static func job(from db: Database, rowId: Int64) throws -> DBJob? { - let job = try DBJob.filter(Column.rowID == rowId).fetchOne(db) - try job?.construct(db) - return job + return try DBJob.filter(Column.rowID == rowId).fetchOneConstructed(db) } static func job(_ db: Database, serverId: Int64) throws -> DBJob? { - let serverIdColumn = Column(JobTable.Column.serverId.title) - let job = try DBJob.filter(serverIdColumn == serverId).fetchOne(db) - try job?.construct(db) - return job + return try DBJob.filter(Column.serverId == serverId).fetchOneConstructed(db) } static func jobs(_ db: Database, filter: SQLExpressible? = nil) throws -> [DBJob] { - let jobs = try (filter == nil ? DBJob.fetchAll(db) : DBJob.filter(filter!).fetchAll(db)) - try jobs.forEach { try $0.construct(db) } - return jobs + return try (filter == nil ? + DBJob.all().fetchAllConstructed(db) : // TODO: need to think + DBJob.filter(filter!).fetchAllConstructed(db)) } static func jobs(_ db: Database, type: JobType) throws -> [DBJob] { - return try jobs(db, filter: Column(JobTable.Column.type.title) == type.rawValue) + return try jobs(db, filter: Column.type == type.rawValue) } static func jobs(_ db: Database, messageLocalId: String) throws -> [DBJob] { @@ -112,10 +112,10 @@ class DBJob: Record, DBModelProtocol { return try SQLRequest(sql).asRequest(of: DBJob.self).fetchAll(db) } - private func construct(_ db: Database) throws { + func construct(_ db: Database) throws { if let jobId = self.id { self.messages = try DBJobMessage.messages(db, jobId: jobId) - self.features = try DBJob.requestFeature(jobId: String(describing: jobId)).fetchAll(db) + self.features = try DBFeature.request(targetId: "\(jobId)", targetType: .job).fetchAll(db) } } @@ -152,7 +152,7 @@ class DBJob: Record, DBModelProtocol { guard let jobId = tempId else { return false } self.id = jobId - try DBJob.requestFeature(jobId: String(describing: jobId)).deleteAll(db) + try DBFeature.deleteAll(db, targetId: "\(jobId)", targetType: .job) try deleteMessages(db, jobId: jobId) return try self.delete(db) @@ -160,11 +160,12 @@ class DBJob: Record, DBModelProtocol { // MARK: - Private private func fetchId(_ db: Database) throws -> Int64? { - let idColumn = Column(JobTable.Column.id.title) - let serverIdColumn = Column(JobTable.Column.serverId.title) - - let predicate = (serverId != nil && serverIdColumn == self.serverId) - return try DBJob.filter(predicate).select(idColumn).asRequest(of: Int64.self).fetchOne(db) + let predicate = (serverId != nil && Column.serverId == serverId) + return try DBJob + .filter(predicate) + .select(Column.id) + .asRequest(of: Int64.self) + .fetchOne(db) } private func deleteMessages(_ db: Database, jobId: Int64) throws { @@ -173,22 +174,19 @@ class DBJob: Record, DBModelProtocol { } // MARK: - Make Requests - static func requestFeature(jobId: String) -> QueryInterfaceRequest { - return DBFeature.request(targetId: jobId, targetType: .job) - } static func request(jobId: Int64) -> QueryInterfaceRequest { - return DBJob.filter(Column(JobTable.Column.id.title) == jobId) + return DBJob.filter(Column.id == jobId) } private static func sqlJobs(for messageLocalId: String, type: JobType = .schedule) -> String { let jobTable = JobTable.name - let jobType = "\(jobTable).\(JobTable.Column.type.title)" - let jobId = "\(jobTable).\(JobTable.Column.id.title)" + let jobType = "\(jobTable).\(Column.type)" + let jobId = "\(jobTable).\(Column.id)" let jobMessageTable = JobMessageTable.name - let jodMessageJobId = "\(jobMessageTable).\(JobMessageTable.Column.jobId.title)" - let jobMessageLocalId = "\(jobMessageTable).\(JobMessageTable.Column.localId.title)" + let jodMessageJobId = "\(jobMessageTable).\(Column.jobId)" + let jobMessageLocalId = "\(jobMessageTable).\(Column.localId)" let sql = """ select \(jobTable).* @@ -199,5 +197,19 @@ class DBJob: Record, DBModelProtocol { return sql } +} + +extension DBJob { + + struct QueryArgs: CompositeQueryArgs { + let type: DBJob.JobType + let args: AnyQueryArgs + + func makeTypedRequest() -> QueryInterfaceRequest { + return AnyQueryArgs(args: args) + .filter { $0.filter(Column.type == self.type.rawValue) } + .makeTypedRequest() + } + } } diff --git a/Nynja/DB/Models/DBJobMessage.swift b/Nynja/DB/Models/DBJobMessage.swift index 705505d3130f0225fd88605808f4516fb366435f..fd146f3c074c922db3ad2a2018f5698a2e19eafb 100644 --- a/Nynja/DB/Models/DBJobMessage.swift +++ b/Nynja/DB/Models/DBJobMessage.swift @@ -9,7 +9,7 @@ import Foundation import GRDBCipher -final class DBJobMessage: Record, DBModelProtocol { +final class DBJobMessage: Record, DBModel { var id: Int64? var container: String? @@ -119,7 +119,7 @@ final class DBJobMessage: Record, DBModelProtocol { return messages } - private func construct(_ db: Database) throws { + func construct(_ db: Database) throws { if let id = self.id, case let targetId = String(id) { self.files = try DBDesc.descs(targetId: targetId, targetType: .job, db: db) } diff --git a/Nynja/DB/Models/DBLink.swift b/Nynja/DB/Models/DBLink.swift index a10c2009f1baf9e1685eaf6e711819d4f8aae331..2df604df64a5c34389f911f68f891aeba4c24d75 100644 --- a/Nynja/DB/Models/DBLink.swift +++ b/Nynja/DB/Models/DBLink.swift @@ -52,7 +52,7 @@ final class DBLink: Codable { } -extension DBLink: DBModelProtocol { +extension DBLink: DBModel { static var databaseTableName: String { return LinkTable.name diff --git a/Nynja/DB/Models/DBMember.swift b/Nynja/DB/Models/DBMember.swift index 2b456cbcb55bab7d3f707ed44e840a73af12b98c..abbba718122601b1a10ed3753d33c4c18f719c9f 100644 --- a/Nynja/DB/Models/DBMember.swift +++ b/Nynja/DB/Models/DBMember.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBMember: Record, DBModelProtocol { +final class DBMember: Record, DBModel { var id: Int64 var container: String? @@ -145,15 +145,6 @@ class DBMember: Record, DBModelProtocol { try member.construct(db) return member } - - static func all(from db: Database) throws -> [DBMember] { - let members = try DBMember.fetchAll(db) - try members.forEach { - try $0.construct(db) - } - - return members - } static func member(from db: Database, id: Int64) throws -> DBMember? { guard let member = try DBMember.fetchOne(db, key: id) else { @@ -164,21 +155,21 @@ class DBMember: Record, DBModelProtocol { return member } + static func member(from db: Database, roomId: String, phoneId: String) throws -> DBMember? { + return try requestMember(roomId: roomId, phoneIds: [phoneId]).fetchOneConstructed(db) + } + static func members(from db: Database, roomId: String, isAdmin: Bool = false) throws -> [DBMember] { - let members = try requestMember(roomId: roomId, isAdmin: isAdmin).fetchAll(db) - try members.forEach { try $0.construct(db) } - return members + return try requestMember(roomId: roomId, isAdmin: isAdmin).fetchAllConstructed(db) } - static func member(from db: Database, roomId: String, phoneId: String) throws -> DBMember? { - let member = try requestMember(roomId: roomId, phoneId: phoneId).fetchOne(db) - try member?.construct(db) - return member + static func members(from db: Database, roomId: String, phoneIds: [String]) throws -> [DBMember] { + return try requestMember(roomId: roomId, phoneIds: phoneIds).fetchAllConstructed(db) } - private func construct(_ db: Database) throws { + func construct(_ db: Database) throws { let memberId = "\(self.id)" - self.features = (try? DBMember.requestFeature(targetId: memberId).fetchAll(db)) ?? [] + self.features = (try? DBFeature.request(targetId: memberId, targetType: .member).fetchAll(db)) ?? [] self.services = (try? DBService.request(targetId: memberId, targetType: .member).fetchAll(db)) ?? [] if let feedId = self.feedId, let feedType = self.feedType { @@ -194,29 +185,29 @@ class DBMember: Record, DBModelProtocol { @discardableResult func deleteAggregate(_ db: Database) throws -> Bool { let memberId = "\(self.id)" - try DBMember.requestFeature(targetId: memberId).deleteAll(db) - - try? DBService.request(targetId: memberId, targetType: .member).deleteAll(db) + try DBFeature.deleteAll(db, targetId: memberId, targetType: .member) + try? DBService.deleteAll(db, targetId: memberId, targetType: .member) return try self.delete(db) } // MARK: - Requests - static private func requestFeature(targetId: String) -> QueryInterfaceRequest { - return DBFeature.request(targetId: targetId, targetType: DBFeature.TargetType.member) - } - static private func requestMember(roomId: String, phoneId: String) -> AnyTypedRequest { + static private func requestMember(roomId: String, phoneIds: [String]) -> AnyTypedRequest { let memberTable = MemberTable.name let roomMemberTable = RoomMemberTable.name + let phoneIds = phoneIds + .map { "'\($0)'" } + .joinedByComma() + let sql = """ SELECT \(memberTable).* FROM \(roomMemberTable) LEFT JOIN \(memberTable) ON \(roomMemberTable).\(RoomMemberTable.Column.memberId.title) = \(memberTable).\(MemberTable.Column.id.title) WHERE \(RoomMemberTable.Column.roomId.title) = '\(roomId)' - AND \(MemberTable.Column.phoneId.title) = '\(phoneId)' + AND \(MemberTable.Column.phoneId.title) in (\(phoneIds)) """ return SQLRequest(sql).asRequest(of: DBMember.self) diff --git a/Nynja/DB/Models/DBMessage.swift b/Nynja/DB/Models/DBMessage.swift index b4074042489fa6662da89fe7c5ce706a9ab986bd..9c0ec7a6b3cbbf84cbc3ced38dfe7e7c8579632e 100644 --- a/Nynja/DB/Models/DBMessage.swift +++ b/Nynja/DB/Models/DBMessage.swift @@ -10,7 +10,7 @@ import GRDBCipher private let tableName = MessageTable.name -final class DBMessage: Record, DBModelProtocol { +final class DBMessage: Record, DBModel { var container: String? var feedId: Int64? diff --git a/Nynja/DB/Models/DBMessageAction.swift b/Nynja/DB/Models/DBMessageAction.swift index fa37566035fd3dac8b0a2df559002ddf4a2cfdcc..099a5176bbfd25d711f5c81a2274cbdbe2837c6e 100644 --- a/Nynja/DB/Models/DBMessageAction.swift +++ b/Nynja/DB/Models/DBMessageAction.swift @@ -8,7 +8,7 @@ import GRDBCipher -final class DBMessageAction: Record, DBModelProtocol { +final class DBMessageAction: Record, DBModel { enum Action: String { case delete = "delete" @@ -51,7 +51,7 @@ final class DBMessageAction: Record, DBModelProtocol { } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { try self.save(db) diff --git a/Nynja/DB/Models/DBMessageEditAction.swift b/Nynja/DB/Models/DBMessageEditAction.swift index ee2ff754df4f58b1ea4ee0b031cffa03ecd2efb3..0e1bb65e2942a805ececa76c23bc35c4bba171df 100644 --- a/Nynja/DB/Models/DBMessageEditAction.swift +++ b/Nynja/DB/Models/DBMessageEditAction.swift @@ -8,7 +8,7 @@ import GRDBCipher -final class DBMessageEditAction: Record, DBModelProtocol { +final class DBMessageEditAction: Record, DBModel { var messageId: MessageServerId var payload: String @@ -45,7 +45,7 @@ final class DBMessageEditAction: Record, DBModelProtocol { } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { try save(db) diff --git a/Nynja/DB/Models/DBMessageLink.swift b/Nynja/DB/Models/DBMessageLink.swift index 307000ddd7060e03fde196b12f66bde75a10667e..12f3236b1aa9aefd65ef27289e04bd33f1af57a2 100644 --- a/Nynja/DB/Models/DBMessageLink.swift +++ b/Nynja/DB/Models/DBMessageLink.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBMessageLink: Record, DBModelProtocol { +final class DBMessageLink: Record, DBModel { var value: String? var feedId: String? @@ -56,7 +56,7 @@ class DBMessageLink: Record, DBModelProtocol { container[MessageLinkTable.Column.feedType.title] = feedType } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { try self.save(db) } diff --git a/Nynja/DB/Models/DBMuc.swift b/Nynja/DB/Models/DBMuc.swift index a2be04a71780e969f304295d444fe9521dc30399..3d35b1dd4577fe63e3012cb85fe2b2e77af457c7 100644 --- a/Nynja/DB/Models/DBMuc.swift +++ b/Nynja/DB/Models/DBMuc.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBMuc: Record, FeedProtocol { +final class DBMuc: Record, FeedProtocol { var id: Int64? var name: String @@ -49,7 +49,7 @@ class DBMuc: Record, FeedProtocol { container[MucTable.Column.name.title] = name } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { let nameColumn = Column(MucTable.Column.name.title) diff --git a/Nynja/DB/Models/DBP2p.swift b/Nynja/DB/Models/DBP2p.swift index b57d36ea600db77e7d1e892813d2d4b5065b2dc6..1742c46caaec95c900d088d285f1fdf39f3896ea 100644 --- a/Nynja/DB/Models/DBP2p.swift +++ b/Nynja/DB/Models/DBP2p.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBP2p: Record, FeedProtocol { +final class DBP2p: Record, FeedProtocol { var id: Int64? var from: String @@ -53,7 +53,7 @@ class DBP2p: Record, FeedProtocol { container[P2pTable.Column.to.title] = to } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { let fromColumn = Column(P2pTable.Column.from.title) let toColumn = Column(P2pTable.Column.to.title) diff --git a/Nynja/DB/Models/DBProfile.swift b/Nynja/DB/Models/DBProfile.swift index 7c7ef4ff5c345fbb61268b396e2a76aa9ca30d33..5c89cf9ffb064066b87d090ffc1b3e0d8d55043f 100644 --- a/Nynja/DB/Models/DBProfile.swift +++ b/Nynja/DB/Models/DBProfile.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBProfile: Record, DBModelProtocol { +final class DBProfile: Record, DBModel { var phone: String var update: Int64 @@ -80,23 +80,17 @@ class DBProfile: Record, DBModelProtocol { dbProfile.services = try DBService.request(targetId: dbProfile.phone, targetType: .profile).fetchAll(db) dbProfile.rosters = try DBRoster.rosters(from: db, profileId: dbProfile.phone) - dbProfile.features = try request(targetId: dbProfile.phone).fetchAll(db) + dbProfile.features = try DBFeature.request(targetId: dbProfile.phone, targetType: .profile).fetchAll(db) return dbProfile } @discardableResult func deleteAggregate(_ db: Database) throws -> Bool { - try DBProfile.request(targetId: self.phone).deleteAll(db) + try DBFeature.deleteAll(db, targetId: phone, targetType: .profile) + try DBService.deleteAll(db, targetId: phone, targetType: .profile) - try DBService.request(targetId: self.phone, targetType: .profile).deleteAll(db) - - return try self.delete(db) - } - - static private func request(targetId: String) -> QueryInterfaceRequest { - return DBFeature.request(targetId: targetId, targetType: DBFeature.TargetType.profile) + return try delete(db) } - } diff --git a/Nynja/DB/Models/DBRecentSticker.swift b/Nynja/DB/Models/DBRecentSticker.swift index 8c1f0315b4fbff862251c30afd690c63c3c0b296..07fa83dc4df7217c2735400cfebf4aa737863fcc 100644 --- a/Nynja/DB/Models/DBRecentSticker.swift +++ b/Nynja/DB/Models/DBRecentSticker.swift @@ -8,7 +8,7 @@ import GRDBCipher -final class DBRecentSticker: Codable, DBModelProtocol { +final class DBRecentSticker: Codable, DBModel { var id: Int64? var stickerId: String diff --git a/Nynja/DB/Models/DBRoom.swift b/Nynja/DB/Models/DBRoom.swift index a41b3696d4b7431d3b790531f0bf788f39a76f88..1424c99d2c253b312ead585e94a423b58bca8c92 100644 --- a/Nynja/DB/Models/DBRoom.swift +++ b/Nynja/DB/Models/DBRoom.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBRoom: Record, DBModelProtocol { +final class DBRoom: Record, DBExtendedModel { var id: String var name: String @@ -32,7 +32,11 @@ class DBRoom: Record, DBModelProtocol { var rosterId: Int64? var messageId: String? - var message: DBMessage? + var message: DBMessage? { + didSet { + messageId = message?.localId + } + } var members: [DBMember] = [] var admins: [DBMember] = [] @@ -40,6 +44,10 @@ class DBRoom: Record, DBModelProtocol { var files: [DBDesc] = [] var links: [DBLink] = [] + var serverModel: Room { + return Room(room: self) + } + init?(room: Room, rosterId: Int64?) { guard let id = room.id else { return nil } @@ -63,7 +71,7 @@ class DBRoom: Record, DBModelProtocol { // Message if let message = room.message { self.message = DBMessage(message: message) - self.messageId = room.message?.msg_id + self.messageId = self.message?.localId } else { self.messageId = room.lastMessageId } @@ -129,7 +137,7 @@ class DBRoom: Record, DBModelProtocol { // MARK: - Modification func saveAggregate(_ db: Database) throws { - try saveMessage(db) + try message?.saveAggregate(db) reader = calculateReader() try save(db) @@ -153,14 +161,6 @@ class DBRoom: Record, DBModelProtocol { return readers.max(except: selfReader) } - private func saveMessage(_ db: Database) throws { - try message?.saveAggregate(db) - - if message != nil || messageId == nil { - messageId = message?.localId - } - } - private func saveMembers(_ db: Database) throws { try admins.forEach { try $0.saveAggregate(db) @@ -177,17 +177,15 @@ class DBRoom: Record, DBModelProtocol { @discardableResult func deleteAggregate(_ db: Database) throws -> Bool { - try DBRoom.requestFeature(targetId: self.id).deleteAll(db) - try DBDesc.deleteAll(db, targetId: self.id, targetType: .room) + try DBFeature.deleteAll(db, targetId: id, targetType: .room) + try DBDesc.deleteAll(db, targetId: id, targetType: .room) try DBMuc.filter(MucTable.Column.name.title == self.name).deleteAll(db) return try self.delete(db) } // MARK: - Fetch static func room(from db: Database, rowId: Int64) throws -> DBRoom? { - let room = try DBRoom.filter(Column.rowID == rowId).fetchOne(db) - try room?.construct(db) - return room + return try DBRoom.filter(Column.rowID == rowId).fetchOneConstructed(db) } static func room(from db: Database, id: String, fullModel: Bool = true) throws -> DBRoom? { @@ -199,13 +197,6 @@ class DBRoom: Record, DBModelProtocol { return room } - static func rooms(_ db: Database, contactId: String, isAdmin: Bool, type: String?) throws -> [DBRoom] { - let sql = sqlContactRooms(contactId, isAdmin: isAdmin, type: type) - let rooms = try SQLRequest(sql).asRequest(of: DBRoom.self).fetchAll(db) - try rooms.forEach { try $0.construct(db) } - return rooms - } - static func rooms(_ db: Database, rosterId: Int64, type: String?) throws -> [DBRoom] { let rosterIdColumn = Column(RoomTable.Column.rosterId.title) return try rooms(db, type: type, predicate: rosterIdColumn == rosterId) @@ -213,10 +204,14 @@ class DBRoom: Record, DBModelProtocol { static func rooms(_ db: Database, ids: [String], type: String?) throws -> [DBRoom] { let idColumn = Column(RoomTable.Column.id.title) - return try rooms(db, type: type, predicate: ids.contains(idColumn)) + return try rooms( + db, + type: type, + predicate: ids.contains(idColumn), + onlySenderAndSelf: true) } - private static func rooms(_ db: Database, type: String?, predicate: SQLExpressible) throws -> [DBRoom] { + private static func rooms(_ db: Database, type: String?, predicate: SQLExpressible, onlySenderAndSelf: Bool = false) throws -> [DBRoom] { let typeColumn = Column(RoomTable.Column.type.title) let statusColumn = Column(RoomTable.Column.status.title) @@ -226,67 +221,191 @@ class DBRoom: Record, DBModelProtocol { } let rooms = try DBRoom.filter(predicate).fetchAll(db) - try rooms.forEach { try $0.construct(db) } + try rooms.forEach { try $0.construct(db, onlySenderAndSelf: onlySenderAndSelf) } return rooms } - private func construct(_ db: Database) throws { + static func rooms(_ db: Database, args: RequestArgs) throws -> [DBRoom] { + let rooms = try request(with: args).fetchAll(db) + try rooms.forEach { try $0.construct(db, onlySenderAndSelf: true) } + return rooms + } + + func construct(_ db: Database) throws { + try construct(db, onlySenderAndSelf: false) + } + + private func construct(_ db: Database, onlySenderAndSelf: Bool) throws { if let messageId = self.messageId { self.message = try DBMessage.message(db, localId: messageId) } - self.admins = try DBMember.members(from: db, roomId: id, isAdmin: true) - self.members = try DBMember.members(from: db, roomId: id) + var phoneIds: [String] = [] + if onlySenderAndSelf { + message?.from.map { phoneIds.append($0) } + StorageService.sharedInstance.phoneId.map { phoneIds.append($0) } + } + + try constructMembers(db, phoneIds: phoneIds) - self.features = (try? DBRoom.requestFeature(targetId: id).fetchAll(db)) ?? [] + self.features = (try? DBFeature.request(targetId: id, targetType: .room).fetchAll(db)) ?? [] self.files = DBRoom.fetchDescs(db, roomId: id) self.links = (try? DBLink.links(db, roomId: id)) ?? [] } + private func constructMembers(_ db: Database, phoneIds: [String]) throws { + guard !phoneIds.isEmpty else { + self.admins = try DBMember.members(from: db, roomId: id, isAdmin: true) + self.members = try DBMember.members(from: db, roomId: id) + return + } + + let members = try DBMember.members(from: db, roomId: id, phoneIds: phoneIds) + + let statuses: [MemberStatus] = [.admin, .owner] + let statusStrings = statuses.map { $0.rawValue } + + self.admins = [] + self.members = [] + + members.forEach { member in + if let status = member.status, statusStrings.contains(status) { + self.admins.append(member) + } else { + self.members.append(member) + } + } + } + static func fetchDescs(_ db: Database, roomId: String) -> [DBDesc] { return (try? descs(targetId: roomId, db: db)) ?? [] } - private static func sqlContactRooms(_ contactId: String, isAdmin: Bool, type: String?) -> String { + + // MARK: - Make Requests + + static private func descs(targetId: String, db: Database) throws -> [DBDesc] { + return try DBDesc.descs(targetId: targetId, targetType: .room, db: db) + } + + private static func request(with args: RequestArgs) -> AnyTypedRequest { let roomTable = RoomTable.name - let roomMemberTable = RoomMemberTable.name + let messageTable = MessageTable.name let memberTable = MemberTable.name + var sql = """ + select \(roomTable).* + from \(roomTable) + \(messageJoin(messageTable: messageTable, roomTable: roomTable)) + \(memberJoin(ownerId: args.ownerId, memberTable: memberTable, roomTable: roomTable)) + where + \(condition(rosterId: args.rosterId, roomTable: roomTable)) + and \(condition(type: args.type, roomTable: roomTable)) + \(condition(onlyUnread: args.onlyUnread, roomTable: roomTable)) + \(condition(ownerId: args.ownerId)) + \(orderBy(messageTable: messageTable)) + """ + + if let limit = args.limit { + sql.append(" limit \(limit)") + } + + if let offset = args.offset { + sql.append(" offset \(offset)") + } + + return SQLRequest(sql).asRequest(of: DBRoom.self) + } + + private static func messageJoin(messageTable: String, roomTable: String) -> String { + let messageIdColumn = "\(roomTable).\(Column.messageId)" + let localIdColumn = "\(messageTable).\(Column.localId)" + + return "left join \(messageTable) on \(messageIdColumn) == \(localIdColumn)" + } + + private static func memberJoin(ownerId: String?, memberTable: String, roomTable: String) -> String { + guard ownerId != nil else { + return "" + } + + let roomMemberTable = RoomMemberTable.name + let roomIdColumn = "\(roomTable).\(RoomTable.Column.id.title)" let roomMemberRoomIdColumn = "\(roomMemberTable).\(RoomMemberTable.Column.roomId.title)" let memberIdColumn = "\(memberTable).\(MemberTable.Column.id.title)" let rommMemberMemberIdColumn = "\(roomMemberTable).\(RoomMemberTable.Column.memberId.title)" + - let memberPhoneIdColumn = "\(memberTable).\(MemberTable.Column.phoneId.title)" - - var sql = """ - select \(roomTable).* - from \(roomTable) - left join \(roomMemberTable) on \(roomIdColumn) == \(roomMemberRoomIdColumn) - left join \(memberTable) on \(memberIdColumn) == \(rommMemberMemberIdColumn) - where \(memberPhoneIdColumn) == '\(contactId)' + return """ + left join \(roomMemberTable) on \(roomIdColumn) == \(roomMemberRoomIdColumn) + left join \(memberTable) on \(memberIdColumn) == \(rommMemberMemberIdColumn) """ + } + + private static func condition(rosterId: Int64, roomTable: String) -> String { + let rosterIdColumn = "\(roomTable).\(Column.rosterId)" + return "\(rosterIdColumn) == \(rosterId)" + } + + private static func condition(type: String, roomTable: String) -> String { + let typeColumn = "\(roomTable).\(Column.type)" + return "\(typeColumn) == '\(type)'" + } + + private static func condition(onlyUnread: Bool, roomTable: String) -> String { + let unreadColumn = "\(roomTable).\(Column.unread)" + return onlyUnread ? "and \(unreadColumn) > 0" : "" + } + + private static func condition(ownerId: String?) -> String { + guard let ownerId = ownerId else { + return "" + } + + let memberTable = MemberTable.name + let memberPhoneIdColumn = "\(memberTable).\(MemberTable.Column.phoneId.title)" let memberStatusColumn = "\(memberTable).\(MemberTable.Column.status.title)" - if isAdmin { - sql.append(contentsOf: "and \(memberStatusColumn) in ('admin', 'owner')") - } - let roomTypeColumn = "\(roomTable).\(RoomTable.Column.type.title)" - if let type = type { - sql.append(contentsOf: "and \(roomTypeColumn) == '\(type)'") - } - - return sql + return """ + and \(memberPhoneIdColumn) == '\(ownerId)'" + and \(memberStatusColumn) in ('admin', 'owner') + """ } - // MARK: - Make Requests - static private func requestFeature(targetId: String) -> QueryInterfaceRequest { - return DBFeature.request(targetId: targetId, targetType: .room) + private static func orderBy(messageTable: String) -> String { + let createdColumn = "\(messageTable).\(Column.created)" + return "order by \(createdColumn) desc" } +} + + +// MARK: - + +extension DBRoom { - static private func descs(targetId: String, db: Database) throws -> [DBDesc] { - return try DBDesc.descs(targetId: targetId, targetType: .room, db: db) + struct RequestArgs { + let rosterId: Int64 + let type: String + let onlyUnread: Bool + let ownerId: String? + let limit: Int? + let offset: Int? + + init(rosterId: Int64, + type: String, + onlyUnread: Bool = false, + ownerId: String? = nil, + limit: Int? = nil, + offset: Int? = nil) { + self.rosterId = rosterId + self.type = type + self.onlyUnread = onlyUnread + self.ownerId = ownerId + self.limit = limit + self.offset = offset + } } } diff --git a/Nynja/DB/Models/DBRoomMember.swift b/Nynja/DB/Models/DBRoomMember.swift index 95d1502219621c8da8741fac3a4281d9b4b251df..064920885dd954bf29bc58f5974af0b19a7ed571 100644 --- a/Nynja/DB/Models/DBRoomMember.swift +++ b/Nynja/DB/Models/DBRoomMember.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBRoomMember: Record { +final class DBRoomMember: Record { var roomId: String var memberId: Int64 diff --git a/Nynja/DB/Models/DBRoster.swift b/Nynja/DB/Models/DBRoster.swift index c76950802b688ef068fcd5c9ec8cdeeda8f3ef88..ecf212027055a321e221e5f9457258725fced6a9 100644 --- a/Nynja/DB/Models/DBRoster.swift +++ b/Nynja/DB/Models/DBRoster.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBRoster: Record, DBModelProtocol { +final class DBRoster: Record, DBModel { var id: Int64 var names: String @@ -24,9 +24,7 @@ class DBRoster: Record, DBModelProtocol { var contacts: [DBContact] = [] var rooms: [DBRoom] = [] - // TODO: Implement tags var stars: [DBStar] = [] -// var tag: [DBTag] = [] init?(roster: Roster, profileId: String) { guard let id = roster.id else { @@ -124,8 +122,7 @@ class DBRoster: Record, DBModelProtocol { } @discardableResult - func deleteAggragete(_ db: Database) throws -> Bool { + func deleteAggregate(_ db: Database) throws -> Bool { return try self.delete(db) - } - + } } diff --git a/Nynja/DB/Models/DBService.swift b/Nynja/DB/Models/DBService.swift index 0a6eafa869abb8cff4776374286460d406dedd29..849aca8ae0338c53b174c1a19b094338e2ca5a86 100644 --- a/Nynja/DB/Models/DBService.swift +++ b/Nynja/DB/Models/DBService.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBService: Codable { +final class DBService: Codable { var id: String var type: String @@ -58,6 +58,9 @@ class DBService: Codable { self.targetType = targetType.rawValue } + static func deleteAll(_ db: Database, targetId: String, targetType: TargetType) throws { + try request(targetId: targetId, targetType: targetType).deleteAll(db) + } } extension DBService: RowConvertible, Persistable { diff --git a/Nynja/DB/Models/DBStar.swift b/Nynja/DB/Models/DBStar.swift index 6f21437a7ccd263468e0092d5b3d7937908f5fbb..3551483edfdd5cc198fa54a11c64cfdcbf168b6f 100644 --- a/Nynja/DB/Models/DBStar.swift +++ b/Nynja/DB/Models/DBStar.swift @@ -9,16 +9,26 @@ import Foundation import GRDBCipher -final class DBStar: Record, DBModelProtocol { +final class DBStar: Record, DBExtendedModel { var id: Int64? var clientId: String? var rosterId: Int64? - var message: DBStarMessage? + var message: DBStarMessage? { + didSet { + messageID = message?.localId + } + } var messageID: String? var status: String? + var serverModel: Star { + return Star(star: self) + } + + // MARK: - Mapping + init?(star: Star) { self.id = star.id self.clientId = star.client_id ?? IdBuilder(format: .starClientId) @@ -28,6 +38,7 @@ final class DBStar: Record, DBModelProtocol { self.status = StringAtom.string(star.status) if let msg = star.message { self.message = DBStarMessage(message: msg) + self.messageID = message?.localId } super.init() } @@ -44,71 +55,39 @@ final class DBStar: Record, DBModelProtocol { } } + // MARK: - Record + override static var databaseTableName: String { return StarTable.name } required init(row: Row) { - id = row[StarTable.Column.id.title] - clientId = row[StarTable.Column.clientId.title] - rosterId = row[StarTable.Column.rosterId.title] - status = row[StarTable.Column.status.title] - messageID = row[StarTable.Column.messageId.title] + id = row[Column.id] + clientId = row[Column.clientId] + rosterId = row[Column.rosterId] + status = row[Column.status] + messageID = row[Column.messageId] super.init() } override func encode(to container: inout PersistenceContainer) { - container[StarTable.Column.id.title] = id - container[StarTable.Column.clientId.title] = clientId - container[StarTable.Column.rosterId.title] = rosterId - container[StarTable.Column.status.title] = status - container[StarTable.Column.messageId.title] = messageID + container[Column.id] = id + container[Column.clientId] = clientId + container[Column.rosterId] = rosterId + container[Column.status] = status + container[Column.messageId] = messageID } - // MARK: - DBModelProtocol + + // MARK: - DBModel + func saveAggregate(_ db: Database) throws { try message?.saveAggregate(db) - messageID = message?.localId try self.save(db) } - static func star(_ db: Database, rowId: Int64) throws -> DBStar? { - let star = try DBStar.filter(Column.rowID == rowId).fetchOne(db) - try star?.construct(db) - return star - } - - static func star(_ db: Database, clientId: String) throws -> DBStar? { - let clientIdColumn = Column(StarTable.Column.clientId.title) - let star = try DBStar.filter(clientIdColumn == clientId).fetchOne(db) - try star?.construct(db) - return star - } - - static func stars(from db: Database, rosterId: Int64) throws -> [DBStar] { - let rosterIdColumn = Column(StarTable.Column.rosterId.title) - let statusColumn = Column(StarTable.Column.status.title) - - let filter: SQLExpressible = rosterIdColumn == rosterId && statusColumn !== Star.Status.remove.rawValue - let stars = try DBStar.filter(filter).fetchAll(db) - - try stars.forEach { try $0.construct(db) } - return stars - } - - static func undeliveredStars(from db: Database, rosterId: Int64) throws -> [DBStar] { - let rosterIdColumn = Column(StarTable.Column.rosterId.title) - let starIdColumn = Column(StarTable.Column.id.title) - - let filter: SQLExpressible = rosterIdColumn == rosterId && starIdColumn == nil - let stars = try DBStar.filter(filter).fetchAll(db) - - try stars.forEach { try $0.construct(db) } - return stars - } - - private func construct(_ db: Database) throws { + func construct(_ db: Database) throws { if let messageId = messageID { message = try DBStarMessage.message(db, localId: messageId) } @@ -119,4 +98,15 @@ final class DBStar: Record, DBModelProtocol { try self.message?.deleteAggregate(db) return try self.delete(db) } + + + // MARK: - Fetching + + static func stars(from db: Database, rosterId: Int64) throws -> [DBStar] { + return try DBStar + .filter(Column.rosterId == rosterId) + .filter(Column.status !== Star.Status.remove.rawValue) + .fetchAllConstructed(db) + } + } diff --git a/Nynja/DB/Models/DBStarAction.swift b/Nynja/DB/Models/DBStarAction.swift index 9e669edbb0614bb06bcdde660eebea9a7bb35e07..7a65d5b46e8078a9b362c38b49110850e8baed99 100644 --- a/Nynja/DB/Models/DBStarAction.swift +++ b/Nynja/DB/Models/DBStarAction.swift @@ -8,7 +8,7 @@ import GRDBCipher -final class DBStarAction: Record, DBModelProtocol { +final class DBStarAction: Record, DBModel { enum Action: String { case delete = "delete" } @@ -23,14 +23,14 @@ final class DBStarAction: Record, DBModelProtocol { } required init(row: Row) { - starLocalId = row[StarActionTable.Column.starId.title] - action = Action(rawValue: row[StarActionTable.Column.action.title])! + starLocalId = row[Column.starId] + action = Action(rawValue: row[Column.action])! super.init() } override func encode(to container: inout PersistenceContainer) { - container[StarActionTable.Column.starId.title] = starLocalId - container[StarActionTable.Column.action.title] = action.rawValue + container[Column.starId] = starLocalId + container[Column.action] = action.rawValue } override static var databaseTableName: String { @@ -38,8 +38,8 @@ final class DBStarAction: Record, DBModelProtocol { } static func starAction(_ db: Database, starLocalId: String) throws -> DBStarAction? { - let starIdColumn = Column(StarActionTable.Column.starId.title) - let filter: SQLExpressible = starIdColumn == starLocalId - return try DBStarAction.filter(filter).fetchOne(db) + return try DBStarAction + .filter(Column.starId == starLocalId) + .fetchOne(db) } } diff --git a/Nynja/DB/Models/DBStarMessage.swift b/Nynja/DB/Models/DBStarMessage.swift index 00e7da110ef0f2c0866f2b921f35f6a4b3ecefaf..e75a2c273dbc54d08c7eaf6b37b32d28ebb96ea8 100644 --- a/Nynja/DB/Models/DBStarMessage.swift +++ b/Nynja/DB/Models/DBStarMessage.swift @@ -9,7 +9,7 @@ import Foundation import GRDBCipher -final class DBStarMessage: Record, DBModelProtocol { +final class DBStarMessage: Record, DBModel { var container: String? var feedId: Int64? @@ -68,7 +68,6 @@ final class DBStarMessage: Record, DBModelProtocol { self.status = message.statusString self.files = (message.files ?? []).compactMap { DBDesc(desc: $0, targetId: nil, targetType: .star) } -// self.repliedBy = message.repliedby?.myJoined(separator: DBMessage.separator) self.mentioned = message.mentioned?.joinedByComma() super.init() @@ -235,7 +234,7 @@ final class DBStarMessage: Record, DBModelProtocol { return nil } - private func construct(_ db: Database) throws { + func construct(_ db: Database) throws { files = try DBDesc.descs(targetId: localId, targetType: .star, db: db) guard let feedId = feedId, let feedType = feedType, let type = FeedType(rawValue: feedType) else { @@ -264,7 +263,9 @@ final class DBStarMessage: Record, DBModelProtocol { } } + // MARK: - Delete + @discardableResult func deleteAggregate(_ db: Database) throws -> Bool { try DBDesc.deleteAll(db, targetId: localId, targetType: .star) diff --git a/Nynja/DB/Models/DBStickerPack.swift b/Nynja/DB/Models/DBStickerPack.swift index a0818e949b6e8c8106346c10f7c408197f4ece7b..05d4e4c360cf13e341d6b21341dc82a586bf7319 100644 --- a/Nynja/DB/Models/DBStickerPack.swift +++ b/Nynja/DB/Models/DBStickerPack.swift @@ -8,7 +8,7 @@ import GRDBCipher -final class DBStickerPack: Record, DBModelProtocol { +final class DBStickerPack: Record, DBModel { // MARK: - Fields @@ -74,7 +74,7 @@ final class DBStickerPack: Record, DBModelProtocol { } - // MARK: - DBModelProtocol + // MARK: - DBModel func saveAggregate(_ db: Database) throws { try save(db) @@ -124,7 +124,7 @@ final class DBStickerPack: Record, DBModelProtocol { // MARK: Foreign Constraints - private func construct(_ db: Database) throws { + func construct(_ db: Database) throws { stickers = try DBStickerPack.stickers(from: db, targetId: String(id)) } diff --git a/Nynja/DB/Models/DBSyncFile.swift b/Nynja/DB/Models/DBSyncFile.swift index 943111b1faf71d435edf353602ff35955f3c864c..bd291d4c0eb9c4af6986186ac42a88000e3d8012 100644 --- a/Nynja/DB/Models/DBSyncFile.swift +++ b/Nynja/DB/Models/DBSyncFile.swift @@ -8,7 +8,7 @@ import GRDBCipher -class DBSyncFile: Record { +final class DBSyncFile: Record { var id: Int? var serverLink: String? diff --git a/Nynja/DB/Protocols/DBModelConvertible.swift b/Nynja/DB/Protocols/DBModelConvertible.swift index 658c1536253bcf87c68b48bbf0369063ea0db87a..b2e844f407bb46d39465c4bbb78b6aaceeee0ebd 100644 --- a/Nynja/DB/Protocols/DBModelConvertible.swift +++ b/Nynja/DB/Protocols/DBModelConvertible.swift @@ -8,6 +8,6 @@ protocol DBModelConvertible { - var databaseModel: DBModelProtocol? { get } + var databaseModel: DBModel? { get } } diff --git a/Nynja/DB/QueryArgs.swift b/Nynja/DB/QueryArgs.swift new file mode 100644 index 0000000000000000000000000000000000000000..31a59b4da8146363aa2efc36c9c214a765b2a34a --- /dev/null +++ b/Nynja/DB/QueryArgs.swift @@ -0,0 +1,78 @@ +// +// QueryArgs.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +protocol QueryRequestMakeable { + func makeRequest() -> Request +} + +protocol QueryArgs: QueryRequestMakeable { + var limit: Int? { get } + var offset: Int? { get } + var orderingTerms: [SQLOrderingTerm]? { get } +} + +protocol TypedQueryRequestMakeable { + associatedtype Model: DBModel + func makeTypedRequest() -> QueryInterfaceRequest +} + +protocol CompositeQueryArgs: TypedQueryRequestMakeable { + // TODO: add filter func... + var args: AnyQueryArgs { get } +} + +typealias QueryFilter = (QueryInterfaceRequest) -> QueryInterfaceRequest + +struct AnyQueryArgs: QueryArgs, TypedQueryRequestMakeable { + let limit: Int? + let offset: Int? + let orderingTerms: [SQLOrderingTerm]? + + private(set) var filters: [QueryFilter] = [] + + init(limit: Int? = nil, + offset: Int? = nil, + orderingTerms: [SQLOrderingTerm]? = nil, + filters: [QueryFilter] = []) { + self.limit = limit + self.offset = offset + self.orderingTerms = orderingTerms + self.filters = filters + } + + init(args: QueryArgs, filters: [QueryFilter] = []) { + self.init( + limit: args.limit, + offset: args.offset, + orderingTerms: args.orderingTerms) + } + + func filter(_ filter: @escaping QueryFilter) -> AnyQueryArgs { + var filters = self.filters + filters.append(filter) + return AnyQueryArgs(args: self, filters: filters) + } + + func makeTypedRequest() -> QueryInterfaceRequest { + var query = T.all() + .performIfValueExists(limit) { $0.limit($1, offset: offset) } + .performIfValueExists(orderingTerms) { $0.order($1) } + + filters.forEach { filter in + query = filter(query) + } + + return query + } + + func makeRequest() -> Request { + return makeTypedRequest() + } +} diff --git a/Nynja/DB/RosterRelatedQueryArgs.swift b/Nynja/DB/RosterRelatedQueryArgs.swift new file mode 100644 index 0000000000000000000000000000000000000000..c7127806656048568430e0fee93775968396f454 --- /dev/null +++ b/Nynja/DB/RosterRelatedQueryArgs.swift @@ -0,0 +1,27 @@ +// +// RosterRelatedQueryArgs.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/13/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +struct RosterRelatedQueryArgs: CompositeQueryArgs { + let rosterId: Int64 + let args: AnyQueryArgs + + init(rosterId: Int64) { + self.init(rosterId: rosterId, args: AnyQueryArgs()) + } + + init(rosterId: Int64, args: AnyQueryArgs) { + self.rosterId = rosterId + self.args = args + } + + func makeTypedRequest() -> QueryInterfaceRequest { + return args.makeTypedRequest().filter(Column.rosterId == rosterId) + } +} diff --git a/Nynja/DB/Tables/Base/SharedColumn.swift b/Nynja/DB/Tables/Base/SharedColumn.swift new file mode 100644 index 0000000000000000000000000000000000000000..45050efac3c963990dadc773848876d79e512e3d --- /dev/null +++ b/Nynja/DB/Tables/Base/SharedColumn.swift @@ -0,0 +1,33 @@ +// +// Column.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/4/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +extension Column { + static let id = Column("id") + static let phoneId = Column("phoneId") + static let rosterId = Column("rosterId") + static let messageId = Column("messageId") + static let serverId = Column("serverId") + static let localId = Column("localId") + static let starId = Column("starId") + static let feedId = Column("feedId") + + static let container = Column("container") + static let action = Column("action") + static let reader = Column("reader") + static let unread = Column("unread") + static let created = Column("created") + static let time = Column("time") + + static let status = Column("status") + static let type = Column("type") + + static let next = Column("next") + static let prev = Column("prev") +} diff --git a/Nynja/DB/Tables/ContactTable.swift b/Nynja/DB/Tables/ContactTable.swift index 3ac2717c618af8e4e9806f0140df56999c3350e7..f8a4e45605706e731c6ed827fa786f2ea37d6ce6 100644 --- a/Nynja/DB/Tables/ContactTable.swift +++ b/Nynja/DB/Tables/ContactTable.swift @@ -52,3 +52,8 @@ extension ContactTable { case rosterId } } + + +extension Column { + static let nick = Column("nick") +} diff --git a/Nynja/DB/Tables/JobMessageTable.swift b/Nynja/DB/Tables/JobMessageTable.swift index cbd6bdb48ec7eaaf51ff48425756455ad92e0e55..5f02501d10233c2dbb4475806b60b10a56aa05c5 100644 --- a/Nynja/DB/Tables/JobMessageTable.swift +++ b/Nynja/DB/Tables/JobMessageTable.swift @@ -60,3 +60,8 @@ extension JobMessageTable { case jobId } } + + +extension Column { + static let jobId = Column("jobId") +} diff --git a/Nynja/DB/Tables/JobTable.swift b/Nynja/DB/Tables/JobTable.swift index ce966f7f0a6ea5459a72940778315745f266c502..4182a226449796be93502649ecdbe30c11ee235c 100644 --- a/Nynja/DB/Tables/JobTable.swift +++ b/Nynja/DB/Tables/JobTable.swift @@ -16,31 +16,15 @@ final class JobTable: Table { static func create(in db: Database) throws { try db.create(self) { t in - t.column(JobTable.Column.id, .integer).primaryKey(onConflict: nil, autoincrement: true) - t.column(JobTable.Column.serverId, .integer) - t.column(JobTable.Column.container, .text) - t.column(JobTable.Column.feedId, .text) - t.column(JobTable.Column.prev, .integer) - t.column(JobTable.Column.next, .integer) - t.column(JobTable.Column.time, .integer) - t.column(JobTable.Column.status, .text) - t.column(JobTable.Column.type, .integer).notNull().defaults(to: DBJob.JobType.schedule.rawValue) + t.column(Column.id, .integer).primaryKey(onConflict: nil, autoincrement: true) + t.column(Column.serverId, .integer) + t.column(Column.container, .text) + t.column(Column.feedId, .text) + t.column(Column.prev, .integer) + t.column(Column.next, .integer) + t.column(Column.time, .integer) + t.column(Column.status, .text) + t.column(Column.type, .integer).notNull().defaults(to: DBJob.JobType.schedule.rawValue) } } } - -// MARK: - Column -extension JobTable { - - enum Column: Int, Describable { - case id - case serverId - case container - case feedId - case prev - case next - case time - case status - case type - } -} diff --git a/Nynja/DB/Tables/StarActionTable.swift b/Nynja/DB/Tables/StarActionTable.swift index e906491682e8fe2b7de48a131bbeffe554351100..183fe3a8fd638ca29e8b295918d7a703f6c3b10f 100644 --- a/Nynja/DB/Tables/StarActionTable.swift +++ b/Nynja/DB/Tables/StarActionTable.swift @@ -19,18 +19,9 @@ final class StarActionTable: Table { t.column(Column.starId, .text) .notNull() .primaryKey(onConflict: .replace, autoincrement: false) - .references(StarTable.name, column: StarTable.Column.clientId.title, onDelete: .cascade) + .references(StarTable.name, column: Column.clientId, onDelete: .cascade) t.column(Column.action, .text).notNull() } } } - -// MARK: Column -extension StarActionTable { - - enum Column: Int, Describable { - case starId - case action - } -} diff --git a/Nynja/DB/Tables/StarTable.swift b/Nynja/DB/Tables/StarTable.swift index 1768cacb632d68bd0f55c75b39b3b062a1eb05d6..6676cd1755ab0357918697e6e3259d0747c4ec0c 100644 --- a/Nynja/DB/Tables/StarTable.swift +++ b/Nynja/DB/Tables/StarTable.swift @@ -25,14 +25,9 @@ final class StarTable: Table { } } -// MARK: - Column -extension StarTable { - - enum Column: Int, Describable { - case id - case clientId - case status - case rosterId - case messageId - } + +extension Column { + static let clientId = Column("clientId") } + + diff --git a/Nynja/DBManagerProtocol.swift b/Nynja/DBManagerProtocol.swift index cce9695e9b8e52362c7713ef9466d583a7563f97..07c5c2434b27e1adc4ccc88534176739cf4c810c 100644 --- a/Nynja/DBManagerProtocol.swift +++ b/Nynja/DBManagerProtocol.swift @@ -27,9 +27,9 @@ protocol DBManagerProtocol { // MARK: - Perform Actions func perform(action: DatabaseAction, with model: DBModelConvertible) throws - func perform(action: DatabaseAction, with model: DBModelProtocol) throws + func perform(action: DatabaseAction, with model: DBModel) throws func perform(action: DatabaseAction, with models: [DBModelConvertible]) throws - func perform(action: DatabaseAction, with models: [DBModelProtocol]) throws + func perform(action: DatabaseAction, with models: [DBModel]) throws } diff --git a/Nynja/DBObserver.swift b/Nynja/DBObserver.swift index e5ceec7a7c9ab3d0d880b288dbebce620c5bf6d8..37e28e9b08f31ef12889ea0760728652e9e833a6 100644 --- a/Nynja/DBObserver.swift +++ b/Nynja/DBObserver.swift @@ -8,19 +8,23 @@ import GRDBCipher -class DBObserver: StorageObserver, TransactionObserver { +final class DBObserver: StorageObserver, TransactionObserver { static let `default` = DBObserver() private init() {} + private let processingQueue = DispatchQueue( + label: String.label(withSuffix: "db-observer.processing-queue"), + qos: .utility) + // MARK: - Properties var subscribers: [SubscribeType: [StorageSubscriberReference]] = [:] private var allChanges: Dictionary = [:] - - private var tables: [Table.Type] { - return [ + + private let tableNames: [String] = { + let tables: [Table.Type] = [ JobTable.self, MessageTable.self, ContactTable.self, @@ -32,11 +36,8 @@ class DBObserver: StorageObserver, TransactionObserver { RecentStickerTable.self, StickerPackTable.self ] - } - - private var tableNames: [String] { return tables.map { $0.name } - } + }() // MARK: - TransactionObserver func observes(eventsOfKind eventKind: DatabaseEventKind) -> Bool { @@ -54,12 +55,24 @@ class DBObserver: StorageObserver, TransactionObserver { } func databaseDidChange(with event: DatabaseEvent) { + processingQueue.async { [unowned self] in + self.handleDidChange(with: event) + } + } + + private func handleDidChange(with event: DatabaseEvent) { var temp = allChanges[event.tableName] ?? [] temp.append(ChangeInfo(event: event)) allChanges[event.tableName] = temp } func databaseWillCommit() throws { + processingQueue.async { [unowned self] in + self.handleWillCommit() + } + } + + private func handleWillCommit() { allChanges.forEach { (tableName, changes) in changes.forEach { info in guard info.kind != .insert else { return } @@ -69,124 +82,34 @@ class DBObserver: StorageObserver, TransactionObserver { } func databaseDidCommit(_ db: Database) { + processingQueue.async { [unowned self] in + self.handleDidCommit(db) + } + } + + private func handleDidCommit(_ db: Database) { allChanges.forEach { (tableName, changes) in - var storageChanges: [StorageChange] = [] - switch tableName { case JobTable.name: - changes.forEach { info in - let change = storageChange(from: info) - storageChanges.append(change) - - let job = change.entity as? Job - notify(with: [change], type: .job(job?.id)) - } - - notify(with: storageChanges, type: .job(nil)) + handleJobDidCommit(changes: changes) case MessageTable.name: - func handle(changes: [ChangeInfo]) { - changes.forEach { info in - let message = changedValue(from: info) as? Message - - if let receiver = message?.p2pFeed?.opponentId { - notify(with: info.event, entity: message, type: .chat(receiver)) - } else if let roomId = message?.mucFeed?.name { - notify(with: info.event, entity: message, type: .chat(roomId)) - } - - notify(with: info.event, entity: message, type: .reply(message?.id)) - } - } - - if changes.count == 2, - case let firstInfo = changes[0], - case let secondInfo = changes[1], - let firstMessage = changedValue(from: firstInfo) as? Message, - let secondMessage = changedValue(from: secondInfo) as? Message, - case let isFirstReply = firstMessage.isReply && firstMessage.linkedId == secondMessage.id, - case let isSecondReply = secondMessage.isReply && secondMessage.linkedId == firstMessage.id, - isFirstReply || isSecondReply { - handle(changes: [firstInfo]) - handle(changes: [secondInfo]) - } else if changes.count > 1, let info = changes.first, let message = changedValue(from: info) as? Message { - if let receiver = message.p2pFeed?.opponentId { - notify(with: [], type: .chat(receiver)) - } else if let roomId = message.mucFeed?.name { - notify(with: [], type: .chat(roomId)) - } - } else { - handle(changes: changes) - } + handleMessageDidCommit(changes: changes) case ContactTable.name: - if changes.count == 1, let info = changes.first { - let contact = changedValue(from: info) as? DBContact - notify(with: info.event, entity: contact, type: .contact(nil)) - } else { - notify(with: [], type: .contact(nil)) - } - - changes.forEach { info in - let contact = changedValue(from: info) as? DBContact - notify(with: info.event, entity: contact, type: .contact(contact?.phoneId)) - } + handleContactDidCommit(changes: changes) case RoomTable.name: - changes.forEach { info in - let change = storageChange(from: info) - storageChanges.append(change) - - let room = change.entity as? DBRoom - notify(with: [change], type: .room(room?.id)) - } - - notify(with: storageChanges, type: .room(nil)) + handleRoomDidCommit(changes: changes) case MemberTable.name: - changes.forEach { info in - let member = changedValue(from: info) as? DBMember - notify(with: info.event, entity: member, type: .member((member?.feed as? DBMuc)?.name)) - } + handleMemberDidCommit(changes: changes) case RosterTable.name: - changes.forEach { info in - let change = storageChange(from: info) - storageChanges.append(change) - - let roster = changedValue(from: info) as? DBRoster - notify(with: [change], type: .roster(roster?.id)) - } - - notify(with: storageChanges, type: .roster(nil)) + handleRosterDidCommit(changes: changes) case StarTable.name: - changes.forEach { info in - let change = storageChange(from: info) - storageChanges.append(change) - - let star = changedValue(from: info) as? DBStar - notify(with: [change], type: .star(star?.clientId)) - } - - notify(with: storageChanges, type: .star(nil)) + handleStarDidCommit(changes: changes) case ProfileTable.name: - changes.forEach { info in - let profile = changedValue(from: info) as? DBProfile - notify(with: info.event, entity: profile, type: .profile) - } + handleProfileDidCommit(changes: changes) case RecentStickerTable.name: - changes.forEach { info in - let change = storageChange(from: info) - storageChanges.append(change) - - let recentSticker = changedValue(from: info) as? DBRecentSticker - notify(with: [change], type: .recentSticker(recentSticker?.id)) - } - notify(with: storageChanges, type: .recentSticker(nil)) + handleRecentStickerDidCommit(changes: changes) case StickerPackTable.name: - changes.forEach { info in - let change = storageChange(from: info) - storageChanges.append(change) - - let stickerPack = changedValue(from: info) as? StickerPack - notify(with: [change], type: .stickerPack(stickerPack?.id)) - } - notify(with: storageChanges, type: .stickerPack(nil)) + handleStickerPackDidCommit(changes: changes) default: break } @@ -195,8 +118,156 @@ class DBObserver: StorageObserver, TransactionObserver { clear() } + private func handleJobDidCommit(changes: [ChangeInfo]) { + var storageChanges: [StorageChange] = [] + + changes.forEach { info in + let change = storageChange(from: info) + storageChanges.append(change) + + let job = change.entity as? Job + notify(with: [change], type: .job(job?.id)) + } + + notify(with: storageChanges, type: .job(nil)) + } + + private func handleMessageDidCommit(changes: [ChangeInfo]) { + func handle(changes: [ChangeInfo]) { + changes.forEach { info in + let message = changedValue(from: info) as? Message + + if let receiver = message?.p2pFeed?.opponentId { + notify(with: info.event, entity: message, type: .chat(receiver)) + } else if let roomId = message?.mucFeed?.name { + notify(with: info.event, entity: message, type: .chat(roomId)) + } + + notify(with: info.event, entity: message, type: .reply(message?.id)) + } + } + + if changes.count == 2, + case let firstInfo = changes[0], + case let secondInfo = changes[1], + let firstMessage = changedValue(from: firstInfo) as? Message, + let secondMessage = changedValue(from: secondInfo) as? Message, + case let isFirstReply = firstMessage.isReply && firstMessage.linkedId == secondMessage.id, + case let isSecondReply = secondMessage.isReply && secondMessage.linkedId == firstMessage.id, + isFirstReply || isSecondReply { + handle(changes: [firstInfo]) + handle(changes: [secondInfo]) + } else if changes.count > 1, let info = changes.first, let message = changedValue(from: info) as? Message { + if let receiver = message.p2pFeed?.opponentId { + notify(with: [], type: .chat(receiver)) + } else if let roomId = message.mucFeed?.name { + notify(with: [], type: .chat(roomId)) + } + } else { + handle(changes: changes) + } + } + + private func handleContactDidCommit(changes: [ChangeInfo]) { + if changes.count == 1, let info = changes.first { + let contact = changedValue(from: info) as? DBContact + notify(with: info.event, entity: contact, type: .contact(nil)) + } else { + notify(with: [], type: .contact(nil)) + } + + changes.forEach { info in + let contact = changedValue(from: info) as? DBContact + notify(with: info.event, entity: contact, type: .contact(contact?.phoneId)) + } + } + + private func handleRoomDidCommit(changes: [ChangeInfo]) { + var storageChanges: [StorageChange] = [] + + changes.forEach { info in + let change = storageChange(from: info) + storageChanges.append(change) + + let room = change.entity as? DBRoom + notify(with: [change], type: .room(room?.id)) + } + + notify(with: storageChanges, type: .room(nil)) + } + + private func handleMemberDidCommit(changes: [ChangeInfo]) { + changes.forEach { info in + let member = changedValue(from: info) as? DBMember + notify(with: info.event, entity: member, type: .member((member?.feed as? DBMuc)?.name)) + } + } + + private func handleRosterDidCommit(changes: [ChangeInfo]) { + var storageChanges: [StorageChange] = [] + + changes.forEach { info in + let change = storageChange(from: info) + storageChanges.append(change) + + let roster = changedValue(from: info) as? DBRoster + notify(with: [change], type: .roster(roster?.id)) + } + + notify(with: storageChanges, type: .roster(nil)) + } + + private func handleStarDidCommit(changes: [ChangeInfo]) { + var storageChanges: [StorageChange] = [] + + changes.forEach { info in + let change = storageChange(from: info) + storageChanges.append(change) + + let star = changedValue(from: info) as? DBStar + notify(with: [change], type: .star(star?.clientId)) + } + + notify(with: storageChanges, type: .star(nil)) + } + + private func handleProfileDidCommit(changes: [ChangeInfo]) { + changes.forEach { info in + let profile = changedValue(from: info) as? DBProfile + notify(with: info.event, entity: profile, type: .profile) + } + } + + private func handleRecentStickerDidCommit(changes: [ChangeInfo]) { + var storageChanges: [StorageChange] = [] + + changes.forEach { info in + let change = storageChange(from: info) + storageChanges.append(change) + + let recentSticker = changedValue(from: info) as? DBRecentSticker + notify(with: [change], type: .recentSticker(recentSticker?.id)) + } + notify(with: storageChanges, type: .recentSticker(nil)) + } + + private func handleStickerPackDidCommit(changes: [ChangeInfo]) { + var storageChanges: [StorageChange] = [] + + changes.forEach { info in + let change = storageChange(from: info) + storageChanges.append(change) + + let stickerPack = changedValue(from: info) as? StickerPack + notify(with: [change], type: .stickerPack(stickerPack?.id)) + } + notify(with: storageChanges, type: .stickerPack(nil)) + } + func databaseDidRollback(_ db: Database) { - clear() + processingQueue.async { + self.clear() + } } // MARK: - Private diff --git a/Nynja/DatabaseManager.swift b/Nynja/DatabaseManager.swift index 315b4c23312118e822f8bce995adbe5559658747..83c0dc9d758a85fcd77f97e0ddb7cf7cfaf282d5 100644 --- a/Nynja/DatabaseManager.swift +++ b/Nynja/DatabaseManager.swift @@ -191,7 +191,7 @@ final class DatabaseManager: DBManagerProtocol { try perform(action: action, with: dbModel) } - func perform(action: DatabaseAction, with model: DBModelProtocol) throws { + func perform(action: DatabaseAction, with model: DBModel) throws { try perform(action: action, with: [model]) } @@ -200,7 +200,7 @@ final class DatabaseManager: DBManagerProtocol { try perform(action: action, with: models) } - func perform(action: DatabaseAction, with models: [DBModelProtocol]) throws { + func perform(action: DatabaseAction, with models: [DBModel]) throws { try writeInTransaction { db in try models.forEach { model in switch action { diff --git a/Nynja/Extensions/Models/Contact/Contact+DB.swift b/Nynja/Extensions/Models/Contact/Contact+DB.swift index 47b6784513818514623fca550707221734d78725..0aff9a2ebad5ee1bde174c7a21fa516fee3b2e66 100644 --- a/Nynja/Extensions/Models/Contact/Contact+DB.swift +++ b/Nynja/Extensions/Models/Contact/Contact+DB.swift @@ -38,7 +38,7 @@ extension Contact { extension Contact: DBModelConvertible { - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return DBContact(contact: self, rosterId: StorageService.sharedInstance.rosterId) } diff --git a/Nynja/Extensions/Models/Job+DB.swift b/Nynja/Extensions/Models/Job+DB.swift index d01e59b571c3c9eb398c69c95929c41cf12f3fe8..e3b94670ffd47dde0c8fdc38179745471bb9f531 100644 --- a/Nynja/Extensions/Models/Job+DB.swift +++ b/Nynja/Extensions/Models/Job+DB.swift @@ -8,7 +8,7 @@ extension Job: DBModelConvertible { - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return DBJob(job: self) } diff --git a/Nynja/Extensions/Models/Member/MemberExtension.swift b/Nynja/Extensions/Models/Member/MemberExtension.swift index 5af8936a1d2198911b20137206a516ee294e377c..ef11c8e04fb8038a73b5db114cfda40952c6bb22 100644 --- a/Nynja/Extensions/Models/Member/MemberExtension.swift +++ b/Nynja/Extensions/Models/Member/MemberExtension.swift @@ -93,7 +93,7 @@ extension Member { } extension Member: DBModelConvertible { - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return DBMember(member: self) } } @@ -104,7 +104,7 @@ extension Array where Element == Member { var contacts: [Contact] { let phoneIds = compactMap { $0.phone_id } - let tempContacts = ContactDAO.fetchContacts(with: phoneIds) + let tempContacts = ContactDAO.fetchPlainContacts(with: phoneIds) var contacts: [Contact] = [] diff --git a/Nynja/Extensions/Models/Message/Message+DB.swift b/Nynja/Extensions/Models/Message/Message+DB.swift index 7f4df71cfdbcd14202b79a77e72a27c3fb70a5c9..87770aade0ff89ee1f652e4dfd2476428038e15e 100644 --- a/Nynja/Extensions/Models/Message/Message+DB.swift +++ b/Nynja/Extensions/Models/Message/Message+DB.swift @@ -121,7 +121,7 @@ extension Message: DBModelConvertible { return DBMessage(message: self) } - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return dbMessage } } diff --git a/Nynja/Extensions/Models/ProfileExtension.swift b/Nynja/Extensions/Models/ProfileExtension.swift index b2d0014832c9786c3b421502bdee99ca883e8db1..6b633fe577195c740e822460c3d989e9fd70648f 100644 --- a/Nynja/Extensions/Models/ProfileExtension.swift +++ b/Nynja/Extensions/Models/ProfileExtension.swift @@ -34,7 +34,7 @@ extension Profile { extension Profile: DBModelConvertible { - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return DBProfile(profile: self) } } diff --git a/Nynja/Extensions/Models/Room/Room+DB.swift b/Nynja/Extensions/Models/Room/Room+DB.swift index 7bb5c5631549382b569db5a292046c51e0c3d43f..d229126a0be99561d06aed56094cd1f7650e5adf 100644 --- a/Nynja/Extensions/Models/Room/Room+DB.swift +++ b/Nynja/Extensions/Models/Room/Room+DB.swift @@ -46,7 +46,7 @@ extension Room: DBModelConvertible { return DBRoom(room: self, rosterId: StorageService.sharedInstance.rosterId) } - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return dbRoom } } diff --git a/Nynja/Extensions/Models/Roster+DB.swift b/Nynja/Extensions/Models/Roster+DB.swift index f7485cc7a6de080d67bad4d0fca1bd021ebeb20f..075433a680ba6c3005a0f6600d0ed27ab0445f81 100644 --- a/Nynja/Extensions/Models/Roster+DB.swift +++ b/Nynja/Extensions/Models/Roster+DB.swift @@ -30,7 +30,7 @@ extension Roster { // MARK: - DBModelConvertible extension Roster: DBModelConvertible { - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { guard let profileId = StorageService.sharedInstance.phone else { return nil } diff --git a/Nynja/Extensions/Models/RosterExtension.swift b/Nynja/Extensions/Models/RosterExtension.swift index ddd7a130b8fbb1fe5a824652eb8ddc01e92bc69e..ccb1e2c3bf2e806c992e597ee7bca81539a2470f 100644 --- a/Nynja/Extensions/Models/RosterExtension.swift +++ b/Nynja/Extensions/Models/RosterExtension.swift @@ -6,37 +6,23 @@ // Copyright © 2017 TecSynt Solutions. All rights reserved. // -extension Roster { +extension Roster: FullNameRepresentable { // Returns self contact var myContact: Contact? { // Check that 'contacts' and 'phone' exist - guard let contacts = self.userlist, let phone = self.phone else { - return nil + guard let contacts = self.userlist, + let phoneId = self.phoneId, + let contact = contacts.first(where: { $0.phone_id == phoneId }) else { + return nil } - //Find index of self contact - guard let index = contacts.index(where: { contact in - // Check that 'phoneNumber' exists in contact - guard let phoneNumber = contact.phoneNumber else { - return false - } - - return phone == phoneNumber - }) else { - return nil - } - - let contact = contacts[index] contact.names = self.names contact.surnames = self.surnames contact.avatar = self.avatar + return contact } - - var hasName: Bool { - return names != nil && names != "" - } var phoneId: String? { guard let phone = phone, let rosterId = id else { @@ -45,5 +31,4 @@ extension Roster { return "\(phone)_\(rosterId)" } - } diff --git a/Nynja/Extensions/Models/StarExtension.swift b/Nynja/Extensions/Models/StarExtension.swift index 95cbaf53a88b93451596b8e51355680792934dbf..3317259a779047b308ea3e1285187b8003787896 100644 --- a/Nynja/Extensions/Models/StarExtension.swift +++ b/Nynja/Extensions/Models/StarExtension.swift @@ -116,7 +116,7 @@ extension Star { extension Star: DBModelConvertible { - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return DBStar(star: self) } diff --git a/Nynja/Extensions/Models/StickerPack/StickerPack+DB.swift b/Nynja/Extensions/Models/StickerPack/StickerPack+DB.swift index 34ce67e99a8eb80addcd7be31f6059c8d91d453b..6b46e3f5a939da77d48901e2072abf7e937aaf4d 100644 --- a/Nynja/Extensions/Models/StickerPack/StickerPack+DB.swift +++ b/Nynja/Extensions/Models/StickerPack/StickerPack+DB.swift @@ -23,7 +23,7 @@ extension StickerPack: DBModelConvertible { downloaded = stickerPack.downloaded } - var databaseModel: DBModelProtocol? { + var databaseModel: DBModel? { return DBStickerPack(stickerPack: self) } } diff --git a/Nynja/Extensions/SwiftLibrary/Array/Array+Contact.swift b/Nynja/Extensions/SwiftLibrary/Array/Array+Contact.swift index 6ff167dc82eec1b29f1f105d9464b173705e8402..056a4d9a70f8889c068f4ac83855ceb6f791708d 100644 --- a/Nynja/Extensions/SwiftLibrary/Array/Array+Contact.swift +++ b/Nynja/Extensions/SwiftLibrary/Array/Array+Contact.swift @@ -30,3 +30,10 @@ extension Array where Element == Contact { } } + + +extension Array where Element == Contact.Status { + var strings: [String] { + return self.map { $0.rawValue } + } +} diff --git a/Nynja/FullNameRepresentable.swift b/Nynja/FullNameRepresentable.swift new file mode 100644 index 0000000000000000000000000000000000000000..78560d73c1864cd78d01130a56892acdd9c1598f --- /dev/null +++ b/Nynja/FullNameRepresentable.swift @@ -0,0 +1,36 @@ +// +// FullNameRepresentable.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/1/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +protocol FullNameRepresentable { + var names: String? { get set } + var surnames: String? { get set } + var fullName: String? { get } +} + +extension FullNameRepresentable { + + var fullName: String? { + if let name = self.names, let surname = self.surnames { + if !surname.isEmpty { + return "\(name) \(surname)" + } else { + return name + } + } else if names != nil && surnames == nil { + return names + } else if names == nil && surnames == nil { + return surnames + } + + return nil + } + + var hasName: Bool { + return names != nil && names != "" + } +} diff --git a/Nynja/Generated/LocalizableConstants.swift b/Nynja/Generated/LocalizableConstants.swift index 377325bf81ff6a7be94abcf2f0c3490e69725207..08137e75e9e4ea505aa0513b0cead97fa748a04e 100644 --- a/Nynja/Generated/LocalizableConstants.swift +++ b/Nynja/Generated/LocalizableConstants.swift @@ -1130,7 +1130,7 @@ internal extension String { static var tpTranslation: String { return localizable.tr("Localizable", "tp_translation") } /// Translation failed. Please try again. static var tpTranslationFailed: String { return localizable.tr("Localizable", "tp_translation_failed") } - /// Original and translated messages language is the same. + /// Original and translated message are the same language. static var tpTranslationLanguageIsEqual: String { return localizable.tr("Localizable", "tp_translation_language_is_equal") } /// Transcribe with Google static var transcribe: String { return localizable.tr("Localizable", "transcribe") } diff --git a/Nynja/JobDAO.swift b/Nynja/JobDAO.swift index 560f682c64d775a0f4487dfdfb4cb330cf69fffa..485286a44dc14cbbe7fd4ffb976672422f9563f4 100644 --- a/Nynja/JobDAO.swift +++ b/Nynja/JobDAO.swift @@ -9,8 +9,9 @@ import GRDBCipher class JobDAO: JobDAOProtocol { - + // MARK: - Fetch + static func fetchJob(for serverId: Int64) -> DBJob? { return dbManager.fetch { db in return try DBJob.job(db, serverId: serverId) @@ -18,18 +19,13 @@ class JobDAO: JobDAOProtocol { } static func findJob(by rowId: Int64) -> Job? { - guard let job = dbManager.fetch({ db in - return try DBJob.job(from: db, rowId: rowId) - }) else { - return nil + return dbManager.fetch { db in + return try DBJob.job(from: db, rowId: rowId)?.serverModel } - - return Job(job: job) } static func findJob(for serverId: Int64) -> Job? { - guard let job = fetchJob(for: serverId) else { return nil } - return Job(job: job) + return fetchJob(for: serverId)?.serverModel } static func fetchJobs() -> [DBJob] { @@ -39,14 +35,18 @@ class JobDAO: JobDAOProtocol { } static func fetchJobs(of type: DBJob.JobType) -> [Job] { - let jobs = dbManager.fetch { db in + return dbManager.fetch { db in return try DBJob.jobs(db, type: type) - } - - return jobs.map { Job(job: $0) } + }.serverModels + } + + static func fetchJobs(with args: DBJob.QueryArgs) -> [Job] { + return DAO().fetch(with: args).serverModels } + // MARK: - Delete + static func deleteJobs() { do { let jobs = fetchJobs() @@ -63,5 +63,4 @@ class JobDAO: JobDAOProtocol { try? dbManager.perform(action: .delete, with: jobs) } - } diff --git a/Nynja/JobService.swift b/Nynja/JobService.swift index b7777de5b6d9d765e2f38f6f2edd27cfdc4deaa2..1ccd48c050d1d4219042ce15588a2835da169123 100644 --- a/Nynja/JobService.swift +++ b/Nynja/JobService.swift @@ -16,12 +16,12 @@ class JobService { private static func fetchContacts(for job: Job) -> [Contact] { let ids = job.contactsIds - return ContactDAO.fetchContacts(with: ids) + return ContactDAO.fetchPlainContacts(with: ids) } private static func fetchRooms(for job: Job) -> [Room] { let ids = job.roomsIds - return RoomDAO.fetchRooms(with: ids) + return RoomDAO.fetchPlainRooms(with: ids) } } diff --git a/Nynja/Library/Debug/DebugLogs.swift b/Nynja/Library/Debug/DebugLogs.swift index dd8ea8f2d9f87b569818ba91f6fbc5065fde6ead..28c3c5c28a456a35fb65a29c826cd26b3451b3b8 100644 --- a/Nynja/Library/Debug/DebugLogs.swift +++ b/Nynja/Library/Debug/DebugLogs.swift @@ -9,5 +9,7 @@ import Foundation func deinited(_ object: AnyObject) { - LogService.log(topic: .arc) { "\(type(of: object)) deinited" } + #if !RELEASE + print("\(type(of: object)) deinited") + #endif } diff --git a/Nynja/Library/UI/Extensions/String/StringExtensions.swift b/Nynja/Library/UI/Extensions/String/StringExtensions.swift index f936adddbebab041085673c4053ceaf240cc8da9..75ad7b8a7a1271057033b5c346c0f860e328c1ab 100644 --- a/Nynja/Library/UI/Extensions/String/StringExtensions.swift +++ b/Nynja/Library/UI/Extensions/String/StringExtensions.swift @@ -379,3 +379,10 @@ extension String { self = self.capitalizingFirstLetter() } } + +extension String { + + static func label(withSuffix suffix: String) -> String { + return Bundle.main.bundleIdentifier.appending(suffix) + } +} diff --git a/Nynja/Modules/AddContactByUsername/Interactor/AddContactByUsernameInteractor.swift b/Nynja/Modules/AddContactByUsername/Interactor/AddContactByUsernameInteractor.swift index 21d47a38e4c9670ccbf18447c72b5fbb0104b731..1882fbe249752f3b9d151cbe3f606b526fe5388f 100644 --- a/Nynja/Modules/AddContactByUsername/Interactor/AddContactByUsernameInteractor.swift +++ b/Nynja/Modules/AddContactByUsername/Interactor/AddContactByUsernameInteractor.swift @@ -33,7 +33,7 @@ final class AddContactByUsernameInteractor: AddContactByUsernameInteractorInputP func getContactByUserName(username: String) { searchAction = nil - if let contact = ContactDAO.findContactBy(username: username) { + if let contact = ContactDAO.findPlainContactBy(username: username) { if contact.phoneId == StorageService.sharedInstance.phoneId { presenter.getMyProfile() } else { diff --git a/Nynja/Modules/AddContactViaPhone/Interactor/AddContactViaPhoneInteractor.swift b/Nynja/Modules/AddContactViaPhone/Interactor/AddContactViaPhoneInteractor.swift index b3e89801c91bff6e6a5b8818808218e91989a17f..3e9ba94c05de565a72a78d75bda26f60eee37959 100644 --- a/Nynja/Modules/AddContactViaPhone/Interactor/AddContactViaPhoneInteractor.swift +++ b/Nynja/Modules/AddContactViaPhone/Interactor/AddContactViaPhoneInteractor.swift @@ -36,7 +36,7 @@ final class AddContactViaPhoneInteractor: AddContactViaPhoneInteractorInputProto if storageService.phone == number { presenter.getMyProfile() - } else if let contact = ContactDAO.findContactBy(phone: number) { + } else if let contact = ContactDAO.findPlainContactBy(phone: number) { presenter.getContactByPhoneSuccess(contact: contact) } else { searchAction = { [weak self] in diff --git a/Nynja/Modules/AddParticipants/Interactor/AddParticipantsInteractor.swift b/Nynja/Modules/AddParticipants/Interactor/AddParticipantsInteractor.swift index f059e1ebc7635e31871c74b766c5b4e42cd8f548..74ce1fb7a2fab7820ac4b9b7713e3ce8af8e1be2 100644 --- a/Nynja/Modules/AddParticipants/Interactor/AddParticipantsInteractor.swift +++ b/Nynja/Modules/AddParticipants/Interactor/AddParticipantsInteractor.swift @@ -48,8 +48,7 @@ class AddParticipantsInteractor: BaseInteractor, AddParticipantsInteractorInputP } func getMySelf() -> Contact? { - guard let id = storageService.rosterId, let roster = RosterDAO.findRosterBy(id: id) else { return nil } - return roster.myContact + return ContactDAO.currentContact } func allocateConference() { @@ -135,7 +134,7 @@ class AddParticipantsInteractor: BaseInteractor, AddParticipantsInteractorInputP //MARK: - AddParticipantsInteractorInputProtocol func fetchParticipants(`for` mode: ParticipantsModeType) { - var contacts = ContactDAO.fetchContacts(with: [.friend]) + var contacts = ContactDAO.fetchPlainContacts(with: [.friend]) if mode == .delete || mode == .admins { if let members = members { diff --git a/Nynja/Modules/Call/CallCreatorMediator.swift b/Nynja/Modules/Call/CallCreatorMediator.swift index e82b7d1e3d1b5ca70314bca51d0bef3bef539d0e..c8832cf34f21fc7a6706b48e3e26b09bd46a3e28 100644 --- a/Nynja/Modules/Call/CallCreatorMediator.swift +++ b/Nynja/Modules/Call/CallCreatorMediator.swift @@ -71,5 +71,4 @@ class CallCreatorMediator { return false } - } diff --git a/Nynja/Modules/Channel/SubscribersSelector/Interactor/SubscribersSelectorInteractor.swift b/Nynja/Modules/Channel/SubscribersSelector/Interactor/SubscribersSelectorInteractor.swift index 4aaa35199f62ea08ed4bc30555477e8bb5ae3a62..06301f43a637ad73ed099be61f18d8373bff7aa9 100644 --- a/Nynja/Modules/Channel/SubscribersSelector/Interactor/SubscribersSelectorInteractor.swift +++ b/Nynja/Modules/Channel/SubscribersSelector/Interactor/SubscribersSelectorInteractor.swift @@ -57,7 +57,7 @@ final class SubscribersSelectorInteractor: BaseInteractor, SubscribersSelectorIn private func members(from subscribers: [ChannelSubscriber]) -> [Member] { let ids = subscribers.map { $0.id } return ContactDAO - .fetchContacts(with: ids) + .fetchPlainContacts(with: ids) .map { Member(contact: $0) } } diff --git a/Nynja/Modules/ChannelsList/Interactor/ChannelsListInteractor.swift b/Nynja/Modules/ChannelsList/Interactor/ChannelsListInteractor.swift index 69b2c0e4f4ff0360c59e16746469af58ef17a9b2..dea84c7eaf93c94c30c891952280768aafcebf18 100644 --- a/Nynja/Modules/ChannelsList/Interactor/ChannelsListInteractor.swift +++ b/Nynja/Modules/ChannelsList/Interactor/ChannelsListInteractor.swift @@ -13,24 +13,19 @@ final class ChannelsListInteractor: BaseInteractor, ChannelsListInteractorInputP weak var presenter: ChannelsListInteractorOutputProtocol! private var conversationsProvider: ConversationsProviding + private var storageService: StorageService private var mode: ChannelsListMode private var channels: [Room] = [] private var searchText: String = "" - // MARK: - InitializeInjectable - - struct Dependencies { - let presenter: ChannelsListInteractorOutputProtocol - let conversationsProvider: ConversationsProviding - - let mode: ChannelsListMode - } + // MARK: - Init required init(dependencies: Dependencies) { presenter = dependencies.presenter conversationsProvider = dependencies.conversationsProvider + storageService = dependencies.storageService mode = dependencies.mode } @@ -79,10 +74,16 @@ final class ChannelsListInteractor: BaseInteractor, ChannelsListInteractorInputP //MARK: - Private private func loadChannels() { + guard let rosterId = storageService.rosterId else { + return + } + + let args = ConversationsProviding.FetchingArgs(rosterId: rosterId) + if mode == .all { - channels = conversationsProvider.fetchChannels() - } else { - channels = conversationsProvider.fetchMyChannels() + channels = conversationsProvider.fetchChannels(with: args) + } else if let phoneId = StorageService.sharedInstance.phoneId { + channels = conversationsProvider.fetchMyChannels(with: args, ownerId: phoneId) } } @@ -121,3 +122,16 @@ final class ChannelsListInteractor: BaseInteractor, ChannelsListInteractorInputP } } + +// MARK: - InitializableInjectable + +extension ChannelsListInteractor { + + struct Dependencies { + let presenter: ChannelsListInteractorOutputProtocol + let conversationsProvider: ConversationsProviding + let storageService: StorageService + + let mode: ChannelsListMode + } +} diff --git a/Nynja/Modules/ChannelsList/WireFrame/ChannelsListWireFrame.swift b/Nynja/Modules/ChannelsList/WireFrame/ChannelsListWireFrame.swift index 19077e274e4dff30004b3a1ff3813124256319a3..53436fff261542ca249e626b250bb3a5ade64cc2 100644 --- a/Nynja/Modules/ChannelsList/WireFrame/ChannelsListWireFrame.swift +++ b/Nynja/Modules/ChannelsList/WireFrame/ChannelsListWireFrame.swift @@ -25,6 +25,7 @@ final class ChannelsListWireFrame: ChannelsListWireFrameProtocol { let serviceFactory = ServiceFactory() let messagePayloadParser = serviceFactory.makeMessagePayloadParser() let conversationProvider = serviceFactory.makeConversationsProvider() + let storageService = serviceFactory.makeStorageService() // Module components let view = ChannelsListViewController() @@ -32,6 +33,7 @@ final class ChannelsListWireFrame: ChannelsListWireFrameProtocol { let interactor = ChannelsListInteractor( dependencies: .init(presenter: presenter, conversationsProvider: conversationProvider, + storageService: storageService, mode: mode)) // Connecting diff --git a/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift b/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift index 02aa173111d987dda1e4f5fa6d1a242e6bee4f26..1698753810b5910be5b64dae4f346e5dbacd2721 100644 --- a/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift +++ b/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift @@ -16,6 +16,9 @@ class ChatsListInteractor: BaseInteractor, ChatsListInteractorInputProtocol, Ini private var chats: [Contact] = [] private var searchText: String = "" + private var rosterId: Int64? { + return storageService.rosterId + } // MARK: - InitializeInjectable @@ -61,7 +64,11 @@ class ChatsListInteractor: BaseInteractor, ChatsListInteractorInputProtocol, Ini let contact = Contact(contact: dbContact) chats = updateChatsList(with: contact) } else { - chats = conversationsProvider.fetchChats() + guard let args = rosterId.map({ ConversationsProviding.FetchingArgs(rosterId: $0) }) else { + return + } + + chats = conversationsProvider.fetchChats(with: args) } applyFilter(with: searchText) @@ -71,7 +78,11 @@ class ChatsListInteractor: BaseInteractor, ChatsListInteractorInputProtocol, Ini //MARK: - Private private func fetchChats() { - chats = conversationsProvider.fetchChats() + guard let args = rosterId.map({ ConversationsProviding.FetchingArgs(rosterId: $0) }) else { + return + } + + chats = conversationsProvider.fetchChats(with: args) presenter.didFetch(chats: chats) } diff --git a/Nynja/Modules/ChatsList/WireFrame/ChatsListWireframe.swift b/Nynja/Modules/ChatsList/WireFrame/ChatsListWireframe.swift index 608c9433cb5997956536ebe4d43078ece267b25c..d54d9eb7b2f985efd06d0e5052aa7915e1f59805 100644 --- a/Nynja/Modules/ChatsList/WireFrame/ChatsListWireframe.swift +++ b/Nynja/Modules/ChatsList/WireFrame/ChatsListWireframe.swift @@ -20,7 +20,7 @@ class ChatsListWireFrame: ChatsListWireFrameProtocol { let interactor = ChatsListInteractor( dependencies: .init(storageService: StorageService.sharedInstance, - conversationsProvider: ConversationsProvider())) + conversationsProvider: ServiceFactory().makeConversationsProvider())) self.main = main diff --git a/Nynja/Modules/Contacts/Interactor/ContactsInteractor.swift b/Nynja/Modules/Contacts/Interactor/ContactsInteractor.swift index 5b0a313da3c5f5d86a112a58d55a93e5dbbf2214..bf794f6955c7b1b3881561e1cbd892b976e06fe3 100644 --- a/Nynja/Modules/Contacts/Interactor/ContactsInteractor.swift +++ b/Nynja/Modules/Contacts/Interactor/ContactsInteractor.swift @@ -75,12 +75,12 @@ class ContactsInteractor: BaseInteractor, ContactsInteractorInputProtocol, IoHan //MARK: - Private private func fetchFriends() { - contacts = ContactDAO.fetchContactWithoutSelf() + contacts = ContactDAO.fetchPlainContactsWithoutSelf() showHistory(contacts: contacts) } private func fetchAll() { - contacts = ContactDAO.fetchContacts() + contacts = ContactDAO.fetchPlainContacts() showHistory(contacts: contacts) } diff --git a/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift b/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift index 35f397cf45d22d4cfe248e993ca084f26d5e3181..f1661ea99fcf19f449f17e184386587ac93a53c9 100644 --- a/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift +++ b/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift @@ -22,7 +22,7 @@ class FavoritesPresenter: BasePresenter, FavoritesPresenterProtocol, FavoritesIn } func getStarsSuccess(stars: [Star]) { - self.view.setup(stars: stars) + view.setup(stars: stars) } func showed() { diff --git a/Nynja/Modules/ForwardSelector/Interactor/ForwardSelectorInteractor.swift b/Nynja/Modules/ForwardSelector/Interactor/ForwardSelectorInteractor.swift index 898ef5ea7e6054d6df3e82e1a224cf7ab6db72d9..271f881b91a0ac2d3329fdaadab6cedb4935e72a 100644 --- a/Nynja/Modules/ForwardSelector/Interactor/ForwardSelectorInteractor.swift +++ b/Nynja/Modules/ForwardSelector/Interactor/ForwardSelectorInteractor.swift @@ -33,6 +33,7 @@ final class ForwardSelectorInteractor: BaseInteractor, ForwardSelectorInteractor weak var presenter: ForwardSelectorInteractorOutputProtocol! private var mqttService: MQTTService! private var storageService: StorageService! + private var conversationsProviding: ConversationsProviding! private var contacts: [ForwardTarget]? private var groups: [ForwardTarget]? @@ -111,7 +112,7 @@ final class ForwardSelectorInteractor: BaseInteractor, ForwardSelectorInteractor if let contacts = self.contacts { completion(contacts) } else { - let contacts = ContactDAO.fetchContacts(with: [.friend]) + let contacts = ContactDAO.fetchPlainContacts(with: [.friend]) .map { makeForwardTarget(with: $0) } .sorted(by: sortComparator) @@ -132,12 +133,19 @@ final class ForwardSelectorInteractor: BaseInteractor, ForwardSelectorInteractor } else { let selectedRooms = targets?.groups ?? [] - let groups = RoomDAO.fetchRooms(kind: .group) - .map { room in - let isSelected = selectedRooms.contains(where: { $0.id == room.id }) - return ForwardTarget(content: .room(room), isSelected: isSelected) - } - .sorted(by: sortComparator) + let groups: [ForwardTarget] + if let rosterId = storageService.rosterId { + let args = ConversationsProviding.FetchingArgs(rosterId: rosterId) + groups = conversationsProviding + .fetchGroups(with: args) + .map { room in + let isSelected = selectedRooms.contains(where: { $0.id == room.id }) + return ForwardTarget(content: .room(room), isSelected: isSelected) + } + .sorted(by: sortComparator) + } else { + groups = [] + } self.groups = groups completion(groups) @@ -182,11 +190,13 @@ extension ForwardSelectorInteractor { let presenter: ForwardSelectorInteractorOutputProtocol let mqttService: MQTTService let storageService: StorageService + let conversationsProviding: ConversationsProviding } func inject(dependencies: Dependencies) { presenter = dependencies.presenter mqttService = dependencies.mqttService storageService = dependencies.storageService + conversationsProviding = dependencies.conversationsProviding } } diff --git a/Nynja/Modules/ForwardSelector/WireFrame/ForwardSelectorWireFrame.swift b/Nynja/Modules/ForwardSelector/WireFrame/ForwardSelectorWireFrame.swift index 6df4be8d4deb8e5ddf603d2c7fc477cade26c86a..33e951de6965ab451f7f7fdad9268636f5d34817 100644 --- a/Nynja/Modules/ForwardSelector/WireFrame/ForwardSelectorWireFrame.swift +++ b/Nynja/Modules/ForwardSelector/WireFrame/ForwardSelectorWireFrame.swift @@ -24,7 +24,13 @@ final class ForwardSelectorWireFrame: ForwardSelectorWireFrameProtocol { let view = ForwardSelectorViewController() let presenter = ForwardSelectorPresenter() - let interactorDependencies = ForwardSelectorInteractor.Dependencies(presenter: presenter, mqttService: MQTTService.sharedInstance, storageService: StorageService.sharedInstance) + let serviceFactory = ServiceFactory() + + let interactorDependencies = ForwardSelectorInteractor.Dependencies( + presenter: presenter, + mqttService: serviceFactory.makeMQTTService(), + storageService: serviceFactory.makeStorageService(), + conversationsProviding: serviceFactory.makeConversationsProvider()) let interactor = ForwardSelectorInteractor(mode: mode) // Connecting diff --git a/Nynja/Modules/GroupsList/Interactor/GroupsListInteractor.swift b/Nynja/Modules/GroupsList/Interactor/GroupsListInteractor.swift index c16ee18b592dc3cf72bec06869f27034189d6902..c44ceff9fe342dc75255fd197c952de1cdc05b61 100644 --- a/Nynja/Modules/GroupsList/Interactor/GroupsListInteractor.swift +++ b/Nynja/Modules/GroupsList/Interactor/GroupsListInteractor.swift @@ -16,6 +16,9 @@ class GroupsListInteractor: BaseInteractor, GroupsListInteractorInputProtocol, I private var chats: [Room] = [] private var searchText: String = "" + private var rosterId: Int64? { + return storageService.rosterId + } // MARK: - InitializeInjectable @@ -67,7 +70,11 @@ class GroupsListInteractor: BaseInteractor, GroupsListInteractorInputProtocol, I applyFilter(with: searchText) } } else { - chats = conversationsProvider.fetchGroups() + guard let args = rosterId.map({ ConversationsProviding.FetchingArgs(rosterId: $0) }) else { + return + } + + chats = conversationsProvider.fetchGroups(with: args) applyFilter(with: searchText) } } @@ -75,8 +82,12 @@ class GroupsListInteractor: BaseInteractor, GroupsListInteractorInputProtocol, I //MARK: - Private - private func fetchGroups(_ filter: String? = nil) { - chats = conversationsProvider.fetchGroups() + private func fetchGroups() { + guard let args = rosterId.map({ ConversationsProviding.FetchingArgs(rosterId: $0) }) else { + return + } + + chats = conversationsProvider.fetchGroups(with: args) presenter.didFetch(groups: chats) } diff --git a/Nynja/Modules/GroupsList/WireFrame/GroupsListWireframe.swift b/Nynja/Modules/GroupsList/WireFrame/GroupsListWireframe.swift index 3db6d4df5599742459d5f5299f85c2822cd85f30..e777359cf6142e2f15ca9347b50e74192f2b7147 100644 --- a/Nynja/Modules/GroupsList/WireFrame/GroupsListWireframe.swift +++ b/Nynja/Modules/GroupsList/WireFrame/GroupsListWireframe.swift @@ -15,18 +15,14 @@ class GroupsListWireFrame: GroupsListWireFrameProtocol { func presentGroupsList(navigation: UINavigationController, main: MainWireFrame, animated: Bool) { self.navigation = navigation - self.main = main - - // Dependencies - let conversationsProvider = ConversationsProvider() - + self.main = main // Compomentes let view = GroupsListViewController() let presenter = GroupsListPresenter() let interactor = GroupsListInteractor( dependencies: .init(storageService: StorageService.sharedInstance, - conversationsProvider: ConversationsProvider())) + conversationsProvider: ServiceFactory().makeConversationsProvider())) // Connecting view.presenter = presenter diff --git a/Nynja/Modules/History/Interactor/HistoryInteractor.swift b/Nynja/Modules/History/Interactor/HistoryInteractor.swift index f8cbf74de164f0d80a7cf9cb649cf7df4d6d74a3..efff84e8e800633a75adbc169be687925a82ffcd 100644 --- a/Nynja/Modules/History/Interactor/HistoryInteractor.swift +++ b/Nynja/Modules/History/Interactor/HistoryInteractor.swift @@ -15,6 +15,9 @@ class HistoryInteractor: BaseInteractor, HistoryInteractorInputProtocol, SetInje private var contacts: [Contact] = [] + private var storageService: StorageService { + return StorageService.sharedInstance + } //MARK: - BaseInteractor @@ -67,7 +70,16 @@ class HistoryInteractor: BaseInteractor, HistoryInteractorInputProtocol, SetInje //MARK: - Private private func _fetchHistory() { - contacts = contactsProvider.fetchHistory() + guard let rosterId = storageService.rosterId, + let phoneId = storageService.phoneId else { + return + } + + let args = ContactsProvidingFetchingArgs( + rosterId: rosterId, + phoneId: phoneId) + + contacts = contactsProvider.fetchHistory(with: args) presenter.fetched(contacts: contacts) } } diff --git a/Nynja/Modules/Main/Interactor/MainInteractor.swift b/Nynja/Modules/Main/Interactor/MainInteractor.swift index a2ad1f2ff875ce309d80d06eb4b1542a1a7aa0d2..6952408d4910d14ec40fdfc18eb4f5e874bffc1e 100644 --- a/Nynja/Modules/Main/Interactor/MainInteractor.swift +++ b/Nynja/Modules/Main/Interactor/MainInteractor.swift @@ -10,15 +10,15 @@ import SDWebImage import Intercom class MainInteractor: MainInteractorInputProtocol, EditPhotoDelegate, MQTTServiceDelegate { - func startRinging() { - - } - weak var presenter: MainInteractorOutputProtocol! var contact: Contact? { return ContactDAO.currentContact } + + private var storageService: StorageService { + return StorageService.sharedInstance + } init() { let notificationsSettings = UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil) @@ -80,7 +80,7 @@ class MainInteractor: MainInteractorInputProtocol, EditPhotoDelegate, MQTTServic } func deleteAccount() { - if let phone = StorageService.sharedInstance.phone, phone != "" { + if let phone = storageService.phone, phone != "" { MQTTService.sharedInstance.deleteUser(number: phone) } LogService.log(topic: .db) { return "Clear storage: delete account" } @@ -102,23 +102,33 @@ class MainInteractor: MainInteractorInputProtocol, EditPhotoDelegate, MQTTServic } func updateAvatar(url: URL) { - guard let roster = RosterDAO.currentRoster else { return } - + guard let rosterId = storageService.rosterId else { + return + } + + do { + try updateAvatar(url: url, rosterId: rosterId) + uploadAvatar(with: url, rosterId: rosterId) + } catch { + assertionFailure("Failed to save avatar url for roster with id \(rosterId)") + } + } + + private func updateAvatar(url: URL, rosterId: Int64) throws { + let roster = Roster() + roster.id = rosterId + roster.avatar = url.absoluteString.getShortPath() + try storageService.perform(action: .updateColumns([RosterTable.Column.avatar.title]), with: roster) + } + + private func uploadAvatar(with url: URL, rosterId: Int64) { let sync = SyncFileManager.sharedInstance sync.downloader = AmazonManager.shared - - roster.avatar = url.absoluteString.getShortPath() - do { - try StorageService.sharedInstance.perform(action: .updateColumns([RosterTable.Column.avatar.title]), with: roster) - - SyncFileManager.sharedInstance.saveExternalFileLink(localUrl: url.path) { (ext, progress,request) in - if ext != nil { - if let id = roster.id { - MQTTService.sharedInstance.updateAvatar(id: id, link: String(describing: ext!)) - } - } + SyncFileManager.sharedInstance.saveExternalFileLink(localUrl: url.path) { (ext, progress, request) in + if ext != nil { + MQTTService.sharedInstance.updateAvatar(id: rosterId, link: String(describing: ext!)) } - } catch {} + } } // MARK: MQTT subscribing @@ -143,16 +153,17 @@ class MainInteractor: MainInteractorInputProtocol, EditPhotoDelegate, MQTTServic private func setupIntercom() { Intercom.logout() - guard let roster = RosterDAO.currentRoster else { + + guard let contact = ContactDAO.currentContact else { Intercom.registerUnidentifiedUser() return } - let rand = "\(UIDevice.current.persistentIdentifier)" + let userAttributes = ICMUserAttributes() - let id = roster.id != nil ? "\(roster.phoneId!)" : rand + let id = contact.phone_id ?? "\(UIDevice.current.persistentIdentifier)" Intercom.registerUser(withUserId: id) - userAttributes.name = roster.myContact?.fullName - userAttributes.phone = roster.phone + userAttributes.name = contact.fullName + userAttributes.phone = contact.phoneNumber Intercom.updateUser(userAttributes) } diff --git a/Nynja/Modules/Main/View/MainViewController+Recents.swift b/Nynja/Modules/Main/View/MainViewController+Recents.swift index 8963fb3d5abea932f2ce09d450da457d80a4d00d..3e7a8cb5f9bbc43fbc2fc12214b58e6b29d69211 100644 --- a/Nynja/Modules/Main/View/MainViewController+Recents.swift +++ b/Nynja/Modules/Main/View/MainViewController+Recents.swift @@ -43,15 +43,30 @@ extension MainViewController { // MARK: - Chats func showRecentP2PChats(indexPath: IndexPath?) { - showRecentConversation(indexPath: indexPath, conversations: ConversationsProvider().fetchChats()) + let conversations = fetchConversation( + using: ServiceFactory().makeConversationsProvider().fetchChats(with:)) + showRecentConversation(indexPath: indexPath, conversations: conversations) } func showRecentGroupChats(indexPath: IndexPath?) { - showRecentConversation(indexPath: indexPath, conversations: ConversationsProvider().fetchGroups()) + let conversations = fetchConversation( + using: ServiceFactory().makeConversationsProvider().fetchGroups(with:)) + showRecentConversation(indexPath: indexPath, conversations: conversations) } - + func showRecentChannels(indexPath: IndexPath?) { - showRecentConversation(indexPath: indexPath, conversations: ConversationsProvider().fetchChannels()) + let conversations = fetchConversation( + using: ServiceFactory().makeConversationsProvider().fetchChannels(with:)) + showRecentConversation(indexPath: indexPath, conversations: conversations) + } + + private func fetchConversation(using fetcher: (ConversationsProviding.FetchingArgs) -> [ChatModel]) -> [ChatModel] { + guard let rosterId = StorageService.sharedInstance.rosterId else { + return [] + } + + let args = ConversationsProviding.FetchingArgs(rosterId: rosterId) + return fetcher(args) } private func showRecentConversation(indexPath: IndexPath?, conversations: [ChatModel]) { @@ -86,5 +101,4 @@ extension MainViewController { } } } - } diff --git a/Nynja/Modules/MapSearch/Interactor/MapSearchInteractor.swift b/Nynja/Modules/MapSearch/Interactor/MapSearchInteractor.swift index d49dc2aafdbdca48122f5a88f2a6936d88e602dd..e0ccb32f73f63c19ca84a2d468232012725563db 100644 --- a/Nynja/Modules/MapSearch/Interactor/MapSearchInteractor.swift +++ b/Nynja/Modules/MapSearch/Interactor/MapSearchInteractor.swift @@ -49,6 +49,7 @@ class MapSearchInteractor: MapSearchInteractorInputProtocol { guard let id = StorageService.sharedInstance.rosterId else { return [] } + // TODO: rewrite as SQL script return StarDAO.fetchStars(rosterId: id).values.compactMap { $0.message?.files?.first?.placeId } } diff --git a/Nynja/Modules/Participants/Interactor/ParticipantsInteractor.swift b/Nynja/Modules/Participants/Interactor/ParticipantsInteractor.swift index babd3b0c4482bd136a25a35d649b297d32a50d29..5e2db5099eb3ab2dee089799851f60ee9a6659cd 100644 --- a/Nynja/Modules/Participants/Interactor/ParticipantsInteractor.swift +++ b/Nynja/Modules/Participants/Interactor/ParticipantsInteractor.swift @@ -84,7 +84,7 @@ class ParticipantsInteractor: BaseInteractor, ParticipantsInteractorInputProtoco //MARK: - Private private func loadContacts() { - let contacts = ContactDAO.fetchContacts(with: [.friend, .ban, .banned]) + let contacts = ContactDAO.fetchPlainContacts(with: [.friend, .ban, .banned]) mapToParticipants(contacts) } diff --git a/Nynja/Modules/Profile/Interactor/HomeDataProvider/HomeDataProvider.swift b/Nynja/Modules/Profile/Interactor/HomeDataProvider/HomeDataProvider.swift new file mode 100644 index 0000000000000000000000000000000000000000..eb45e28c1432c39daeea1f881579b20d71c5d98b --- /dev/null +++ b/Nynja/Modules/Profile/Interactor/HomeDataProvider/HomeDataProvider.swift @@ -0,0 +1,20 @@ +// +// HomeDataProvider.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/2/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +protocol HomeDataProvider { + var conversationsProviding: ConversationsProviding { get } + var contactsProviding: ContactsProviding { get } + + var limit: Int { get } + + func fetchChats(rosterId: Int64) -> [Contact] + func fetchGroups(rosterId: Int64) -> [Room] + func fetchHistory(rosterId: Int64, phoneId: String) -> [Contact] + func fetchStars(rosterId: Int64) -> [Star] + func fetchScheduledMessages() -> [ScheduledMessage] +} diff --git a/Nynja/Modules/Profile/Interactor/HomeDataProvider/HomeDataProviderImpl.swift b/Nynja/Modules/Profile/Interactor/HomeDataProvider/HomeDataProviderImpl.swift new file mode 100644 index 0000000000000000000000000000000000000000..876ff879590c389636c0aa6435b2a54889bfe3e4 --- /dev/null +++ b/Nynja/Modules/Profile/Interactor/HomeDataProvider/HomeDataProviderImpl.swift @@ -0,0 +1,119 @@ +// +// HomeDataProviderImpl.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/2/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +final class HomeDataProviderImpl: HomeDataProvider, InitializeInjectable { + let conversationsProviding: ConversationsProviding + let contactsProviding: ContactsProviding + let limit: Int + + required init(dependencies: Dependencies) { + conversationsProviding = dependencies.services.conversationsProviding + contactsProviding = dependencies.services.contactsProviding + limit = dependencies.fields.limit + } + + // MARK: - HomeDataProvider + // MARK: - Conversations + + func fetchChats(rosterId: Int64) -> [Contact] { + let fetcher = conversationsProviding.fetchChats(with:) + return fetchConversations(rosterId: rosterId, fetcher: fetcher) + } + + func fetchGroups(rosterId: Int64) -> [Room] { + let fetcher = conversationsProviding.fetchGroups(with:) + return fetchConversations(rosterId: rosterId, fetcher: fetcher) + } + + private func fetchConversations( + rosterId: Int64, + fetcher: (ConversationsProviding.FetchingArgs) -> [T]) -> [T] { + + let args = makeConversationsProvidingFetchingArgs(rosterId: rosterId) + return fetcher(args) + } + + private func makeConversationsProvidingFetchingArgs(rosterId: Int64) -> ConversationsProviding.FetchingArgs { + return ConversationsProviding.FetchingArgs( + rosterId: rosterId, + onlyUnread: true, + limit: limit) + } + + + // MARK: - History + + func fetchHistory(rosterId: Int64, phoneId: String) -> [Contact] { + let args = makeContactsProvidingFetchingArgs(rosterId: rosterId, phoneId: phoneId) + return contactsProviding.fetchHistory(with: args) + } + + private func makeContactsProvidingFetchingArgs(rosterId: Int64, phoneId: String) -> ContactsProvidingFetchingArgs { + return ContactsProvidingFetchingArgs( + rosterId: rosterId, + phoneId: phoneId, + statuses: [.request, .ignore], + limit: limit) + } + + + // MARK: - Stars + + func fetchStars(rosterId: Int64) -> [Star] { + let args = makeStarQueryArgs(rosterId: rosterId) + return StarDAO.fetchStars(with: args) + } + + private func makeStarQueryArgs(rosterId: Int64) -> RosterRelatedQueryArgs { + return RosterRelatedQueryArgs( + rosterId: rosterId, + args: .init( + limit: limit, + orderingTerms: [Column.created.desc])) + } + + + // MARK: - Jobs + + func fetchScheduledMessages() -> [ScheduledMessage] { + let args = makeDBJobQueryArgs() + + return DAO() + .fetch(with: args) + .serverModels + .map { ScheduledMessage(job: $0) } + } + + private func makeDBJobQueryArgs() -> DBJob.QueryArgs { + return DBJob.QueryArgs( + type: .schedule, + args: .init( + limit: limit, + orderingTerms: [Column.id.desc])) + } +} + + +extension HomeDataProviderImpl { + + struct Dependencies { + let services: Services + let fields: Fields + } + + struct Services { + let conversationsProviding: ConversationsProviding + let contactsProviding: ContactsProviding + } + + struct Fields { + let limit: Int + } +} diff --git a/Nynja/Modules/Profile/Interactor/ProfileInteractor.swift b/Nynja/Modules/Profile/Interactor/ProfileInteractor.swift index 0b73d2bbf27c8549af0f788996db16b08311efc1..613cb6390408365aef6abf6583c3e5b33a4fcaf7 100644 --- a/Nynja/Modules/Profile/Interactor/ProfileInteractor.swift +++ b/Nynja/Modules/Profile/Interactor/ProfileInteractor.swift @@ -15,13 +15,13 @@ class ProfileInteractor: BaseInteractor, ProfileInteractorInputProtocol { var myContact: Contact! var chats: CellModels = [] - var history: CellModels = [] var rooms: CellModels = [] + var history: CellModels = [] var starred: CellModels = [] var scheduled: CellModels = [] + private var homeDataProvider: HomeDataProvider! private var contactsProvider: ContactsProviding! - private var conversationsProvider: ConversationsProviding! private var mqttService: MQTTService! //MARK: - BaseInteractor @@ -101,41 +101,43 @@ fileprivate extension ProfileInteractor { } func fetchChats() { - let models = conversationsProvider - .fetchChats() - .filter { $0.unreadCount > 0 } - - chats = Array(models.prefix(presenter.elemsInSection)) + performIfRosterIdExists { rosterId in + chats = homeDataProvider.fetchChats(rosterId: rosterId) + } } func fetchRooms() { - let models = conversationsProvider - .fetchGroups() - .filter { $0.unreadCount > 0 } + performIfRosterIdExists { rosterId in + rooms = homeDataProvider.fetchGroups(rosterId: rosterId) + } + } + + private func performIfRosterIdExists(_ closure: (Int64) -> Void) { + guard let rosterId = StorageService.sharedInstance.rosterId else { + return + } - rooms = Array(models.prefix(presenter.elemsInSection)) + closure(rosterId) } func fetchHistory() { - let models = contactsProvider.fetchHistory(without: [.request, .ignore]) - history = Array(models.prefix(presenter.elemsInSection)) + performIfRosterIdExists { rosterId in + guard let phoneId = StorageService.sharedInstance.phoneId else { + return + } + + history = homeDataProvider.fetchHistory(rosterId: rosterId, phoneId: phoneId) + } } func fetchStar() { - guard let id = StorageService.sharedInstance.rosterId else { - starred = [Star]() - return + performIfRosterIdExists { rosterId in + starred = homeDataProvider.fetchStars(rosterId: rosterId) } - let stars = StarDAO.fetchStars(rosterId: id).values.sorted { $0.timestamp > $1.timestamp } - starred = Array(stars.prefix(presenter.elemsInSection)) } func fetchScheduledMessages() { - let jobs = JobDAO.fetchJobs(of: .schedule).sorted { $0.id ?? 0 > $1.id ?? 0 } - let scheduledMessages = jobs.map { - ScheduledMessage(job: $0) - } - scheduled = Array(scheduledMessages.prefix(presenter.elemsInSection)) + scheduled = homeDataProvider.fetchScheduledMessages() } func fetchLastEvents() { @@ -159,15 +161,15 @@ fileprivate extension ProfileInteractor { extension ProfileInteractor: SetInjectable { func inject(dependencies: ProfileInteractor.Dependencies) { presenter = dependencies.presenter + homeDataProvider = dependencies.homeDataProvider contactsProvider = dependencies.contactsProvider - conversationsProvider = dependencies.conversationsProvider mqttService = dependencies.mqttService } struct Dependencies { let presenter: ProfileInteractorOutputProtocol + let homeDataProvider: HomeDataProvider let contactsProvider: ContactsProviding - let conversationsProvider: ConversationsProviding let mqttService: MQTTService } } diff --git a/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift b/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift index 119210b333d4166f8356782538a7e9dff47d225b..3e001cd9d92c3d22955b5d6180d71f77b2ddf96a 100644 --- a/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift +++ b/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift @@ -15,27 +15,25 @@ class ProfileWireFrame: ProfileWireFrameProtocol { func presentProfile(navigation: UINavigationController, main: MainWireFrame?) { - // Dependencies - let contactsProvider = ContactsProvider() - let conversationsProvider = ConversationsProvider() - let mqttService = MQTTService.sharedInstance + let serviceFactory = ServiceFactory() // Components let view = ProfileViewController() let presenter = ProfilePresenter() let interactor = ProfileInteractor() - - let interactorDependencies = ProfileInteractor.Dependencies(presenter: presenter, - contactsProvider: contactsProvider, - conversationsProvider: conversationsProvider, - mqttService: mqttService) - let presenterDependencies = ProfilePresenter.Dependencies(view: view, wireFrame: self, interactor: interactor) - let viewDependencies = ProfileViewController.Dependencies(presenter: presenter) - - - interactor.inject(dependencies: interactorDependencies) - presenter.inject(dependencies: presenterDependencies) - view.inject(dependencies: viewDependencies) + + interactor.inject( + dependencies: .init( + presenter: presenter, + homeDataProvider: serviceFactory.makeHomeDataProvider(limit: 5), + contactsProvider: serviceFactory.makeContactsProvider(), + mqttService: serviceFactory.makeMQTTService())) + presenter.inject( + dependencies: .init( + view: view, + wireFrame: self, + interactor: interactor)) + view.inject(dependencies: .init(presenter: presenter)) self.navigation = navigation self.main = main diff --git a/Nynja/Modules/QRCodeReader/Interactor/QRCodeReaderInteractor.swift b/Nynja/Modules/QRCodeReader/Interactor/QRCodeReaderInteractor.swift index 60cf171cd21e43a42267ef7b9f62a73bf58541e6..0f7e8eaaf8aad61fc960c1dcedcddf46a4f070d5 100644 --- a/Nynja/Modules/QRCodeReader/Interactor/QRCodeReaderInteractor.swift +++ b/Nynja/Modules/QRCodeReader/Interactor/QRCodeReaderInteractor.swift @@ -21,7 +21,7 @@ class QRCodeReaderInteractor: QRCodeReaderInteractorInputProtocol, IoHandlerDele currentNumer = number if StorageService.sharedInstance.phone == number { self.presenter.getMyProfile() - } else if let contact = ContactDAO.findContactBy(phone: number) { + } else if let contact = ContactDAO.findPlainContactBy(phone: number) { self.presenter.getContactSuccess(contact: contact) } else { MQTTService.sharedInstance.tryFindContact(number: number, modelReference: .QRCODE) diff --git a/Nynja/Modules/Settings/Privacy/Interactor/PrivacyListInteractor.swift b/Nynja/Modules/Settings/Privacy/Interactor/PrivacyListInteractor.swift index f549baa5662d4f9168704c5ecb33842186b66310..05273084c39acabb3b241d8181889df969bae906 100644 --- a/Nynja/Modules/Settings/Privacy/Interactor/PrivacyListInteractor.swift +++ b/Nynja/Modules/Settings/Privacy/Interactor/PrivacyListInteractor.swift @@ -13,7 +13,7 @@ final class PrivacyListInteractor: BaseInteractor, PrivacyListInteractorInputPr weak var presenter: PrivacyListInteractorOutputProtocol! private var filterText: String? private var contacts: [Contact] { - return ContactDAO.fetchContacts(with: [.banned]) + return ContactDAO.fetchPlainContacts(with: [.banned]) } // MARK: - PrivacyListInteractorInputProtocol diff --git a/Nynja/Modules/Splash/Interactor/SplashInteractor.swift b/Nynja/Modules/Splash/Interactor/SplashInteractor.swift index cec6ce8a9625787480116f4fedbe45c300be8deb..38422a4da00df515ef0039ee9828398006eb6a08 100644 --- a/Nynja/Modules/Splash/Interactor/SplashInteractor.swift +++ b/Nynja/Modules/Splash/Interactor/SplashInteractor.swift @@ -59,9 +59,9 @@ class SplashInteractor: SplashInteractorInputProtocol { } guard storageService.isUserLogined, let phoneId = storageService.phoneId else { - LogService.log(topic: .db) { return """ - Clear storage: hasPhone = \(storageService.hasPhone), hasToken = \(storageService.hasToken), - phoneId = \(storageService.phoneId ?? "none") + LogService.log(topic: .db) { [weak self] in return """ + Clear storage: hasPhone = \(self?.storageService.hasPhone), hasToken = \(self?.storageService.hasToken), + phoneId = \(self?.storageService.phoneId ?? "none") """ } prepareToShowAuth() return @@ -70,16 +70,16 @@ class SplashInteractor: SplashInteractorInputProtocol { LogService.log(topic: .db) { return "Setup DB: Splash" } storageService.setupDatabase(with: phoneId, application: UIApplication.shared) - guard let roster = RosterDAO.currentRoster else { - LogService.log(topic: .db) { return "Clear storage: can't find current roster" } + guard let contact = ContactDAO.currentContact else { + LogService.log(topic: .db) { return "Clear storage: can't find current contact" } prepareToShowAuth() return } - if roster.hasName { + if contact.hasName { presenter.showMain() } else { - presenter.showEditProfile(roster: roster) + presenter.showEditProfile() } } diff --git a/Nynja/Modules/Splash/Presenter/SplashPresenter.swift b/Nynja/Modules/Splash/Presenter/SplashPresenter.swift index 8ea3595dc9c4f78a5e66ac2e7c0b482bb702c4e9..f001fed03c86c84548e7b3b774b7258d4ea5a274 100644 --- a/Nynja/Modules/Splash/Presenter/SplashPresenter.swift +++ b/Nynja/Modules/Splash/Presenter/SplashPresenter.swift @@ -33,8 +33,8 @@ class SplashPresenter: BasePresenter, SplashPresenterProtocol, SplashInteractorO self.wireFrame.showMain() } - func showEditProfile(roster: Roster) { - self.wireFrame.showEditProfile(roster: roster) + func showEditProfile() { + self.wireFrame.showEditProfile() } func showJailbreakAlert(with completion: @escaping () -> Void) { diff --git a/Nynja/Modules/Splash/SplashProtocols.swift b/Nynja/Modules/Splash/SplashProtocols.swift index ba8af6fb133dc989434c5727b011b4be7277699a..93800181eae0cb56ecbd7c2dc4d330be875a2a7d 100644 --- a/Nynja/Modules/Splash/SplashProtocols.swift +++ b/Nynja/Modules/Splash/SplashProtocols.swift @@ -19,7 +19,7 @@ protocol SplashWireFrameProtocol: class { func showAuth() func showTutorial() func showMain() - func showEditProfile(roster: Roster) + func showEditProfile() } protocol SplashViewProtocol: class { @@ -51,7 +51,7 @@ protocol SplashInteractorOutputProtocol: class { func showAuth() func showTutorial() func showMain() - func showEditProfile(roster: Roster) + func showEditProfile() func showJailbreakAlert(with completion: @escaping () -> Void) } diff --git a/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift b/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift index decce33128789c0c43ff81e1b325ae7079533f0d..949955c740463634f2c0eae9538bbb637a592731 100644 --- a/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift +++ b/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift @@ -41,11 +41,7 @@ class SplashWireFrame: SplashWireFrameProtocol { MainWireFrame().presentMain(navigation: navigation!, isRegistered: false, checkSession: true) } - func showEditProfile(roster: Roster) { - guard let contact = roster.myContact else { - assertionFailure("Contact should exist!") - return - } + func showEditProfile() { EditProfileWireFrame().presentEditProfile(navigation: navigation!, isRegistered: true, main: nil) } } diff --git a/Nynja/NotificationManager.swift b/Nynja/NotificationManager.swift index 7b86fdf0a68ffae8a0eedb199e04f95d7ce7b39d..4059601d62ab7155da847a3cc6fadd0c2b30b8b7 100644 --- a/Nynja/NotificationManager.swift +++ b/Nynja/NotificationManager.swift @@ -261,32 +261,29 @@ final class NotificationManager { } private func getContainer(isFromPush: Bool) -> Container? { - guard let message = getMessage(), message.messageStatus != .delete else { + guard let message = getMessage(), + message.messageStatus != .delete, + let phoneId = StorageService.sharedInstance.phoneId else { return nil } let sender = message.from - guard let id = StorageService.sharedInstance.rosterId, let roster = RosterDAO.findRosterBy(id: id) else { return nil } - guard let contacts = roster.userlist else { return nil } - guard let myContactID = roster.myContact?.phone_id else { return nil } - let isCursorInOwn = message.isInOwnChat && message.isCursor - if sender == myContactID && !isCursorInOwn { + if sender == phoneId, !isCursorInOwn { return nil } - var senderContact = contacts.first { (contact) -> Bool in - return contact.phone_id == sender - } - + var senderContact = sender.flatMap { ContactDAO.findContactBy(phoneId: $0) } var room_s: Room? = nil - if let room = roster.roomlist?.first(where: { $0.id == message.to }), - let member = room.allMembersWithoutFilter?.first(where: { $0.phone_id == StorageService.sharedInstance.phoneId }) { + if let room = message.to.flatMap({ RoomDAO.findRoom(by: $0) }), + let member = room.allMembersWithoutFilter?.first(where: { $0.phone_id == phoneId }) { + senderContact = nil room_s = room - if !member.shouldNotify(for: message) { + + guard member.shouldNotify(for: message) else { return nil } } diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Contents.json b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Contents.json deleted file mode 100644 index 406236518a3691f14aec3dae5e95eb318a784dde..0000000000000000000000000000000000000000 --- a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Contents.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon-App-57x57@1x.png", - "scale" : "1x" - }, - { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon-App-57x57@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "50x50", - "idiom" : "ipad", - "filename" : "Icon-Small-50x50@1x.png", - "scale" : "1x" - }, - { - "size" : "50x50", - "idiom" : "ipad", - "filename" : "Icon-Small-50x50@2x.png", - "scale" : "2x" - }, - { - "size" : "72x72", - "idiom" : "ipad", - "filename" : "Icon-App-72x72@1x.png", - "scale" : "1x" - }, - { - "size" : "72x72", - "idiom" : "ipad", - "filename" : "Icon-App-72x72@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "ItunesArtwork@2x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index bb676f8c4bba57356bbeb0848322855fbdefa576..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index beb24e4e21b20d7623fc2e98a3b2f2067e4b0737..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@3x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index ba5bf8699c8433a52d871b9fe9e1380a613abf53..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 8ee922c9d4a256126e532dfde177ba455d054ba4..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index 9c7c309b7f2406db4a4a48b8a9308213798f8fd3..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@3x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index fc202f0686b7a1c916c1294a4b071eac31e105f2..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index beb24e4e21b20d7623fc2e98a3b2f2067e4b0737..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index a8d751472cc9fea2a94a08c51eebe205e11a63ac..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@3x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 2e68bfd69244aed1f418ad8da95e8451ed886350..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-57x57@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index a053209e804005fe0da9ec6caf7a1f1ba057b685..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-57x57@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-57x57@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index be6eb04b7a849fdae7a191125f0306e560f7b3dc..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-57x57@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-60x60@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 2e68bfd69244aed1f418ad8da95e8451ed886350..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-60x60@3x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 098a96998f645e5fedb7e8bd94cde276c18c3e11..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-72x72@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-72x72@1x.png deleted file mode 100644 index 0f2a4f9bfc185a564c57d5cf04494b70ca0d8197..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-72x72@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-72x72@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-72x72@2x.png deleted file mode 100644 index 336135dc0ffd907c1214528403ea0310af9a948d..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-72x72@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-76x76@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 07fe4980249f70a9c266f492741049a9eac74ad8..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-76x76@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 9f7d35a2f2ca582085eb9ae21fa49419897ff444..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-83.5x83.5@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 2008709fa59ab71b591943718f074f3f5472f0c9..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-Small-50x50@1x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-Small-50x50@1x.png deleted file mode 100644 index 392fec50044c22bf63c6fe97073a74499b2271ef..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-Small-50x50@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-Small-50x50@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-Small-50x50@2x.png deleted file mode 100644 index a9a4d33d6d6b9fa76a5ab58137b63fae6ab941d7..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/Icon-Small-50x50@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/ItunesArtwork@2x.png b/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/ItunesArtwork@2x.png deleted file mode 100644 index b3974deb8782eb2991bbb6f659617dd36969b39e..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconChannels.appiconset/ItunesArtwork@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Contents.json b/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Contents.json index 191d433565a1b8bc451e6e434fa4dd0c062dbe12..406236518a3691f14aec3dae5e95eb318a784dde 100644 --- a/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Contents.json +++ b/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Contents.json @@ -149,30 +149,6 @@ "idiom" : "ios-marketing", "filename" : "ItunesArtwork@2x.png", "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "iphone", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@3x.png", - "scale" : "3x" } ], "info" : { diff --git a/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Icon-App-60x60@1x.png b/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Icon-App-60x60@1x.png deleted file mode 100644 index ba5bf8699c8433a52d871b9fe9e1380a613abf53..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Icon-App-60x60@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Icon-App-76x76@3x.png b/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Icon-App-76x76@3x.png deleted file mode 100644 index ca372c421e2455ac4f7d9ada4a2dd634a7f81ddc..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconSpotify.appiconset/Icon-App-76x76@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Contents.json b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Contents.json deleted file mode 100755 index 406236518a3691f14aec3dae5e95eb318a784dde..0000000000000000000000000000000000000000 --- a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Contents.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon-App-57x57@1x.png", - "scale" : "1x" - }, - { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon-App-57x57@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "50x50", - "idiom" : "ipad", - "filename" : "Icon-Small-50x50@1x.png", - "scale" : "1x" - }, - { - "size" : "50x50", - "idiom" : "ipad", - "filename" : "Icon-Small-50x50@2x.png", - "scale" : "2x" - }, - { - "size" : "72x72", - "idiom" : "ipad", - "filename" : "Icon-App-72x72@1x.png", - "scale" : "1x" - }, - { - "size" : "72x72", - "idiom" : "ipad", - "filename" : "Icon-App-72x72@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "ItunesArtwork@2x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index bb676f8c4bba57356bbeb0848322855fbdefa576..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index beb24e4e21b20d7623fc2e98a3b2f2067e4b0737..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@3x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index ba5bf8699c8433a52d871b9fe9e1380a613abf53..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 8ee922c9d4a256126e532dfde177ba455d054ba4..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index 9c7c309b7f2406db4a4a48b8a9308213798f8fd3..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@3x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index fc202f0686b7a1c916c1294a4b071eac31e105f2..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index beb24e4e21b20d7623fc2e98a3b2f2067e4b0737..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index a8d751472cc9fea2a94a08c51eebe205e11a63ac..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@3x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 2e68bfd69244aed1f418ad8da95e8451ed886350..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-57x57@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index a053209e804005fe0da9ec6caf7a1f1ba057b685..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-57x57@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-57x57@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index be6eb04b7a849fdae7a191125f0306e560f7b3dc..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-57x57@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-60x60@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 2e68bfd69244aed1f418ad8da95e8451ed886350..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-60x60@3x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 098a96998f645e5fedb7e8bd94cde276c18c3e11..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-72x72@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-72x72@1x.png deleted file mode 100644 index 0f2a4f9bfc185a564c57d5cf04494b70ca0d8197..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-72x72@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-72x72@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-72x72@2x.png deleted file mode 100644 index 336135dc0ffd907c1214528403ea0310af9a948d..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-72x72@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-76x76@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 07fe4980249f70a9c266f492741049a9eac74ad8..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-76x76@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 9f7d35a2f2ca582085eb9ae21fa49419897ff444..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-83.5x83.5@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 2008709fa59ab71b591943718f074f3f5472f0c9..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-Small-50x50@1x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-Small-50x50@1x.png deleted file mode 100644 index 392fec50044c22bf63c6fe97073a74499b2271ef..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-Small-50x50@1x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-Small-50x50@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-Small-50x50@2x.png deleted file mode 100644 index a9a4d33d6d6b9fa76a5ab58137b63fae6ab941d7..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/Icon-Small-50x50@2x.png and /dev/null differ diff --git a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/ItunesArtwork@2x.png b/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/ItunesArtwork@2x.png deleted file mode 100644 index b3974deb8782eb2991bbb6f659617dd36969b39e..0000000000000000000000000000000000000000 Binary files a/Nynja/Resources/Assets.xcassets/AppIconStickers.appiconset/ItunesArtwork@2x.png and /dev/null differ diff --git a/Nynja/Resources/Info.plist b/Nynja/Resources/Info.plist index dda23f3845685fd71c2ec1b987e5b0f5db50a1cf..d4fda774a3efb9dce590ab6ac2776c06b050e7a9 100644 --- a/Nynja/Resources/Info.plist +++ b/Nynja/Resources/Info.plist @@ -23,7 +23,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 0.5.4.Dev + 0.5.4.Load ConfServerAddress $(ConfServerAddress) ConfServerPort diff --git a/Nynja/Resources/LoadDBConfig.xcconfig b/Nynja/Resources/LoadDBConfig.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..7b7891380aaca508808afbf6d17043c8406f720e --- /dev/null +++ b/Nynja/Resources/LoadDBConfig.xcconfig @@ -0,0 +1,20 @@ +// +// LoadDBConfig.xcconfig +// Nynja +// +// Created by Anton Makarov on 10/24/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +BundleIdentifier = com.nynja.dev.mobile.communicator +ExtensionBundleIdentifier = com.nynja.dev.mobile.communicator.NynjaShare +ServerURL = loaddb.ci.nynja.net +AppName = NYNJALoad +ServerPort = 1883 +Config = dev +AppGroup = group.com.nynja.mobile.communicator.dev +ModelsVersion = 10 +isServerConnectionSecure = false +ConfServerAddress = 35.198.118.190 +ConfServerPort = 80 +ConfServerSecure = false diff --git a/Nynja/Resources/ThirdPartyServices.swift b/Nynja/Resources/ThirdPartyServices.swift index 7bb8ffee29b93bfca549906912c96665dfa87d7f..e86091ba90a5c5c7494da62b043076a4696c4662 100644 --- a/Nynja/Resources/ThirdPartyServices.swift +++ b/Nynja/Resources/ThirdPartyServices.swift @@ -22,6 +22,7 @@ enum AppConfig: String { case devAutoTests case prerelease case release + case loadDB case spotify } @@ -46,7 +47,7 @@ struct AmazonService: ThirdPartyService { init(config: AppConfig) { switch config { - case .dev, .devAutoTests, .spotify: + case .dev, .devAutoTests, .loadDB, .spotify: serviceConfig = Config(accessKey: "AKIAIVFYOPZSACBLBBSA", secretKey: "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", defaultBucketName: "nynja-defaults", @@ -75,7 +76,7 @@ struct GoogleService: ThirdPartyService { init(config: AppConfig) { switch config { - case .dev, .devAutoTests, .spotify: serviceConfig = Config(apiKey: "AIzaSyCAi5Ea_zkYzbIARCqfMMrq4NOy935BltA") + case .dev, .devAutoTests, .loadDB, .spotify: serviceConfig = Config(apiKey: "AIzaSyCAi5Ea_zkYzbIARCqfMMrq4NOy935BltA") case .prerelease: serviceConfig = Config(apiKey: "AIzaSyCAi5Ea_zkYzbIARCqfMMrq4NOy935BltA") case .release: serviceConfig = Config(apiKey: "AIzaSyCAi5Ea_zkYzbIARCqfMMrq4NOy935BltA") } @@ -92,7 +93,7 @@ struct IntercomService: ThirdPartyService { init(config: AppConfig) { switch config { - case .dev, .devAutoTests, .spotify: serviceConfig = Config(apiKey: "ios_sdk-3f0f8a4f52e4ed08a2bf6f1a39a1e9eb8b0763d5", appId: "s3isdm0n") + case .dev, .devAutoTests, .loadDB, .spotify: serviceConfig = Config(apiKey: "ios_sdk-3f0f8a4f52e4ed08a2bf6f1a39a1e9eb8b0763d5", appId: "s3isdm0n") case .prerelease: serviceConfig = Config(apiKey: "ios_sdk-3f0f8a4f52e4ed08a2bf6f1a39a1e9eb8b0763d5", appId: "s3isdm0n") case .release: serviceConfig = Config(apiKey: "ios_sdk-3f0f8a4f52e4ed08a2bf6f1a39a1e9eb8b0763d5", appId: "s3isdm0n") } @@ -112,7 +113,7 @@ struct SupportService: ThirdPartyService { init(config: AppConfig) { switch config { - case .dev, .devAutoTests, .spotify: serviceConfig = Config(mailAddress: "support@nynja.biz", + case .dev, .devAutoTests, .loadDB, .spotify: serviceConfig = Config(mailAddress: "support@nynja.biz", faq: URL(string: "https://landing.nynja.io/-temporary-slug-81be145c-f4aa-4787-8d71-b3ab51a1aef2?hs_preview=XOrlQzBx-6108791186")!, privacyPolicy: URL(string: "https://landing.nynja.io/privacy-policy")!, terms: URL(string:"https://landing.nynja.io/terms-of-use")!) @@ -139,7 +140,7 @@ struct TestFairyService: ThirdPartyService { init(config: AppConfig) { switch config { - case .dev, .devAutoTests, .spotify: serviceConfig = Config(key: "4e58695a5ce5ee4ccddbb4b852d3927626f7da36") + case .dev, .devAutoTests, .loadDB, .spotify: serviceConfig = Config(key: "4e58695a5ce5ee4ccddbb4b852d3927626f7da36") case .prerelease: serviceConfig = Config(key: "4e58695a5ce5ee4ccddbb4b852d3927626f7da36") case .release: serviceConfig = Config(key: "4e58695a5ce5ee4ccddbb4b852d3927626f7da36") } diff --git a/Nynja/RoomDAO.swift b/Nynja/RoomDAO.swift index 7ceca3d9fba26cd75333584b3eeaf5e62c1873c7..6a4612ff9ff720e9c14310a64794ca2cf5d5a918 100644 --- a/Nynja/RoomDAO.swift +++ b/Nynja/RoomDAO.swift @@ -16,6 +16,7 @@ class RoomDAO: RoomDAOProtocol { // MARK: - Fetch // MARK: -- Room + static func fetchRoom(by rowId: Int64) -> DBRoom? { return dbManager.fetch { db in return try DBRoom.room(from: db, rowId: rowId) @@ -33,37 +34,24 @@ class RoomDAO: RoomDAOProtocol { return Room(room: dbRoom) } - // MARK: -- Rooms - static func fetchRooms(kind: Room.Kind? = nil) -> [Room] { - guard let rosterId = StorageService.sharedInstance.rosterId else { - return [] - } - - let rooms = dbManager.fetch { db -> [DBRoom] in - return try DBRoom.rooms(db, rosterId: rosterId, type: kind?.rawValue) - } - - return rooms.map { Room(room: $0) } - } + // MARK: -- Rooms - static func fetchRooms(with ids: [String], kind: Room.Kind? = nil) -> [Room] { - let rooms = dbManager.fetch { db -> [DBRoom] in + static func fetchPlainRooms(with ids: [String], kind: Room.Kind? = nil) -> [Room] { + return dbManager.fetch { db -> [DBRoom] in return try DBRoom.rooms(db, ids: ids, type: kind?.rawValue) - } - - return rooms.map { Room(room: $0) } + }.serverModels } - static func fetchUserRooms(with contactId: String, isAdmin: Bool, kind: Room.Kind?) -> [Room] { - let rooms = dbManager.fetch { db in - return try DBRoom.rooms(db, contactId: contactId, isAdmin: isAdmin, type: kind?.rawValue) - } - - return rooms.map { Room(room: $0) } + static func fetchPlainRooms(with args: DBRoom.RequestArgs) -> [Room] { + return dbManager.fetch { db in + return try DBRoom.rooms(db, args: args) + }.serverModels } + // MARK: -- Reader + static func fetchReader(for roomId: String, kind: ReaderKind) -> Int64? { if kind == .other { return dbManager.fetch { db in diff --git a/Nynja/RoomDAOProtocol.swift b/Nynja/RoomDAOProtocol.swift index 8256c6e3b0d38c342fd3f49fea32f77ccc7c2107..15da8a2214d3e6488c02ec8baafa04ac42b30e54 100644 --- a/Nynja/RoomDAOProtocol.swift +++ b/Nynja/RoomDAOProtocol.swift @@ -10,30 +10,39 @@ protocol RoomDAOProtocol: DAOProtocol { // MARK: - Fetch // MARK: -- Room + static func fetchRoom(by rowId: Int64) -> DBRoom? static func fetchRoom(by id: String) -> DBRoom? static func findRoom(by id: String) -> Room? + // MARK: -- Rooms - static func fetchRooms(kind: Room.Kind?) -> [Room] - static func fetchRooms(with ids: [String], kind: Room.Kind?) -> [Room] - static func fetchUserRooms(with contactId: String, isAdmin: Bool, kind: Room.Kind?) -> [Room] + + static func fetchPlainRooms(with ids: [String], kind: Room.Kind?) -> [Room] + static func fetchPlainRooms(with args: DBRoom.RequestArgs) -> [Room] + // MARK: -- Reader + static func fetchReader(for roomId: String, kind: ReaderKind) -> Int64? + // MARK: - Update // MARK: -- Room + static func patchRoom(_ room: Room) static func updateColumns(_ columns: Set, room: Room) + // MARK: -- Fields + static func updateReader(_ reader: Int64, roomId: String, phoneId: String, kind: ReaderKind) static func updatedMentions(with message: Message, roomId: String) -> UpdateResult<[MessageServerId]> static func isCurrentUserMentioned(in message: Message, phoneId: String) -> Bool + // MARK: - Contains Members - static func containsMembers(with ids: [Int64], roomId: String) -> Bool? + static func containsMembers(with ids: [Int64], roomId: String) -> Bool? } diff --git a/Nynja/RosterDAO.swift b/Nynja/RosterDAO.swift index 514e7ecc58bcbb589c35ba4812b0025680a02268..60dea23223044f20b461ce882dfab4cfae5e8b40 100644 --- a/Nynja/RosterDAO.swift +++ b/Nynja/RosterDAO.swift @@ -16,7 +16,7 @@ class RosterDAO: RosterDAOProtocol { return Roster(roster: roster) } - static var currentDBRoster: DBRoster? { + private static var currentDBRoster: DBRoster? { guard let id = StorageService.sharedInstance.rosterId else { return nil } return fetchRosterBy(id: id) } @@ -37,5 +37,4 @@ class RosterDAO: RosterDAOProtocol { guard let roster = fetchRosterBy(id: id) else { return nil } return Roster(roster: roster) } - } diff --git a/Nynja/RosterDAOProtocol.swift b/Nynja/RosterDAOProtocol.swift index f3d36e82422b564d962faa3e3d278f9c2e9c3f2f..6615f93cc7e8e4ff0fb3475bce22fe5619db6218 100644 --- a/Nynja/RosterDAOProtocol.swift +++ b/Nynja/RosterDAOProtocol.swift @@ -10,11 +10,9 @@ protocol RosterDAOProtocol: DAOProtocol { // MARK: - Fetch static var currentRoster: Roster? { get } - static var currentDBRoster: DBRoster? { get } static func fetchRosterBy(rowId: Int64) -> DBRoster? static func fetchRosterBy(id: Int64) -> DBRoster? static func findRosterBy(id: Int64) -> Roster? - } diff --git a/Nynja/ServerModel/SercerModelConvertible.swift b/Nynja/ServerModel/SercerModelConvertible.swift new file mode 100644 index 0000000000000000000000000000000000000000..99c695c191499d8cb0324dbdd3cc502faf50f01e --- /dev/null +++ b/Nynja/ServerModel/SercerModelConvertible.swift @@ -0,0 +1,19 @@ +// +// SercerModelConvertible.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 11/7/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +protocol ServerModelConvertible { + associatedtype ServerModel + var serverModel: ServerModel { get } +} + +extension Array where Element: ServerModelConvertible { + + var serverModels: [Element.ServerModel] { + return self.map { $0.serverModel } + } +} diff --git a/Nynja/Services/Audio/AudioSessionManager/AudioSessionManager.swift b/Nynja/Services/Audio/AudioSessionManager/AudioSessionManager.swift index 3ec40b6522dcc33b60ac95d33e97aa4ee7d639d8..bf34a7ce33fd5ea9644b2e52a52caf227e4975c6 100644 --- a/Nynja/Services/Audio/AudioSessionManager/AudioSessionManager.swift +++ b/Nynja/Services/Audio/AudioSessionManager/AudioSessionManager.swift @@ -172,7 +172,7 @@ final class AudioSessionManager { LogService.log(topic: .audioSystem) { return "audioSessionRouteChange reason oldDeviceUnavailable" } case .categoryChange: LogService.log(topic: .audioSystem) { return "audioSessionRouteChange reason categoryChange" } - LogService.log(topic: .audioSystem) { return "AVAudioSession Category: \(session.category)" } + LogService.log(topic: .audioSystem) {[weak self] in return "AVAudioSession Category: \(self?.session.category)" } case .override: LogService.log(topic: .audioSystem) { return "audioSessionRouteChange reason override" } case .wakeFromSleep: diff --git a/Nynja/Services/Debug/LogService/LogService/LogService.swift b/Nynja/Services/Debug/LogService/LogService/LogService.swift index 68538a764dafde965a501f491c91fb02d34d31e0..375961628225c84e69cf0f1251bcf2335e336093 100644 --- a/Nynja/Services/Debug/LogService/LogService/LogService.swift +++ b/Nynja/Services/Debug/LogService/LogService/LogService.swift @@ -9,22 +9,28 @@ import Foundation import os.log -class LogService { +final class LogService { - static var enabledTopics: [LogServiceTopic] = [.userDefaults, .wallet, .keychain, .fileSystem, - .audioSystem, .MQTT, .amazon, .callSystem, .locationSystem, + private static let logWriter: LogWriterProtocol? = ServiceFactory().makeLogWriter() + + private static var enabledTopics: [LogServiceTopic] = [.userDefaults, .wallet, .keychain, .fileSystem, + .audioSystem, .MQTT, .db, .amazon, .callSystem, .locationSystem, .system, .network, .galery, .videoConverter, .QRCode, - .passphrase, .arc, .connectionState] + .passphrase, .connectionState] + + private static let backgroundQueue = DispatchQueue(label:"logQueue",qos:.background) - static func log(topic: LogServiceTopic, block: () -> String) { + static func log(topic: LogServiceTopic, block: (() -> String)?) { #if !RELEASE + backgroundQueue.async { if !enabledTopics.contains(topic) { return } - LogService.executeLogs(topic: topic, text: block(), thread: Thread.current.debugDescription) + LogService.executeLogs(topic: topic, text: block?() ?? "", thread: Thread.current.debugDescription) + } #endif } private static func executeLogs(topic: LogServiceTopic, text: String, thread: String) { - LogWriter.shared?.writeLog(topic: topic.rawValue, description: text, thread: thread) + logWriter?.writeLog(topic: topic.rawValue, description: text, thread: thread) printToLog(topic: topic, text: text, thread: thread) } diff --git a/Nynja/Services/Debug/LogService/LogService/LogServiceProtocol.swift b/Nynja/Services/Debug/LogService/LogService/LogServiceProtocol.swift index 5f6c98b232e5efef35f71955b131f85043a5cb31..94822e1a55ea2000a896182971d64746dcb3db98 100644 --- a/Nynja/Services/Debug/LogService/LogService/LogServiceProtocol.swift +++ b/Nynja/Services/Debug/LogService/LogService/LogServiceProtocol.swift @@ -10,3 +10,4 @@ protocol LogServiceProtocol { static var enabledTopics: [LogServiceTopic] { get } static func log(topic: LogServiceTopic, block: () -> String) } + diff --git a/Nynja/Services/Debug/LogService/LogService/LogServiceStub.swift b/Nynja/Services/Debug/LogService/LogService/LogServiceStub.swift deleted file mode 100644 index a2155916c99dce700a0241f59ebd549d71b2916a..0000000000000000000000000000000000000000 --- a/Nynja/Services/Debug/LogService/LogService/LogServiceStub.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// LogServiceStub.swift -// Nynja -// -// Created by Volodymyr Hryhoriev on 10/2/18. -// Copyright © 2018 TecSynt Solutions. All rights reserved. -// - -/// In order to fix errors in test targets -class LogService: LogServiceProtocol { - static let enabledTopics: [LogServiceTopic] = [] - static func log(topic: LogServiceTopic, block: () -> String) {} -} diff --git a/Nynja/Services/Debug/LogService/LogService/LogServiceTopic.swift b/Nynja/Services/Debug/LogService/LogService/LogServiceTopic.swift index 96e71c63739af9004f99b6800f5a24fb382747d6..550f7724b6a39a62c70eb6141c94798826e38157 100644 --- a/Nynja/Services/Debug/LogService/LogService/LogServiceTopic.swift +++ b/Nynja/Services/Debug/LogService/LogService/LogServiceTopic.swift @@ -24,13 +24,12 @@ enum LogServiceTopic: String { case passphrase = "Passphrase" case push = "Push notification" case userDefaults = "User Defaults" - case arc = "ARC" case connectionState = "Connection State" static let allValues: [LogServiceTopic] = [.userDefaults, .wallet, .keychain, .fileSystem, .db, .audioSystem, .MQTT, .amazon, .callSystem, .locationSystem, .system, .network, .galery, .videoConverter, .QRCode, - .passphrase, .arc, .connectionState] + .passphrase, .connectionState] static var allValuesStrings: String { return allValues.reduce("") { (result, topic) -> String in diff --git a/Nynja/Services/Debug/LogService/LogService/LogWriterProtocol.swift b/Nynja/Services/Debug/LogService/LogService/LogWriterProtocol.swift new file mode 100644 index 0000000000000000000000000000000000000000..d496f9b351ebe93901c02212779ab9b018bfe2ec --- /dev/null +++ b/Nynja/Services/Debug/LogService/LogService/LogWriterProtocol.swift @@ -0,0 +1,13 @@ +// +// LogWriterProtocol.swift +// Nynja +// +// Created by Anton Makarov on 10/25/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +protocol LogWriterProtocol: class { + func writeLog(topic: String, description: String, thread: String) +} diff --git a/Nynja/Services/Debug/LogService/LogWriter.swift b/Nynja/Services/Debug/LogService/LogWriter.swift index 1a1453996317c2eddf70009f308f09ba730dcfd6..01f2ce91e57531817b1c4ad3d20eddd3ecca0b5d 100644 --- a/Nynja/Services/Debug/LogService/LogWriter.swift +++ b/Nynja/Services/Debug/LogService/LogWriter.swift @@ -8,7 +8,7 @@ import Foundation -class LogWriter { +final class LogWriter: LogWriterProtocol { static let shared: LogWriter? = LogWriter() diff --git a/Nynja/Services/HandleServices/ProfileHandler.swift b/Nynja/Services/HandleServices/ProfileHandler.swift index d2d68a05cd793a71650300a0c934c2a3ae184792..a1fa7952fe9081226a9af0f2401170d744765552 100644 --- a/Nynja/Services/HandleServices/ProfileHandler.swift +++ b/Nynja/Services/HandleServices/ProfileHandler.swift @@ -74,7 +74,7 @@ class ProfileHandler: BaseHandler { return } configureTestFairy(with: roster) - configureNynjaCommunicatorService(profile) + configureNynjaCommunicatorService(with: roster) requestJobs(with: phoneId) requestStickerPacks(with: phoneId) @@ -147,11 +147,14 @@ class ProfileHandler: BaseHandler { } private static func configureTestFairy(with roster: Roster) { - TestFairy.setUserId("\(roster.myContact?.phone_id ?? "")_\(roster.myContact?.fullName ?? "")") + let phoneId = roster.phoneId ?? "" + let fullName = roster.fullName ?? "" + let userId = "\(phoneId)_\(fullName)" + TestFairy.setUserId(userId) } - private static func configureNynjaCommunicatorService(_ profile: Profile) { - guard let rosterId = (profile.rosters?.first as? Roster)?.myContact?.phone_id else { + private static func configureNynjaCommunicatorService(with roster: Roster) { + guard roster.phoneId != nil else { return } diff --git a/Nynja/Services/HandleServices/RoomHandler.swift b/Nynja/Services/HandleServices/RoomHandler.swift index 6193bb93165b4f1981a579924b9920c7061b479d..8fb79ae803777d963533eddb3dd99c0c1c41179b 100644 --- a/Nynja/Services/HandleServices/RoomHandler.swift +++ b/Nynja/Services/HandleServices/RoomHandler.swift @@ -205,7 +205,7 @@ class RoomHandler: BaseHandler { oldRoom.readers = room.readers oldRoom.originalStatus = .get - oldRoom.unread = 0 + oldRoom.unread = 0 // TODO: need to check. try? storageService.perform(action: .save, with: oldRoom) } } diff --git a/Nynja/Services/HandleServices/RosterHandler.swift b/Nynja/Services/HandleServices/RosterHandler.swift index 419d89e79e2b9b98e44842f63957df0f916714d3..51ac27f172177e39d11e19f2baa952a2300e6ff1 100644 --- a/Nynja/Services/HandleServices/RosterHandler.swift +++ b/Nynja/Services/HandleServices/RosterHandler.swift @@ -17,12 +17,7 @@ class RosterHandler: BaseHandler { } if status == "patch" || status == "nick" { - if let currentRoster = RosterDAO.currentRoster { - roster.favorite = currentRoster.favorite - } - try? StorageService.sharedInstance.perform(action: .save, with: roster) } } - } diff --git a/Nynja/Services/MQTT/MQTTService.swift b/Nynja/Services/MQTT/MQTTService.swift index b3639a0f79a4ecd7bc13b08fd60e49cf29d70cc6..12002089518a4e267140700d759c08924b9d1c24 100644 --- a/Nynja/Services/MQTT/MQTTService.swift +++ b/Nynja/Services/MQTT/MQTTService.swift @@ -158,7 +158,9 @@ final class MQTTService: NSObject, CocoaMQTTDelegate, ConnectionServiceDelegate autoReconnectTimeInterval = 15 - LogService.log(topic: .MQTT) { return "setup clientID: \(mqtt?.clientID ?? "") & password: \(mqtt?.password ?? "")" } + LogService.log(topic: .MQTT) { [weak self] in + return "setup clientID: \(self?.mqtt?.clientID ?? "") & password: \(self?.mqtt?.password ?? "")" + } } func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) { diff --git a/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift b/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift index 8636a192b621c4bc6315495a8764bf3eda201f45..526cd7e54b131159ba603208a08be1f776c47146 100644 --- a/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift +++ b/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift @@ -467,8 +467,7 @@ class NynjaCommunicatorService: NSObject, NynjaCommunicatorDelegate, NYNCallDele //MARK: Helpers func getMySelf() -> Contact? { - guard let id = StorageService.sharedInstance.rosterId, let roster = RosterDAO.findRosterBy(id: id) else { return nil } - return roster.myContact + return ContactDAO.currentContact } func makeMembers(contacts: [Contact], room: Room?) -> [Member] { diff --git a/Nynja/Services/ServiceFactory/ServiceFactory.swift b/Nynja/Services/ServiceFactory/ServiceFactory.swift index f581ec61b326b571744b34cbedbdcf94e48afb35..99adf6859ee2ef4e9c5c40800578c4a851a22cd0 100644 --- a/Nynja/Services/ServiceFactory/ServiceFactory.swift +++ b/Nynja/Services/ServiceFactory/ServiceFactory.swift @@ -47,6 +47,8 @@ protocol ServiceFactoryProtocol: SharedServiceFactoryProtocol { func makeUseCaseValidationServise() -> UseCaseValidationServiceProtocol func makeAudioSessionManager() -> AudioSessionManager + + func makeHomeDataProvider(limit: Int) -> HomeDataProvider } final class ServiceFactory: SharedServiceFactory, ServiceFactoryProtocol { @@ -100,13 +102,13 @@ final class ServiceFactory: SharedServiceFactory, ServiceFactoryProtocol { } func makeConversationsProvider() -> ConversationsProviding { - return ConversationsProvider() + return ConversationsProvider( + dependencies: .init(dbManager: makeStorageService())) } func makeStickersProvider() -> StickersProviding { return StickersProvider( - dependencies: .init(storage: makeStorageService()) - ) + dependencies: .init(storage: makeStorageService())) } func makePermissionManager() -> PermissionManager { @@ -169,4 +171,15 @@ final class ServiceFactory: SharedServiceFactory, ServiceFactoryProtocol { func makeAudioSessionManager() -> AudioSessionManager { return AudioSessionManager.shared } + + func makeHomeDataProvider(limit: Int) -> HomeDataProvider { + return HomeDataProviderImpl( + dependencies: .init( + services: .init( + conversationsProviding: makeConversationsProvider(), + contactsProviding: makeContactsProvider() + ), + fields: .init( + limit: limit))) + } } diff --git a/Nynja/Services/StorageService.swift b/Nynja/Services/StorageService.swift index 9ef71ae31dc8f7c563b4e79dca10c6b262092e9a..ec1b3ea6b96a2227d146911a0a38fd38f5d7e6a5 100644 --- a/Nynja/Services/StorageService.swift +++ b/Nynja/Services/StorageService.swift @@ -80,7 +80,7 @@ class StorageService { application: application) keychain.set(newPassphrase, forKey: passphraseKey) - LogService.log(topic: .passphrase) { return "Store new passphrase: \(keychain.string(forKey: passphraseKey))" } + LogService.log(topic: .passphrase) {[weak self] in return "Store new passphrase: \(self?.keychain.string(forKey: self?.passphraseKey ?? ""))" } } private func setupInsecureDatabase(with name: String, application: UIApplication) { @@ -134,7 +134,7 @@ extension StorageService: DBManagerProtocol { try databaseManager.perform(action: action, with: model) } - func perform(action: DatabaseAction, with model: DBModelProtocol) throws { + func perform(action: DatabaseAction, with model: DBModel) throws { try databaseManager.perform(action: action, with: model) } @@ -142,7 +142,7 @@ extension StorageService: DBManagerProtocol { try databaseManager.perform(action: action, with: models) } - func perform(action: DatabaseAction, with models: [DBModelProtocol]) throws { + func perform(action: DatabaseAction, with models: [DBModel]) throws { try databaseManager.perform(action: action, with: models) } diff --git a/Nynja/StarActionDAO.swift b/Nynja/StarActionDAO.swift index ca97857e44a245c3c6390b2861d8b42574a92e43..21c2585c7bce8cf1b1a6734ea95991c5e66346dc 100644 --- a/Nynja/StarActionDAO.swift +++ b/Nynja/StarActionDAO.swift @@ -24,7 +24,7 @@ final class StarActionDAO: StarActionDAOProtocol { } return dbManager.rowExists( in: StarActionTable.self, - where: "\(StarActionTable.Column.starId) = ?", + where: "\(Column.starId) = ?", arguments: [starLocalId] ) } diff --git a/Nynja/StarDAO.swift b/Nynja/StarDAO.swift index 239ee47573a898f8d07b775032cbdc0b23212710..44bac7df4522f02c5a79d75072ec76551365e026 100644 --- a/Nynja/StarDAO.swift +++ b/Nynja/StarDAO.swift @@ -6,24 +6,35 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // +import GRDBCipher + class StarDAO: StarDAOProtocol { // MARK: - Fetch + static func fetchStarBy(rowId: Int64) -> DBStar? { return dbManager.fetch { db in - return try DBStar.star(db, rowId: rowId) + return try DBStar + .filter(Column.rowID == rowId) + .fetchOneConstructed(db) } } static func fetchStarBy(clientId: String) -> DBStar? { return dbManager.fetch { db in - return try DBStar.star(db, clientId: clientId) + return try DBStar + .filter(Column.clientId == clientId) + .fetchOneConstructed(db) } } static func fetchStars(rosterId: Int64) -> [String: Star] { - let stars = dbManager.fetch { db in - return try DBStar.stars(from: db, rosterId: rosterId) + let stars = dbManager.fetch { db -> [DBStar] in + let args = RosterRelatedQueryArgs(rosterId: rosterId) + return try args + .makeTypedRequest() + .filter(Column.status !== Star.Status.remove.rawValue) + .fetchAllConstructed(db) } var result: [String: Star] = [:] @@ -37,9 +48,21 @@ class StarDAO: StarDAOProtocol { return result } + static func fetchStars(with args: RosterRelatedQueryArgs) -> [Star] { + return dbManager.fetch { db in + return try args + .makeTypedRequest() + .filter(Column.status !== Star.Status.remove.rawValue) + .fetchAllConstructed(db) + }.serverModels + } + static func fetchUndeliveredStars(rosterId: Int64) -> [Star] { - return dbManager - .fetch { try DBStar.undeliveredStars(from: $0, rosterId: rosterId) } - .map { Star(star: $0) } + return dbManager.fetch { db -> [DBStar] in + return try RosterRelatedQueryArgs(rosterId: rosterId) + .makeTypedRequest() + .filter(Column.id == nil) + .fetchAllConstructed(db) + }.serverModels } } diff --git a/Nynja/StorageService+UserInfo.swift b/Nynja/StorageService+UserInfo.swift index b520bbda0837d9ce41904f26744be12140b1a6cb..2e7b6d7b51e9628213b2083a5f13fea58cc9f3ed 100644 --- a/Nynja/StorageService+UserInfo.swift +++ b/Nynja/StorageService+UserInfo.swift @@ -46,11 +46,6 @@ extension StorageService: UserInfo { set { set(newValue, forId: .phone) } } - var voxId: String? { - get { return userDefaults?.string(forKey: UserIdentifiers.voxId.rawValue) } - set { set(newValue, forId: .voxId) } - } - var rosterId: Int64? { get { guard let id = userDefaults?.value(forKey: UserIdentifiers.rosterId.rawValue) as? Int64 else { return nil } @@ -82,7 +77,6 @@ extension StorageService: UserInfo { func setupUserInfo(from roster: Roster) { phone = roster.phone rosterId = roster.id - voxId = roster.myContact?.voxID } private func set(_ value: Any?, forId id: UserIdentifiers) { diff --git a/Nynja/UserInfo.swift b/Nynja/UserInfo.swift index abddc6a468ec0314e7d849aa97753de353cb48bf..b54af5b579a0e50aff165d9f80843c3feada2150 100644 --- a/Nynja/UserInfo.swift +++ b/Nynja/UserInfo.swift @@ -11,7 +11,6 @@ import Foundation enum UserIdentifiers: String { case token case phone - case voxId case rosterId case clientId = "clientID" @@ -24,7 +23,6 @@ protocol UserInfo: class { var tokenAsNSData: NSData? { get } var phone: String? { get set } - var voxId: String? { get set } var rosterId: Int64? { get set } var clientId: String? { get set } @@ -60,7 +58,6 @@ extension UserInfo { LogService.log(topic: .userDefaults) { return "drop user info" } token = nil phone = nil - voxId = nil rosterId = nil clientId = nil } diff --git a/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift b/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift index 73ac1e54a72263fa07479afaab8e2d96ab67d1b5..f2ba00aa2716621ef239bede0952240de8e71ab3 100644 --- a/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift +++ b/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift @@ -93,7 +93,6 @@ class UserInfoTest: XCTestCase { userInfo.phone = phone userInfo.rosterId = rosterId userInfo.token = token - userInfo.voxId = "vox_id" userInfo.clientId = "client_id" userInfo.dropUserInfo() @@ -101,7 +100,6 @@ class UserInfoTest: XCTestCase { XCTAssertNil(userInfo.phone) XCTAssertNil(userInfo.rosterId) XCTAssertNil(userInfo.token) - XCTAssertNil(userInfo.voxId) XCTAssertNil(userInfo.clientId) } @@ -114,11 +112,9 @@ private extension UserInfoTest { var token: String? var tokenAsNSData: NSData? var phone: String? - var voxId: String? var rosterId: Int64? var clientId: String? var wasLogined: Bool = true var wasRun: Bool = true } - } diff --git a/Shared/Library/Extensions/Models/Contact/ContactExtension.swift b/Shared/Library/Extensions/Models/Contact/ContactExtension.swift index 0acc8d98f105dd613bd91b9ef9e9d3fabe5baa74..5be2afe2a046d55436f55279c2da285c8b03eeb9 100644 --- a/Shared/Library/Extensions/Models/Contact/ContactExtension.swift +++ b/Shared/Library/Extensions/Models/Contact/ContactExtension.swift @@ -8,7 +8,7 @@ import UIKit -extension Contact { +extension Contact: FullNameRepresentable { enum Status: String { case get case request @@ -22,24 +22,6 @@ extension Contact { case ignore } - /// Returns fullname, name or surname depending on what exists. - /// If contact doesn't have name and surname, it will return nil - var fullName: String? { - if let name = self.names, let surname = self.surnames { - if !surname.isEmpty { - return "\(name) \(surname)" - } else { - return name - } - } else if names != nil && surnames == nil { - return names - } else if names == nil && surnames == nil { - return surnames - } - - return nil - } - var alias: String? { return fullName } @@ -121,12 +103,6 @@ extension Contact { return phone_id ?? "" } - /// Returns 'person_id' if exists, else - empty string - var voxID: String { - let ser = self.services?.first { ($0.type as? StringAtom)?.string == "vox" } - return ser?.id ?? "" - } - /// Parse roster id from the 'phone_id' property var rosterId: Int64 { if var phone = self.phone_id, let range = phone.range(of: "_") { diff --git a/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift b/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift index 1b8274323a76c31a51f61c19d8371f02eea009b1..40e54e9d20b5834f88b005881abd0a05c0661bd6 100644 --- a/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift +++ b/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift @@ -12,6 +12,7 @@ protocol SharedServiceFactoryProtocol: class { func makeAmazonManager() -> AmazonManager func makeAmazonInitializer() -> AmazonInitializer func makeTypingSenderService() -> TypingSenderServiceProtocol + func makeLogWriter() -> LogWriterProtocol? } class SharedServiceFactory: SharedServiceFactoryProtocol { @@ -38,4 +39,8 @@ class SharedServiceFactory: SharedServiceFactoryProtocol { return TypingSenderService(dependencies: dependencies) } + + func makeLogWriter() -> LogWriterProtocol? { + return LogWriter.shared + } }