From af5cb937c08338ce3a41a1a84ad37b2ec807f540 Mon Sep 17 00:00:00 2001 From: Yulia Date: Sat, 4 Dec 2021 23:08:33 +0300 Subject: [PATCH 01/28] Add firebase to project --- DoIt.xcodeproj/project.pbxproj | 75 ++++++++++- DoIt.xcworkspace/contents.xcworkspacedata | 10 ++ GoogleService-Info.plist | 36 +++++ Podfile | 13 ++ Podfile.lock | 154 ++++++++++++++++++++++ 5 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 DoIt.xcworkspace/contents.xcworkspacedata create mode 100644 GoogleService-Info.plist create mode 100644 Podfile create mode 100644 Podfile.lock diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index a9f1a4e..a2e8da7 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 5038435A2AA2F8CD2F8BEF43 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */; }; 7C6382DD272777F600FED2F4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7C6382DF272777F600FED2F4 /* Localizable.strings */; }; 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E22727884000FED2F4 /* UIImageExtension.swift */; }; 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E52728807900FED2F4 /* UIColorsExtension.swift */; }; @@ -42,6 +43,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DoIt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7C5DE36E272AD0E30051C54B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 7C6382DE272777F600FED2F4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 7C6382E22727884000FED2F4 /* UIImageExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; @@ -77,6 +79,8 @@ 83AF419F27429B5500CA8AAA /* MainTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; 83AF41A127431EB500CA8AAA /* FeedController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedController.swift; sourceTree = ""; }; 83AF41A727431F9600CA8AAA /* FeedCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCollectionViewCell.swift; sourceTree = ""; }; + A6F76C970701A2725CD83976 /* Pods-DoIt.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DoIt.release.xcconfig"; path = "Target Support Files/Pods-DoIt/Pods-DoIt.release.xcconfig"; sourceTree = ""; }; + E5B597D22D74D989EB26883A /* Pods-DoIt.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DoIt.debug.xcconfig"; path = "Target Support Files/Pods-DoIt/Pods-DoIt.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -84,12 +88,23 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5038435A2AA2F8CD2F8BEF43 /* Pods_DoIt.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 68E55F666999107589684535 /* Pods */ = { + isa = PBXGroup; + children = ( + E5B597D22D74D989EB26883A /* Pods-DoIt.debug.xcconfig */, + A6F76C970701A2725CD83976 /* Pods-DoIt.release.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 7C6382CE2725C4EF00FED2F4 /* Views */ = { isa = PBXGroup; children = ( @@ -164,6 +179,8 @@ children = ( 7CAC5DCC27232C6000E2D70B /* DoIt */, 7CAC5DCB27232C6000E2D70B /* Products */, + 68E55F666999107589684535 /* Pods */, + FBE1554FF59FC4B0618D3B41 /* Frameworks */, ); sourceTree = ""; }; @@ -298,6 +315,14 @@ path = FeedCollectionView; sourceTree = ""; }; + FBE1554FF59FC4B0618D3B41 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -305,17 +330,17 @@ isa = PBXNativeTarget; buildConfigurationList = 7CAC5DDE27232C6300E2D70B /* Build configuration list for PBXNativeTarget "DoIt" */; buildPhases = ( + 423DF60E81691518C8C7A6E1 /* [CP] Check Pods Manifest.lock */, 7CAC5DC627232C6000E2D70B /* Sources */, 7CAC5DC727232C6000E2D70B /* Frameworks */, 7CAC5DC827232C6000E2D70B /* Resources */, + FC7455CDDE53378C6DD0B23E /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = DoIt; - packageProductDependencies = ( - ); productName = DoIt; productReference = 7CAC5DCA27232C6000E2D70B /* DoIt.app */; productType = "com.apple.product-type.application"; @@ -345,8 +370,6 @@ Base, ); mainGroup = 7CAC5DC127232C6000E2D70B; - packageReferences = ( - ); productRefGroup = 7CAC5DCB27232C6000E2D70B /* Products */; projectDirPath = ""; projectRoot = ""; @@ -369,6 +392,48 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 423DF60E81691518C8C7A6E1 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-DoIt-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FC7455CDDE53378C6DD0B23E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DoIt/Pods-DoIt-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-DoIt/Pods-DoIt-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DoIt/Pods-DoIt-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 7CAC5DC627232C6000E2D70B /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -549,6 +614,7 @@ }; 7CAC5DDF27232C6300E2D70B /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E5B597D22D74D989EB26883A /* Pods-DoIt.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -577,6 +643,7 @@ }; 7CAC5DE027232C6300E2D70B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = A6F76C970701A2725CD83976 /* Pods-DoIt.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; diff --git a/DoIt.xcworkspace/contents.xcworkspacedata b/DoIt.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..2735e32 --- /dev/null +++ b/DoIt.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist new file mode 100644 index 0000000..d9885d2 --- /dev/null +++ b/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 562011549386-m8uaj5enlra65cq7qlrg3jk91mv66fk5.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.562011549386-m8uaj5enlra65cq7qlrg3jk91mv66fk5 + API_KEY + AIzaSyC6JYyF7IDY-kw3AH9Hl6v9E4b7L7Gj-Is + GCM_SENDER_ID + 562011549386 + PLIST_VERSION + 1 + BUNDLE_ID + com.vkproj.doIt + PROJECT_ID + doit-b9c45 + STORAGE_BUCKET + doit-b9c45.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + DATABASE_URL + https://doit-b9c45-default-rtdb.firebaseio.com/ + GOOGLE_APP_ID + 1:562011549386:ios:6fcfaa37eaad2ceab88e33 + + diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..113616d --- /dev/null +++ b/Podfile @@ -0,0 +1,13 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'DoIt' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for DoIt + pod 'Firebase/Core' + pod 'Firebase/Database' + pod 'Firebase/Storage' + pod 'Firebase/Auth' +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..e4d024f --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,154 @@ +PODS: + - Firebase/Auth (8.9.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 8.9.0) + - Firebase/Core (8.9.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 8.9.0) + - Firebase/CoreOnly (8.9.0): + - FirebaseCore (= 8.9.0) + - Firebase/Database (8.9.0): + - Firebase/CoreOnly + - FirebaseDatabase (~> 8.9.0) + - Firebase/Storage (8.9.0): + - Firebase/CoreOnly + - FirebaseStorage (~> 8.9.0) + - FirebaseAnalytics (8.9.0): + - FirebaseAnalytics/AdIdSupport (= 8.9.0) + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - FirebaseAnalytics/AdIdSupport (8.9.0): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleAppMeasurement (= 8.9.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - FirebaseAuth (8.9.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/Environment (~> 7.6) + - GTMSessionFetcher/Core (~> 1.5) + - FirebaseCore (8.9.0): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - FirebaseCoreDiagnostics (8.9.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - nanopb (~> 2.30908.0) + - FirebaseDatabase (8.9.0): + - FirebaseCore (~> 8.0) + - leveldb-library (~> 1.22) + - FirebaseInstallations (8.9.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/UserDefaults (~> 7.6) + - PromisesObjC (< 3.0, >= 1.2) + - FirebaseStorage (8.9.0): + - FirebaseCore (~> 8.0) + - GTMSessionFetcher/Core (~> 1.5) + - GoogleAppMeasurement (8.9.0): + - GoogleAppMeasurement/AdIdSupport (= 8.9.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (8.9.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (8.9.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleDataTransport (9.1.2): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.6.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.6.0): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.6.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.6.0)" + - GoogleUtilities/Reachability (7.6.0): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.6.0): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (1.7.0) + - leveldb-library (1.22.1) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - PromisesObjC (2.0.0) + +DEPENDENCIES: + - Firebase/Auth + - Firebase/Core + - Firebase/Database + - Firebase/Storage + +SPEC REPOS: + trunk: + - Firebase + - FirebaseAnalytics + - FirebaseAuth + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseDatabase + - FirebaseInstallations + - FirebaseStorage + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleUtilities + - GTMSessionFetcher + - leveldb-library + - nanopb + - PromisesObjC + +SPEC CHECKSUMS: + Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95 + FirebaseAnalytics: 3a11ed901750e1ebcbe35e75915ff079878ea385 + FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b + FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b + FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 + FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc + FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85 + FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 + GoogleAppMeasurement: b54a857d347703d67c7a6f23713760c9bcfe9008 + GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 + GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 + GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 + leveldb-library: 50c7b45cbd7bf543c81a468fe557a16ae3db8729 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + +PODFILE CHECKSUM: 519fd9585678867ec34d7d4b0104a2a739488967 + +COCOAPODS: 1.11.2 From 4a1ab4ceb7d694a9f8c74e7755057ad6096b5aa6 Mon Sep 17 00:00:00 2001 From: Yulia Date: Mon, 6 Dec 2021 04:21:32 +0300 Subject: [PATCH 02/28] Add task and user services --- DoIt.xcodeproj/project.pbxproj | 33 +++++++- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ DoIt/Application/AppDelegate.swift | 2 + DoIt/GoogleService-Info.plist | 36 +++++++++ DoIt/Info.plist | 6 +- DoIt/Models/AuthModel.swift | 40 ++++++++++ DoIt/Models/AuthService.swift | 59 ++++++++++++++ DoIt/Models/FirebaseConstants.swift | 17 +++++ DoIt/Models/Structures.swift | 16 +++- DoIt/Models/TaskService.swift | 76 +++++++++++++++++++ DoIt/Models/UserModel.swift | 28 +++++++ DoIt/Models/UserService.swift | 67 ++++++++++++++++ 12 files changed, 381 insertions(+), 7 deletions(-) create mode 100644 DoIt.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 DoIt/GoogleService-Info.plist create mode 100644 DoIt/Models/AuthModel.swift create mode 100644 DoIt/Models/AuthService.swift create mode 100644 DoIt/Models/FirebaseConstants.swift create mode 100644 DoIt/Models/TaskService.swift create mode 100644 DoIt/Models/UserModel.swift create mode 100644 DoIt/Models/UserService.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index a2e8da7..06a3fb4 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -8,11 +8,18 @@ /* Begin PBXBuildFile section */ 5038435A2AA2F8CD2F8BEF43 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */; }; + 7C022801275D9C4800DFF8EC /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022800275D9C4800DFF8EC /* AuthService.swift */; }; 7C6382DD272777F600FED2F4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7C6382DF272777F600FED2F4 /* Localizable.strings */; }; 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E22727884000FED2F4 /* UIImageExtension.swift */; }; 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E52728807900FED2F4 /* UIColorsExtension.swift */; }; 7C6382E8272883AC00FED2F4 /* Printer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E7272883AC00FED2F4 /* Printer.swift */; }; 7C6382F02729CCC300FED2F4 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382EF2729CCC300FED2F4 /* StringExtension.swift */; }; + 7C6C3BC4275C05E000B6101F /* UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC3275C05E000B6101F /* UserService.swift */; }; + 7C6C3BC8275C06B400B6101F /* AuthModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC7275C06B400B6101F /* AuthModel.swift */; }; + 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */; }; + 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */; }; + 7C6C3BCE275CFE4700B6101F /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCD275CFE4700B6101F /* UserModel.swift */; }; + 7C6C3BD0275CFEA900B6101F /* TaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCF275CFEA900B6101F /* TaskService.swift */; }; 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */; }; 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */; }; 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; @@ -44,12 +51,19 @@ /* Begin PBXFileReference section */ 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DoIt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7C022800275D9C4800DFF8EC /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; 7C5DE36E272AD0E30051C54B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 7C6382DE272777F600FED2F4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 7C6382E22727884000FED2F4 /* UIImageExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; 7C6382E52728807900FED2F4 /* UIColorsExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorsExtension.swift; sourceTree = ""; }; 7C6382E7272883AC00FED2F4 /* Printer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Printer.swift; sourceTree = ""; }; 7C6382EF2729CCC300FED2F4 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; + 7C6C3BC3275C05E000B6101F /* UserService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserService.swift; sourceTree = ""; }; + 7C6C3BC7275C06B400B6101F /* AuthModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthModel.swift; sourceTree = ""; }; + 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseConstants.swift; sourceTree = ""; }; + 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 7C6C3BCD275CFE4700B6101F /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; + 7C6C3BCF275CFEA900B6101F /* TaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskService.swift; sourceTree = ""; }; 7CAC5DCA27232C6000E2D70B /* DoIt.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DoIt.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -101,7 +115,6 @@ E5B597D22D74D989EB26883A /* Pods-DoIt.debug.xcconfig */, A6F76C970701A2725CD83976 /* Pods-DoIt.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -159,6 +172,12 @@ children = ( 8383504C27583FB6008847E1 /* SearchFriendsModel.swift */, 83369A4D273857020025F3D9 /* Structures.swift */, + 7C6C3BC3275C05E000B6101F /* UserService.swift */, + 7C6C3BC7275C06B400B6101F /* AuthModel.swift */, + 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, + 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, + 7C6C3BCF275CFEA900B6101F /* TaskService.swift */, + 7C022800275D9C4800DFF8EC /* AuthService.swift */, ); path = Models; sourceTree = ""; @@ -195,6 +214,7 @@ 7CAC5DCC27232C6000E2D70B /* DoIt */ = { isa = PBXGroup; children = ( + 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */, 7C6382DF272777F600FED2F4 /* Localizable.strings */, 7C6382D52725C5E800FED2F4 /* Models */, 7C6382D32725C5BD00FED2F4 /* Application */, @@ -385,6 +405,7 @@ buildActionMask = 2147483647; files = ( 7C6382DD272777F600FED2F4 /* Localizable.strings in Resources */, + 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */, 8383504B27583F93008847E1 /* Assets.xcassets in Resources */, 8383504727583F0E008847E1 /* LaunchScreen.storyboard in Resources */, ); @@ -446,27 +467,33 @@ 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */, 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */, 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */, + 7C6C3BCE275CFE4700B6101F /* UserModel.swift in Sources */, 8383504027583E58008847E1 /* SearchFriendsCell.swift in Sources */, 8383503827583E58008847E1 /* CustomUIElementsOnboarding.swift in Sources */, 83AF41A227431EB500CA8AAA /* FeedController.swift in Sources */, 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, + 7C6C3BC8275C06B400B6101F /* AuthModel.swift in Sources */, 8383504227583E58008847E1 /* SignUpController.swift in Sources */, 8383504127583E58008847E1 /* SearchFriendsController.swift in Sources */, 8383504D27583FB6008847E1 /* SearchFriendsModel.swift in Sources */, 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */, 7C6382F02729CCC300FED2F4 /* StringExtension.swift in Sources */, 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */, + 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */, 8383503727583E58008847E1 /* SignInController.swift in Sources */, 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */, 8383503E27583E58008847E1 /* CustomUIElementsTask.swift in Sources */, 7C6382E8272883AC00FED2F4 /* Printer.swift in Sources */, 8383504A27583F93008847E1 /* Strings.swift in Sources */, 83369A4E273857020025F3D9 /* Structures.swift in Sources */, + 7C022801275D9C4800DFF8EC /* AuthService.swift in Sources */, 8383503A27583E58008847E1 /* Onboarding.swift in Sources */, 83AF41A027429B5500CA8AAA /* MainTabBarController.swift in Sources */, + 7C6C3BD0275CFEA900B6101F /* TaskService.swift in Sources */, 8383503627583E58008847E1 /* CustomNavigationController.swift in Sources */, 8383503527583E58008847E1 /* Auth.swift in Sources */, + 7C6C3BC4275C05E000B6101F /* UserService.swift in Sources */, 8383503C27583E58008847E1 /* TaskEditViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -633,7 +660,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt111; + PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -662,7 +689,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt111; + PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/DoIt.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DoIt.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/DoIt.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/DoIt/Application/AppDelegate.swift b/DoIt/Application/AppDelegate.swift index 34b1057..add6f21 100644 --- a/DoIt/Application/AppDelegate.swift +++ b/DoIt/Application/AppDelegate.swift @@ -6,11 +6,13 @@ // import UIKit +import Firebase @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + FirebaseApp.configure() // Override point for customization after application launch. return true } diff --git a/DoIt/GoogleService-Info.plist b/DoIt/GoogleService-Info.plist new file mode 100644 index 0000000..d9885d2 --- /dev/null +++ b/DoIt/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 562011549386-m8uaj5enlra65cq7qlrg3jk91mv66fk5.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.562011549386-m8uaj5enlra65cq7qlrg3jk91mv66fk5 + API_KEY + AIzaSyC6JYyF7IDY-kw3AH9Hl6v9E4b7L7Gj-Is + GCM_SENDER_ID + 562011549386 + PLIST_VERSION + 1 + BUNDLE_ID + com.vkproj.doIt + PROJECT_ID + doit-b9c45 + STORAGE_BUCKET + doit-b9c45.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + DATABASE_URL + https://doit-b9c45-default-rtdb.firebaseio.com/ + GOOGLE_APP_ID + 1:562011549386:ios:6fcfaa37eaad2ceab88e33 + + diff --git a/DoIt/Info.plist b/DoIt/Info.plist index 4e52c59..d90e717 100644 --- a/DoIt/Info.plist +++ b/DoIt/Info.plist @@ -2,6 +2,8 @@ + FirebaseAutomaticScreenReportingEnabled + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -11,12 +13,12 @@ UIWindowSceneSessionRoleApplication - UISceneStoryboardFile - LaunchScreen UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + LaunchScreen diff --git a/DoIt/Models/AuthModel.swift b/DoIt/Models/AuthModel.swift new file mode 100644 index 0000000..9da2a6c --- /dev/null +++ b/DoIt/Models/AuthModel.swift @@ -0,0 +1,40 @@ +// +// AuthModel.swift +// DoIt +// +// Created by Y u l i a on 04.12.2021. +// + +import Foundation +import Firebase + +struct AuthCredentials { + let email: String + let password: String + let username: String +} + +enum AuthError { + case invalidEmail + case unknownError + case serverError +} + +extension AuthError: LocalizedError { + var errorDescription: String? { + switch self { + case .invalidEmail: + return NSLocalizedString("email_is_not_valid", comment: "") + case .unknownError: + return NSLocalizedString("server_error", comment: "") + case .serverError: + return NSLocalizedString("server_error", comment: "") + + } + } +} + +enum AuthResult { + case success + case failure(Error) +} diff --git a/DoIt/Models/AuthService.swift b/DoIt/Models/AuthService.swift new file mode 100644 index 0000000..1c9c22a --- /dev/null +++ b/DoIt/Models/AuthService.swift @@ -0,0 +1,59 @@ +// +// AuthService.swift +// DoIt +// +// Created by Y u l i a on 06.12.2021. +// + +import Firebase + +struct AuthService { + //create static instance service + static let shared = AuthService() + + func signIn(email: String?, password: String?, completion: @escaping (AuthResult) -> Void) { + guard let email = email, let password = password else { + completion(.failure(AuthError.unknownError)) + return + } + + Auth.auth().signIn(withEmail: email, password: password) { (result, error) in + guard let result = result else { + completion(.failure(error!)) + return + } + + let uid = result.user.uid + + UserDefaults.standard.set(uid, forKey: "current_user") + + + completion(.success) + } + } + + public func signUp(email: String?, username: String?, password: String?, completion: @escaping (AuthResult) -> Void) { + + guard let email = email, let username = username, let password = password else { + completion(.failure(AuthError.unknownError)) + return + } + + Auth.auth().createUser(withEmail: email, password: password) { (result, error) in + guard let result = result else { + completion(.failure(error!)) + return + } + + let uid = result.user.uid + + UserDefaults.standard.set(uid, forKey: "current_user") + + let values = ["email": email, + "username": username] + let usersReferense = Database.database().reference().child("users").child(uid) + usersReferense.child(uid).updateChildValues(values) + completion(.success) + } + } +} diff --git a/DoIt/Models/FirebaseConstants.swift b/DoIt/Models/FirebaseConstants.swift new file mode 100644 index 0000000..2070868 --- /dev/null +++ b/DoIt/Models/FirebaseConstants.swift @@ -0,0 +1,17 @@ +// +// FirebaseConstants.swift +// DoIt +// +// Created by Yulia on 04.12.2021. +// + +import Firebase + +let DB_REF = Database.database().reference() +let REF_USERS = DB_REF.child("users") + +let REF_TASKS = DB_REF.child("tasks") +let REF_USER_TASKS = DB_REF.child("user-tasks") +let REF_USER_FOLLOWERS = DB_REF.child("user-followers") +let REF_USER_FOLLOWING = DB_REF.child("user-following") +let REF_TWEET_REPLIES = DB_REF.child("tweet-replies") diff --git a/DoIt/Models/Structures.swift b/DoIt/Models/Structures.swift index 4c0c443..28ac637 100644 --- a/DoIt/Models/Structures.swift +++ b/DoIt/Models/Structures.swift @@ -7,18 +7,30 @@ import UIKit -struct Chapter{ +struct Chapter { let title: String let color: UIColor let textColor: UIColor } -struct Task{ +class Task { let image: UIImage? let title: String let description: String? let deadline: Date? let isDone: Bool let creatorId: Int + let uid: String? let color: UIColor + + init(image: UIImage?, title: String, description: String?, deadline: Date?, isDone: Bool, creatorId: Int, color: UIColor, uid: String = "") { + self.image = image + self.title = title + self.description = description + self.deadline = deadline + self.isDone = isDone + self.creatorId = creatorId + self.uid = "" + self.color = color + } } diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift new file mode 100644 index 0000000..272d64e --- /dev/null +++ b/DoIt/Models/TaskService.swift @@ -0,0 +1,76 @@ +// +// PostService.swift +// DoIt +// +// Created by Yulia on 05.12.2021. +// +// + +import Firebase + +struct TaskService { + + static let shared = TaskService() + + func uploadTask(task: Task, completion: @escaping(Error?, DatabaseReference)->Void){ + guard let uid = Auth.auth().currentUser?.uid else {return} + var values = [ + "title": task.title, + "description": task.description ?? "", + "deadline": Int(task.deadline?.timeIntervalSince1970 ?? 0), + "is_done": task.isDone, + "uid": uid, + "timestamp": Int(NSDate().timeIntervalSince1970), + "color": [task.color.cgColor.components?[0], + task.color.cgColor.components?[1], + task.color.cgColor.components?[2] + ] + ] as [String : Any] + + REF_TASKS.childByAutoId().updateChildValues(values) { (error, ref) in + guard let taskID = ref.key else { return } + REF_USER_TASKS.child(uid).updateChildValues([taskID : 1], withCompletionBlock: completion) + } + } + + func fetchTask(taskId: String, completion: @escaping(Task) -> Void){ + REF_TASKS.child(taskId).observeSingleEvent(of: .value) { snapshot in + guard let dictionary = snapshot.value as? [String: Any] else {return} + guard let uid = dictionary["uid"] as? String else {return} + guard let image = dictionary["image"] as? String else { return } + guard let title = dictionary["title"] as? String else { return } + guard let description = dictionary["description"] as? String else { return } + guard let deadline = dictionary["deadline"] as? Int else { return } + guard let isDone = dictionary["is_done"] as? Bool else { return } + guard let creatorId = dictionary["uid"] as? String else { return } + guard let color = dictionary["color"] as? [Int] else { return } + + + UserService.shared.fetchUser(uid: uid) { (user) in + + let task = Task( + image: nil, + title: title, + description: description, + deadline: Date(timeIntervalSince1970: TimeInterval(deadline)), + isDone: isDone, + creatorId: 0, + color: UIColor(red: CGFloat(color[0]) * 255.0, green: CGFloat(color[1]) * 255.0, blue: CGFloat(color[2]) * 255.0, alpha: 1.0) + ) + completion(task) + } + } + } + + func fetchTasks(forUser user: User, completion: @escaping([Task]) -> Void) { + var tasks = [Task]() + REF_USER_TASKS.child(user.uid).observe(.childAdded) { snapshot in + let taskId = snapshot.key + + self.fetchTask(taskId: taskId) { task in + tasks.append(task) + completion(tasks) + } + } + } +} diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift new file mode 100644 index 0000000..6db7579 --- /dev/null +++ b/DoIt/Models/UserModel.swift @@ -0,0 +1,28 @@ +// +// UserModel.swift +// DoIt +// +// Created by Yulia on 05.12.2021. +// +// + +import Firebase + +struct User { + + let uid: String + let email: String + var username: String + var summary: String? + + var isCurrentUser: Bool { + return Auth.auth().currentUser?.uid == uid + } + + init(uid:String, dictionary:[String:AnyObject]) { + self.uid = uid + self.email = dictionary["email"] as? String ?? "" + self.username = dictionary["username"] as? String ?? "" + self.summary = dictionary["summary"] as? String ?? "" + } +} diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift new file mode 100644 index 0000000..f7a28a8 --- /dev/null +++ b/DoIt/Models/UserService.swift @@ -0,0 +1,67 @@ +// +// UserModel.swift +// DoIt +// +// Created by Yulia on 04.12.2021. +// + +import Firebase + +typealias DatabaseCompletion = ((Error?, DatabaseReference)-> Void) + +struct UserService { + + static let shared = UserService() + + func fetchUser(uid: String, completion: @escaping(User)->Void) { + REF_USERS.child(uid).observeSingleEvent(of: .value) { snapshot in + guard let dictionary = snapshot.value as? [String: AnyObject] else {return} + + let user = User(uid: uid, dictionary: dictionary) + completion(user) + } + } + + // TODO: - Update profile picture + + func updateUserData(user: User, completion: @escaping(DatabaseCompletion)){ + guard let uid = Auth.auth().currentUser?.uid else {return} + let values = ["username": user.username, "summary": user.summary ?? ""] + + REF_USERS.child(uid).updateChildValues(values, withCompletionBlock: completion) + } + + func fetchUsers(completion: @escaping([User])->Void) { + var users = [User]() + REF_USERS.observe(.childAdded) { (snapshot) in + let uid = snapshot.key + guard let dictionary = snapshot.value as? [String: AnyObject] else {return} + let user = User(uid: uid, dictionary: dictionary) + users.append(user) + completion(users) + } + } + + func followUser(uid: String, completion: @escaping(DatabaseCompletion)){ + guard let currentUid = Auth.auth().currentUser?.uid else {return} + + REF_USER_FOLLOWING.child(currentUid).updateChildValues([uid : 1]) { (err, ref) in + REF_USER_FOLLOWERS.child(uid).updateChildValues([currentUid: 1], withCompletionBlock: completion) + } + } + + func unfollowUser(uid: String, completion: @escaping(DatabaseCompletion)) { + guard let currentUid = Auth.auth().currentUser?.uid else {return} + + REF_USER_FOLLOWING.child(currentUid).child(uid).removeValue { (err, ref) in + REF_USER_FOLLOWERS.child(uid).child(currentUid).removeValue(completionBlock: completion) + } + } + + func isUserFollowed(uid: String, completion: @escaping(Bool)->Void){ + guard let currentUid = Auth.auth().currentUser?.uid else {return} + + REF_USER_FOLLOWING.child(currentUid).child(uid).observeSingleEvent(of: .value) { snapshot in completion(snapshot.exists()) + } + } +} From 59e7e3e572be042fcac0a8af433dcc8a9aab6e81 Mon Sep 17 00:00:00 2001 From: Yulia Date: Mon, 6 Dec 2021 05:21:21 +0300 Subject: [PATCH 03/28] Add fetching followers and following --- DoIt/Models/FirebaseConstants.swift | 2 +- DoIt/Models/UserService.swift | 37 +++++++++++ .../SearchFriendsController.swift | 66 ++++++++++++++++++- 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/DoIt/Models/FirebaseConstants.swift b/DoIt/Models/FirebaseConstants.swift index 2070868..027a346 100644 --- a/DoIt/Models/FirebaseConstants.swift +++ b/DoIt/Models/FirebaseConstants.swift @@ -14,4 +14,4 @@ let REF_TASKS = DB_REF.child("tasks") let REF_USER_TASKS = DB_REF.child("user-tasks") let REF_USER_FOLLOWERS = DB_REF.child("user-followers") let REF_USER_FOLLOWING = DB_REF.child("user-following") -let REF_TWEET_REPLIES = DB_REF.child("tweet-replies") + diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index f7a28a8..bde3b67 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -22,6 +22,8 @@ struct UserService { } } + // TODO: - Update profile + // TODO: - Update profile picture func updateUserData(user: User, completion: @escaping(DatabaseCompletion)){ @@ -64,4 +66,39 @@ struct UserService { REF_USER_FOLLOWING.child(currentUid).child(uid).observeSingleEvent(of: .value) { snapshot in completion(snapshot.exists()) } } + +// func fetchUserFollowers(uid: String, completion: @escaping([User])->Void){ +// +// var users = [User]() +// +// REF_USER_FOLLOWERS.child(uid).observe(.childAdded) { (snapshot) in +// let usr = snapshot.key +// print("!!!", usr) +// guard let dictionary = snapshot.value as? [String: AnyObject] else {return} +// let user = User(uid: usr, dictionary: dictionary) +// users.append(user) +// completion(users) +// } +// } + + func fetchUserFollowers(uid: String, completion: @escaping([String])->Void) { + var users_uid = [String]() + REF_USER_FOLLOWERS.child(uid).observe(.childAdded) { (snapshot) in + + let follower_uid = snapshot.key + users_uid.append(follower_uid) + completion(users_uid) + } + } + + func fetchUserFollowing(uid: String, completion: @escaping([String])->Void) { + var users_uid = [String]() + REF_USER_FOLLOWING.child(uid).observe(.childAdded) { (snapshot) in + + let following_uid = snapshot.key + users_uid.append(following_uid) + completion(users_uid) + } + } + } diff --git a/DoIt/Views/Search Friends/SearchFriendsController.swift b/DoIt/Views/Search Friends/SearchFriendsController.swift index bc8d41f..6f417f2 100644 --- a/DoIt/Views/Search Friends/SearchFriendsController.swift +++ b/DoIt/Views/Search Friends/SearchFriendsController.swift @@ -63,10 +63,74 @@ final class SearchFriendsController: UIViewController { // MARK: - Lifecycle +// struct AuthCredentials { +// let email: String +// let password: String +// let fullname: String +// let username: String +// } + +// struct AuthService { +// //create static instance service +// static let shared = AuthService() +// +// func logUserIn(withEmail email:String, password:String, completion:AuthDataResultCallback?){ +// Auth.auth().signIn(withEmail: email, password: password, completion: completion) +// print("DEBUG: Email is \(email), passward is \(password)") +// } +// +// +// func registerUser(credentials : AuthCredentials, completion: @escaping(Error?, DatabaseReference) -> Void) { +// // upload image data and download image url +// let email = credentials.email +// let password = credentials.password +// let username = credentials.username +// let fullname = credentials.fullname +// +// let filename = NSUUID().uuidString +// let storageRef = STORAGE_PROFILE_IMAGES.child(filename) +// +// } +// } + override func viewDidLoad() { super.viewDidLoad() - configureUI() + print("111") + + AuthService.shared.signIn(email: "qwerty11111@gmail.com", password: "_1234678A") { (result) in + print(result) + } + var t : Task = Task(image: nil, title: "title", description: nil, deadline: Date.now, isDone: false, creatorId: 0, color: UIColor.red) + TaskService.shared.uploadTask(task: t) { error, result in + print(error, result) + } + + UserService.shared.followUser(uid: "hQekAm6zPvZ8xVgQAGQ0ceN6DpM2") { error, result in + print(error, result) + } + + UserService.shared.fetchUserFollowers(uid: "vkdW6hhGIHh1It2fjexEDpQ0tEB3") { user in + print("kkk", user) + } +// TaskService.shared.uploadTask(task: t) { error, result in +// print(error, result) +// } +// TaskService.shared.uploadTask(task: t) { error, result in +// print(error, result) +// } +// TaskService.shared.uploadTask(task: t) { error, result in +// print(error, result) +// } +// TaskService.shared.uploadTask(task: t) { error, result in +// print(error, result) +// } +// TaskService.shared.uploadTask(task: t) { error, result in +// print(error, result) +// } + UserService.shared.fetchUsers { user in + print(user) + } } // MARK: - Helpers From 727f102c88125a2becb9742d72650c8a17cd2b26 Mon Sep 17 00:00:00 2001 From: Yulia Date: Mon, 6 Dec 2021 05:50:04 +0300 Subject: [PATCH 04/28] Add image uploader && little fixes --- DoIt.xcodeproj/project.pbxproj | 12 ++-- ...AuthModel.swift => AuthResultsModel.swift} | 0 DoIt/Models/AuthService.swift | 4 +- DoIt/Models/FirebaseConstants.swift | 6 +- DoIt/Models/ImageService.swift | 26 ++++++++ DoIt/Models/TaskService.swift | 2 +- DoIt/Models/UserModel.swift | 2 +- DoIt/Models/UserService.swift | 20 +----- .../SearchFriendsController.swift | 65 ------------------- 9 files changed, 45 insertions(+), 92 deletions(-) rename DoIt/Models/{AuthModel.swift => AuthResultsModel.swift} (100%) create mode 100644 DoIt/Models/ImageService.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 06a3fb4..f48876b 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -9,13 +9,14 @@ /* Begin PBXBuildFile section */ 5038435A2AA2F8CD2F8BEF43 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */; }; 7C022801275D9C4800DFF8EC /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022800275D9C4800DFF8EC /* AuthService.swift */; }; + 7C022803275DAE6700DFF8EC /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022802275DAE6700DFF8EC /* ImageService.swift */; }; 7C6382DD272777F600FED2F4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7C6382DF272777F600FED2F4 /* Localizable.strings */; }; 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E22727884000FED2F4 /* UIImageExtension.swift */; }; 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E52728807900FED2F4 /* UIColorsExtension.swift */; }; 7C6382E8272883AC00FED2F4 /* Printer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E7272883AC00FED2F4 /* Printer.swift */; }; 7C6382F02729CCC300FED2F4 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382EF2729CCC300FED2F4 /* StringExtension.swift */; }; 7C6C3BC4275C05E000B6101F /* UserService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC3275C05E000B6101F /* UserService.swift */; }; - 7C6C3BC8275C06B400B6101F /* AuthModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC7275C06B400B6101F /* AuthModel.swift */; }; + 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */; }; 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */; }; 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */; }; 7C6C3BCE275CFE4700B6101F /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCD275CFE4700B6101F /* UserModel.swift */; }; @@ -52,6 +53,7 @@ /* Begin PBXFileReference section */ 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DoIt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7C022800275D9C4800DFF8EC /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; + 7C022802275DAE6700DFF8EC /* ImageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; 7C5DE36E272AD0E30051C54B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 7C6382DE272777F600FED2F4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 7C6382E22727884000FED2F4 /* UIImageExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; @@ -59,7 +61,7 @@ 7C6382E7272883AC00FED2F4 /* Printer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Printer.swift; sourceTree = ""; }; 7C6382EF2729CCC300FED2F4 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; 7C6C3BC3275C05E000B6101F /* UserService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserService.swift; sourceTree = ""; }; - 7C6C3BC7275C06B400B6101F /* AuthModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthModel.swift; sourceTree = ""; }; + 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthResultsModel.swift; sourceTree = ""; }; 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseConstants.swift; sourceTree = ""; }; 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 7C6C3BCD275CFE4700B6101F /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; @@ -173,11 +175,12 @@ 8383504C27583FB6008847E1 /* SearchFriendsModel.swift */, 83369A4D273857020025F3D9 /* Structures.swift */, 7C6C3BC3275C05E000B6101F /* UserService.swift */, - 7C6C3BC7275C06B400B6101F /* AuthModel.swift */, + 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */, 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, 7C6C3BCF275CFEA900B6101F /* TaskService.swift */, 7C022800275D9C4800DFF8EC /* AuthService.swift */, + 7C022802275DAE6700DFF8EC /* ImageService.swift */, ); path = Models; sourceTree = ""; @@ -473,7 +476,7 @@ 83AF41A227431EB500CA8AAA /* FeedController.swift in Sources */, 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, - 7C6C3BC8275C06B400B6101F /* AuthModel.swift in Sources */, + 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */, 8383504227583E58008847E1 /* SignUpController.swift in Sources */, 8383504127583E58008847E1 /* SearchFriendsController.swift in Sources */, 8383504D27583FB6008847E1 /* SearchFriendsModel.swift in Sources */, @@ -489,6 +492,7 @@ 83369A4E273857020025F3D9 /* Structures.swift in Sources */, 7C022801275D9C4800DFF8EC /* AuthService.swift in Sources */, 8383503A27583E58008847E1 /* Onboarding.swift in Sources */, + 7C022803275DAE6700DFF8EC /* ImageService.swift in Sources */, 83AF41A027429B5500CA8AAA /* MainTabBarController.swift in Sources */, 7C6C3BD0275CFEA900B6101F /* TaskService.swift in Sources */, 8383503627583E58008847E1 /* CustomNavigationController.swift in Sources */, diff --git a/DoIt/Models/AuthModel.swift b/DoIt/Models/AuthResultsModel.swift similarity index 100% rename from DoIt/Models/AuthModel.swift rename to DoIt/Models/AuthResultsModel.swift diff --git a/DoIt/Models/AuthService.swift b/DoIt/Models/AuthService.swift index 1c9c22a..453d8ad 100644 --- a/DoIt/Models/AuthService.swift +++ b/DoIt/Models/AuthService.swift @@ -7,8 +7,8 @@ import Firebase -struct AuthService { - //create static instance service +class AuthService { + static let shared = AuthService() func signIn(email: String?, password: String?, completion: @escaping (AuthResult) -> Void) { diff --git a/DoIt/Models/FirebaseConstants.swift b/DoIt/Models/FirebaseConstants.swift index 027a346..b986d1b 100644 --- a/DoIt/Models/FirebaseConstants.swift +++ b/DoIt/Models/FirebaseConstants.swift @@ -7,9 +7,13 @@ import Firebase +let STORAGE_REF = Storage.storage().reference() + +let STORAGE_IMAGES = STORAGE_REF.child("images") + let DB_REF = Database.database().reference() -let REF_USERS = DB_REF.child("users") +let REF_USERS = DB_REF.child("users") let REF_TASKS = DB_REF.child("tasks") let REF_USER_TASKS = DB_REF.child("user-tasks") let REF_USER_FOLLOWERS = DB_REF.child("user-followers") diff --git a/DoIt/Models/ImageService.swift b/DoIt/Models/ImageService.swift new file mode 100644 index 0000000..904fb13 --- /dev/null +++ b/DoIt/Models/ImageService.swift @@ -0,0 +1,26 @@ +// +// ImageService.swift +// DoIt +// +// Created by Yulia on 06.12.2021. +// + +import Firebase +import UIKit + +class ImageService { + + static let shared = ImageService() + + func uploadImage(image: UIImage!) { + let filename = NSUUID().uuidString + let storageRef = STORAGE_IMAGES.child(filename) + if let imageData = image.pngData() { + storageRef.putData(imageData, metadata: nil) { (meta, error) in + storageRef.downloadURL { (url, error) in + guard let profileImageUrl = url?.absoluteString else {return} + } + } + } + } +} diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift index 272d64e..8ed50b0 100644 --- a/DoIt/Models/TaskService.swift +++ b/DoIt/Models/TaskService.swift @@ -8,7 +8,7 @@ import Firebase -struct TaskService { +class TaskService { static let shared = TaskService() diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index 6db7579..e542755 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -8,7 +8,7 @@ import Firebase -struct User { +class User { let uid: String let email: String diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index bde3b67..b4885e7 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -9,7 +9,7 @@ import Firebase typealias DatabaseCompletion = ((Error?, DatabaseReference)-> Void) -struct UserService { +class UserService { static let shared = UserService() @@ -21,9 +21,7 @@ struct UserService { completion(user) } } - - // TODO: - Update profile - + // TODO: - Update profile picture func updateUserData(user: User, completion: @escaping(DatabaseCompletion)){ @@ -67,20 +65,6 @@ struct UserService { } } -// func fetchUserFollowers(uid: String, completion: @escaping([User])->Void){ -// -// var users = [User]() -// -// REF_USER_FOLLOWERS.child(uid).observe(.childAdded) { (snapshot) in -// let usr = snapshot.key -// print("!!!", usr) -// guard let dictionary = snapshot.value as? [String: AnyObject] else {return} -// let user = User(uid: usr, dictionary: dictionary) -// users.append(user) -// completion(users) -// } -// } - func fetchUserFollowers(uid: String, completion: @escaping([String])->Void) { var users_uid = [String]() REF_USER_FOLLOWERS.child(uid).observe(.childAdded) { (snapshot) in diff --git a/DoIt/Views/Search Friends/SearchFriendsController.swift b/DoIt/Views/Search Friends/SearchFriendsController.swift index 6f417f2..57c47de 100644 --- a/DoIt/Views/Search Friends/SearchFriendsController.swift +++ b/DoIt/Views/Search Friends/SearchFriendsController.swift @@ -63,74 +63,9 @@ final class SearchFriendsController: UIViewController { // MARK: - Lifecycle -// struct AuthCredentials { -// let email: String -// let password: String -// let fullname: String -// let username: String -// } - -// struct AuthService { -// //create static instance service -// static let shared = AuthService() -// -// func logUserIn(withEmail email:String, password:String, completion:AuthDataResultCallback?){ -// Auth.auth().signIn(withEmail: email, password: password, completion: completion) -// print("DEBUG: Email is \(email), passward is \(password)") -// } -// -// -// func registerUser(credentials : AuthCredentials, completion: @escaping(Error?, DatabaseReference) -> Void) { -// // upload image data and download image url -// let email = credentials.email -// let password = credentials.password -// let username = credentials.username -// let fullname = credentials.fullname -// -// let filename = NSUUID().uuidString -// let storageRef = STORAGE_PROFILE_IMAGES.child(filename) -// -// } -// } - override func viewDidLoad() { super.viewDidLoad() configureUI() - print("111") - - AuthService.shared.signIn(email: "qwerty11111@gmail.com", password: "_1234678A") { (result) in - print(result) - } - var t : Task = Task(image: nil, title: "title", description: nil, deadline: Date.now, isDone: false, creatorId: 0, color: UIColor.red) - TaskService.shared.uploadTask(task: t) { error, result in - print(error, result) - } - - UserService.shared.followUser(uid: "hQekAm6zPvZ8xVgQAGQ0ceN6DpM2") { error, result in - print(error, result) - } - - UserService.shared.fetchUserFollowers(uid: "vkdW6hhGIHh1It2fjexEDpQ0tEB3") { user in - print("kkk", user) - } -// TaskService.shared.uploadTask(task: t) { error, result in -// print(error, result) -// } -// TaskService.shared.uploadTask(task: t) { error, result in -// print(error, result) -// } -// TaskService.shared.uploadTask(task: t) { error, result in -// print(error, result) -// } -// TaskService.shared.uploadTask(task: t) { error, result in -// print(error, result) -// } -// TaskService.shared.uploadTask(task: t) { error, result in -// print(error, result) -// } - UserService.shared.fetchUsers { user in - print(user) - } } // MARK: - Helpers From 11eda692d162d5f4ecfbd6fe6e15566c79a2ca5f Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 14 Dec 2021 01:24:24 +0300 Subject: [PATCH 05/28] A LOT OF CONFLICTS, CONFLICTS EVERYWHERE --- DoIt/Models/Structures.swift | 13 +- DoIt/Models/UserModel.swift | 11 +- DoIt/Models/UserService.swift | 12 +- .../Custom Views/CustomTabBarController.swift | 3 +- .../FeedCollectionViewCell.swift | 4 +- DoIt/Views/Feed/FeedController.swift | 46 +++--- .../Profile/ProfileEditViewController.swift | 2 +- .../Profile/ProfileFollowingUserCell.swift | 4 +- .../Views/Profile/ProfileViewController.swift | 8 +- DoIt/Views/Search Users/SearchUsersCell.swift | 6 +- DoIt/Views/Tasks/TasksController.swift | 14 +- Podfile.lock | 144 +++++++++++++++++- 12 files changed, 209 insertions(+), 58 deletions(-) diff --git a/DoIt/Models/Structures.swift b/DoIt/Models/Structures.swift index 9ac4145..f464954 100644 --- a/DoIt/Models/Structures.swift +++ b/DoIt/Models/Structures.swift @@ -6,6 +6,7 @@ // import UIKit +import Firebase class Task { let image: UIImage? @@ -17,21 +18,25 @@ class Task { let color: UIColor let chapterId: Int let creationTime: Date - let isMyTask: Bool - init(image: UIImage?, title: String, description: String?, deadline: Date?, isDone: Bool, creatorId: Int, color: UIColor, uid: String = "") { + var isMyTask: Bool { + return Auth.auth().currentUser?.uid == uid + } + + init(image: UIImage?, title: String, description: String?, deadline: Date?, isDone: Bool, color: UIColor, uid: String = "") { self.image = image self.title = title self.description = description self.deadline = deadline self.isDone = isDone - self.creatorId = creatorId self.uid = "" self.color = color + self.creationTime = Date() + self.chapterId = 0 } } struct Chapter { let title: String let color: UIColor -} \ No newline at end of file +} diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index 79d441c..ef184e3 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -8,22 +8,25 @@ import Firebase -class User { +class UserModel { - let image: UIImage? let uid: String let email: String var username: String var summary: String? + let image: UIImage? + let name: String? var isCurrentUser: Bool { return Auth.auth().currentUser?.uid == uid } - init(uid:String, dictionary:[String:AnyObject]) { + init(uid: String, dictionary: [String: AnyObject]) { self.uid = uid self.email = dictionary["email"] as? String ?? "" self.username = dictionary["username"] as? String ?? "" - self.summary = dictionary["summary"] as? String ?? "" + self.summary = dictionary["summary"] as? String + self.image = nil + self.name = nil } } diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index b4885e7..ea728fa 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -13,30 +13,30 @@ class UserService { static let shared = UserService() - func fetchUser(uid: String, completion: @escaping(User)->Void) { + func fetchUser(uid: String, completion: @escaping(UserModel)->Void) { REF_USERS.child(uid).observeSingleEvent(of: .value) { snapshot in guard let dictionary = snapshot.value as? [String: AnyObject] else {return} - let user = User(uid: uid, dictionary: dictionary) + let user = UserModel(uid: uid, dictionary: dictionary) completion(user) } } // TODO: - Update profile picture - func updateUserData(user: User, completion: @escaping(DatabaseCompletion)){ + func updateUserData(user: UserModel, completion: @escaping(DatabaseCompletion)){ guard let uid = Auth.auth().currentUser?.uid else {return} let values = ["username": user.username, "summary": user.summary ?? ""] REF_USERS.child(uid).updateChildValues(values, withCompletionBlock: completion) } - func fetchUsers(completion: @escaping([User])->Void) { - var users = [User]() + func fetchUsers(completion: @escaping([UserModel])->Void) { + var users = [UserModel]() REF_USERS.observe(.childAdded) { (snapshot) in let uid = snapshot.key guard let dictionary = snapshot.value as? [String: AnyObject] else {return} - let user = User(uid: uid, dictionary: dictionary) + let user = UserModel(uid: uid, dictionary: dictionary) users.append(user) completion(users) } diff --git a/DoIt/Views/Custom Views/CustomTabBarController.swift b/DoIt/Views/Custom Views/CustomTabBarController.swift index c5b1bd5..34c7abe 100644 --- a/DoIt/Views/Custom Views/CustomTabBarController.swift +++ b/DoIt/Views/Custom Views/CustomTabBarController.swift @@ -36,7 +36,8 @@ class CustomTabBarController: SwipeableTabBarController { //MARK: - Helpers private func configureViewControllers() { - let userModel = UserModel(image: nil, name: nil, login: "", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: true, isFollowed: false) + let temp: [String: String] = ["email" : "greagges@vk.com", "username": "myname", "password": "12345678"] + let userModel = UserModel(uid: "fafaf", dictionary: temp as [String: AnyObject]) let tasks = TasksController() tasks.userModel = userModel diff --git a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift index 6082a21..9c17624 100644 --- a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift +++ b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift @@ -79,10 +79,10 @@ class FeedCollectionViewCell: UICollectionViewCell { func configureCell(taskInfo: Task, userInfo: UserModel) { taskImage.image = taskInfo.image ?? UIImage.TaskIcons.defaultImage taskLabel.text = taskInfo.title - creatorLabel.text = "@" + userInfo.login + creatorLabel.text = "@" + userInfo.username guard let image = userInfo.image else { creatorImage.layoutIfNeeded() - creatorImage.setImageForName(userInfo.name ?? userInfo.login, circular: false, textAttributes: nil) + creatorImage.setImageForName(userInfo.name ?? userInfo.username, circular: false, textAttributes: nil) return } creatorImage.image = image diff --git a/DoIt/Views/Feed/FeedController.swift b/DoIt/Views/Feed/FeedController.swift index f8fa84c..c7cbf42 100644 --- a/DoIt/Views/Feed/FeedController.swift +++ b/DoIt/Views/Feed/FeedController.swift @@ -43,27 +43,27 @@ class FeedController: UIViewController { var userModel: UserModel? - var following = [ - UserModel(image: nil, name: "wfqjoa fda", login: "fqFJqow", summary: "My summery is", statistics: UserStatisticsModel(inProgress: "0", outdated: "1", done: "1", total: "2"), isMyScreen: false, isFollowed: true), - UserModel(image: nil, name: "gsgdsgger", login: "GIOWJEOG", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), - UserModel(image: nil, name: "greaiojgeo", login: "fwaojfoq", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: true, isFollowed: true), - UserModel(image: nil, name: "greaiojgeo", login: "gasgs", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), - UserModel(image: nil, name: "greaiojgeo", login: "gasg", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), - UserModel(image: nil, name: "greaiojgeo", login: "hdgh", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), - UserModel(image: nil, name: "greaiojgeo", login: "hgdhr", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), - UserModel(image: nil, name: "greaiojgeo", login: "gwaegfa", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true) + var following: [UserModel] = [ +// UserModel(image: nil, name: "wfqjoa fda", login: "fqFJqow", summary: "My summery is", statistics: UserStatisticsModel(inProgress: "0", outdated: "1", done: "1", total: "2"), isMyScreen: false, isFollowed: true), +// UserModel(image: nil, name: "gsgdsgger", login: "GIOWJEOG", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), +// UserModel(image: nil, name: "greaiojgeo", login: "fwaojfoq", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: true, isFollowed: true), +// UserModel(image: nil, name: "greaiojgeo", login: "gasgs", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), +// UserModel(image: nil, name: "greaiojgeo", login: "gasg", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), +// UserModel(image: nil, name: "greaiojgeo", login: "hdgh", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), +// UserModel(image: nil, name: "greaiojgeo", login: "hgdhr", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true), +// UserModel(image: nil, name: "greaiojgeo", login: "gwaegfa", summary: nil, statistics: UserStatisticsModel(inProgress: "0", outdated: "0", done: "0", total: "0"), isMyScreen: false, isFollowed: true) ] - var followingUsersTasks = [ - Task(image: UIImage(named: "bob"), title: "Поменять резину", description: nil, deadline: nil, isDone: true, creatorId: "GIOWJEOG", color: .black, chapterId: 0, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "duck"), title: "Купиить шапку", description: nil, deadline: nil, isDone: false, creatorId: "fqFJqow", color: .yellow, chapterId: 1, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "bob"), title: "Отдохнуть", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "fwaojfoq", color: .red, chapterId: 2, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "duck"), title: "Почистить зубы", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: true, creatorId: "fwaojfoq", color: .orange, chapterId: 3, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "duck"), title: "Занятие по танцам", description: nil, deadline: nil, isDone: false, creatorId: "fwaojfoq", color: .black, chapterId: 4, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "bob"), title: "Отдохнуть", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "GIOWJEOG", color: .red, chapterId: 5, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "duck"), title: "Почистить зубы", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: true, creatorId: "GIOWJEOG", color: .orange, chapterId: 6, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "duck"), title: "Оплатить счета", description: nil, deadline: nil, isDone: false, creatorId: "GIOWJEOG", color: .orange, chapterId: 7, creationTime: Date(), isMyTask: false), - Task(image: UIImage(named: "bob"), title: "Отдохнуть", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "GIOWJEOG", color: .red, chapterId: 8, creationTime: Date(), isMyTask: false) + var followingUsersTasks: [Task] = [ +// Task(image: UIImage(named: "bob"), title: "Поменять резину", description: nil, deadline: nil, isDone: true, creatorId: "GIOWJEOG", color: .black, chapterId: 0, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "duck"), title: "Купиить шапку", description: nil, deadline: nil, isDone: false, creatorId: "fqFJqow", color: .yellow, chapterId: 1, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "bob"), title: "Отдохнуть", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "fwaojfoq", color: .red, chapterId: 2, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "duck"), title: "Почистить зубы", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: true, creatorId: "fwaojfoq", color: .orange, chapterId: 3, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "duck"), title: "Занятие по танцам", description: nil, deadline: nil, isDone: false, creatorId: "fwaojfoq", color: .black, chapterId: 4, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "bob"), title: "Отдохнуть", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "GIOWJEOG", color: .red, chapterId: 5, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "duck"), title: "Почистить зубы", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: true, creatorId: "GIOWJEOG", color: .orange, chapterId: 6, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "duck"), title: "Оплатить счета", description: nil, deadline: nil, isDone: false, creatorId: "GIOWJEOG", color: .orange, chapterId: 7, creationTime: Date(), isMyTask: false), +// Task(image: UIImage(named: "bob"), title: "Отдохнуть", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "GIOWJEOG", color: .red, chapterId: 8, creationTime: Date(), isMyTask: false) ] private var swipeToMyTasks: Bool = false @@ -88,8 +88,8 @@ class FeedController: UIViewController { } private func configureNavigationController() { - navigationItem.title = (userModel?.isMyScreen ?? false) ? FeedStrings.header.rawValue.localized : "Feed" - navigationItem.rightBarButtonItem = (userModel?.isMyScreen ?? false) ? searchButton : nil + navigationItem.title = (userModel?.isCurrentUser ?? false) ? FeedStrings.header.rawValue.localized : "Feed" + navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil } private func layoutCollection() { @@ -108,11 +108,11 @@ extension FeedController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FeedCollectionViewCell.self.description(), for: indexPath) as? FeedCollectionViewCell else { return .init(frame: .zero) } - guard let userInfo = following.first(where: { $0.login == followingUsersTasks[indexPath.row].creatorId }) else { return .init(frame: .zero) } + guard let userInfo = following.first(where: { $0.username == followingUsersTasks[indexPath.row].uid }) else { return .init(frame: .zero) } cell.tapOnUser = { [weak self] in let profileViewController = ProfileViewController() profileViewController.userModel = userInfo - profileViewController.userTasksModel = UserTasksModel(login: userInfo.login, tasks: self?.followingUsersTasks.filter({ $0.creatorId == userInfo.login }) ?? []) + profileViewController.userTasksModel = UserTasksModel(login: userInfo.username, tasks: self?.followingUsersTasks.filter({ $0.uid == userInfo.username }) ?? []) self?.navigationController?.pushViewController(profileViewController, animated: true) } cell.configureCell(taskInfo: followingUsersTasks[indexPath.row], userInfo: userInfo) diff --git a/DoIt/Views/Profile/ProfileEditViewController.swift b/DoIt/Views/Profile/ProfileEditViewController.swift index 4f65f6a..c2dfef1 100644 --- a/DoIt/Views/Profile/ProfileEditViewController.swift +++ b/DoIt/Views/Profile/ProfileEditViewController.swift @@ -146,7 +146,7 @@ final class ProfileEditViewController: UIViewController { summaryTextView.text = userModel.summary guard let image = userModel.image else { profileImageView.layoutIfNeeded() - profileImageView.setImageForName(userModel.name ?? userModel.login, circular: false, textAttributes: nil) + profileImageView.setImageForName(userModel.name ?? userModel.username, circular: false, textAttributes: nil) return } profileImageView.image = image diff --git a/DoIt/Views/Profile/ProfileFollowingUserCell.swift b/DoIt/Views/Profile/ProfileFollowingUserCell.swift index ca0b52b..644fe11 100644 --- a/DoIt/Views/Profile/ProfileFollowingUserCell.swift +++ b/DoIt/Views/Profile/ProfileFollowingUserCell.swift @@ -51,10 +51,10 @@ class ProfileFollowingUserCell: UICollectionViewCell { // MARK: - Helpers func configureCell(with: UserModel) { - loginLabel.text = "@" + with.login + loginLabel.text = "@" + with.username guard let image = with.image else { profileImageView.layoutIfNeeded() - profileImageView.setImageForName(with.name ?? with.login, circular: false, textAttributes: nil) + profileImageView.setImageForName(with.name ?? with.username, circular: false, textAttributes: nil) return } profileImageView.image = image diff --git a/DoIt/Views/Profile/ProfileViewController.swift b/DoIt/Views/Profile/ProfileViewController.swift index c4eb3bc..fe41cbf 100644 --- a/DoIt/Views/Profile/ProfileViewController.swift +++ b/DoIt/Views/Profile/ProfileViewController.swift @@ -295,9 +295,9 @@ class ProfileViewController: UIViewController { private func configureCells() { guard let userModel = userModel else { return } - configureHeader(image: userModel.image, name: userModel.name, login: userModel.login, isFollowed: userModel.isFollowed, isMyScreen: userModel.isMyScreen) + configureHeader(image: userModel.image, name: userModel.name, login: userModel.username, isFollowed: false, isMyScreen: false) configureInformation(summary: userModel.summary) - configureStatistics(with: userModel.statistics) +// configureStatistics(with: userModel.statistics) configureTasks(with: userTasksModel?.tasks ?? []) @@ -309,7 +309,7 @@ class ProfileViewController: UIViewController { layoutScrollView() layoutCellsStackView() - configureNavigationController(title: userModel?.login ?? "", isMyScreen: userModel?.isMyScreen ?? false) + configureNavigationController(title: userModel?.username ?? "", isMyScreen: userModel?.isCurrentUser ?? false) configureCells() } @@ -695,7 +695,7 @@ extension ProfileViewController { @objc private func showAllTasks() { guard let userModel = userModel else { return } - guard !userModel.isMyScreen else { + guard !userModel.isCurrentUser else { NotificationCenter.default.post(name: .openTasksFromProfile, object: nil) navigationController?.popToRootViewController(animated: true) return diff --git a/DoIt/Views/Search Users/SearchUsersCell.swift b/DoIt/Views/Search Users/SearchUsersCell.swift index fdaab7c..9daf14c 100644 --- a/DoIt/Views/Search Users/SearchUsersCell.swift +++ b/DoIt/Views/Search Users/SearchUsersCell.swift @@ -91,10 +91,10 @@ final class SearchUsersCell: UITableViewCell { // MARK: - Helpers func configureCell(with model: UserModel) { - loginLabel.text = model.login + loginLabel.text = model.username configureSummeryLabel(text: model.summary) - configureFollowButton(isFollowed: model.isFollowed) - configureImageView(image: model.image, name: model.name, login: model.login) +// configureFollowButton(isFollowed: model.isFollowed) + configureImageView(image: model.image, name: model.name, login: model.username) } private func configureImageView(image: UIImage?, name: String?, login: String) { diff --git a/DoIt/Views/Tasks/TasksController.swift b/DoIt/Views/Tasks/TasksController.swift index 9148bee..3206fff 100644 --- a/DoIt/Views/Tasks/TasksController.swift +++ b/DoIt/Views/Tasks/TasksController.swift @@ -53,11 +53,11 @@ class TasksController: UIViewController { return tableView }() - var tasks = [ - Task(image: UIImage(named: "bob"), title: "Task 1: Get ready for an exam", description: nil, deadline: nil, isDone: true, creatorId: "1", color: .black, chapterId: 0, creationTime: Date(), isMyTask: true), - Task(image: UIImage(named: "bob"), title: "Task 2: Get ready for an exam", description: nil, deadline: nil, isDone: false, creatorId: "2", color: .yellow, chapterId: 1, creationTime: Date(), isMyTask: true), - Task(image: UIImage(named: "bob"), title: "Task 3: Get ready for an exam", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "2", color: .red, chapterId: 2, creationTime: Date(), isMyTask: true), - Task(image: UIImage(named: "bob"), title: "Task 4: Get ready for an exam", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: Date(timeIntervalSinceNow: 50), isDone: true, creatorId: "1", color: .orange, chapterId: 3, creationTime: Date(), isMyTask: true) + var tasks: [Task] = [ +// Task(image: UIImage(named: "bob"), title: "Task 1: Get ready for an exam", description: nil, deadline: nil, isDone: true, creatorId: "1", color: .black, chapterId: 0, creationTime: Date(), isMyTask: true), +// Task(image: UIImage(named: "bob"), title: "Task 2: Get ready for an exam", description: nil, deadline: nil, isDone: false, creatorId: "2", color: .yellow, chapterId: 1, creationTime: Date(), isMyTask: true), +// Task(image: UIImage(named: "bob"), title: "Task 3: Get ready for an exam", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "2", color: .red, chapterId: 2, creationTime: Date(), isMyTask: true), +// Task(image: UIImage(named: "bob"), title: "Task 4: Get ready for an exam", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: Date(timeIntervalSinceNow: 50), isDone: true, creatorId: "1", color: .orange, chapterId: 3, creationTime: Date(), isMyTask: true) ] private var selectedTasks: [Task]? { @@ -84,7 +84,7 @@ class TasksController: UIViewController { //MARK: - Private Methods private func configureNavigationController() { navigationItem.title = TasksStrings.header.rawValue.localized - navigationItem.rightBarButtonItem = (userModel?.isMyScreen ?? false) ? profileButton : nil + navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? profileButton : nil } private func layoutCollection() { @@ -162,7 +162,7 @@ extension TasksController { navigationController?.pushViewController(profileViewController, animated: true) return } - profileViewController.userTasksModel = UserTasksModel(login: userModel.login, tasks: tasks) + profileViewController.userTasksModel = UserTasksModel(login: userModel.username, tasks: tasks) navigationController?.pushViewController(profileViewController, animated: true) } } diff --git a/Podfile.lock b/Podfile.lock index 8954177..6ef48ed 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,24 +1,166 @@ PODS: - EasyNotificationBadge (1.2.5) + - Firebase/Auth (8.10.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 8.10.0) + - Firebase/Core (8.10.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 8.10.0) + - Firebase/CoreOnly (8.10.0): + - FirebaseCore (= 8.10.0) + - Firebase/Database (8.10.0): + - Firebase/CoreOnly + - FirebaseDatabase (~> 8.10.0) + - Firebase/Storage (8.10.0): + - Firebase/CoreOnly + - FirebaseStorage (~> 8.10.0) + - FirebaseAnalytics (8.10.0): + - FirebaseAnalytics/AdIdSupport (= 8.10.0) + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - FirebaseAnalytics/AdIdSupport (8.10.0): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleAppMeasurement (= 8.10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - FirebaseAuth (8.10.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/Environment (~> 7.6) + - GTMSessionFetcher/Core (~> 1.5) + - FirebaseCore (8.10.0): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - FirebaseCoreDiagnostics (8.10.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - nanopb (~> 2.30908.0) + - FirebaseDatabase (8.10.0): + - FirebaseCore (~> 8.0) + - leveldb-library (~> 1.22) + - FirebaseInstallations (8.10.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/UserDefaults (~> 7.6) + - PromisesObjC (< 3.0, >= 1.2) + - FirebaseStorage (8.10.0): + - FirebaseCore (~> 8.0) + - GTMSessionFetcher/Core (~> 1.5) + - GoogleAppMeasurement (8.10.0): + - GoogleAppMeasurement/AdIdSupport (= 8.10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (8.10.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleDataTransport (9.1.2): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.6.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.6.0): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.6.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.6.0)" + - GoogleUtilities/Reachability (7.6.0): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.6.0): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (1.7.0) - InitialsImageView (0.7.0) + - leveldb-library (1.22.1) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - PromisesObjC (2.0.0) - SwipeableTabBarController (3.4.2) DEPENDENCIES: - EasyNotificationBadge + - Firebase/Auth + - Firebase/Core + - Firebase/Database + - Firebase/Storage - InitialsImageView - SwipeableTabBarController SPEC REPOS: trunk: - EasyNotificationBadge + - Firebase + - FirebaseAnalytics + - FirebaseAuth + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseDatabase + - FirebaseInstallations + - FirebaseStorage + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleUtilities + - GTMSessionFetcher - InitialsImageView + - leveldb-library + - nanopb + - PromisesObjC - SwipeableTabBarController SPEC CHECKSUMS: EasyNotificationBadge: a3ebbcb1de0c0558e102e954380c75801f352702 + Firebase: 44213362f1dcc52555b935dc925ed35ac55f1b20 + FirebaseAnalytics: 319c9b3b1bdd400d60e2f415dff0c5f6959e6760 + FirebaseAuth: 59a2d2b933b5b79e18fb1e6ad230c6abdaa73d26 + FirebaseCore: 04186597c095da37d90ff9fd3e53bc61a1ff2440 + FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18 + FirebaseDatabase: 5f3e83b0a0d8759378fbd5d05661244d14dfbbb0 + FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425 + FirebaseStorage: 815410224b548172c578f02554a86bbc8f817f50 + GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 + GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 + GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 + GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 InitialsImageView: 7a416d36fc6df5434198664db28a3ffb0228426d + leveldb-library: 50c7b45cbd7bf543c81a468fe557a16ae3db8729 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 SwipeableTabBarController: 9a218bdee9426d1bfe36d7962f852024bb08d61b -PODFILE CHECKSUM: b12fb4a56fe0bc7746ec465cf8cbf696c76ee99b +PODFILE CHECKSUM: e86f5144469dc5aa19b2281cf74b6d407d9d4397 COCOAPODS: 1.11.2 From 4972334408ea136db4cfe587e27fa737155ad281 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 14 Dec 2021 04:04:31 +0300 Subject: [PATCH 06/28] nothing --- DoIt.xcodeproj/project.pbxproj | 32 ++++++++++++------- DoIt/Models/AuthService.swift | 1 - DoIt/Models/UserModel.swift | 9 ++++++ DoIt/Models/UserStatisticsModel.swift | 15 --------- DoIt/ViewModels/SearchUsersViewModel.swift | 20 ++++++++++++ DoIt/Views/Feed/FeedController.swift | 6 ++-- .../Views/Profile/ProfileViewController.swift | 28 ++++++++++++---- .../Search Users/SearchUsersController.swift | 15 +++++---- 8 files changed, 85 insertions(+), 41 deletions(-) delete mode 100644 DoIt/Models/UserStatisticsModel.swift create mode 100644 DoIt/ViewModels/SearchUsersViewModel.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 92908b3..df8b23f 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -7,9 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 5038435A2AA2F8CD2F8BEF43 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */; }; - 7C022801275D9C4800DFF8EC /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022800275D9C4800DFF8EC /* AuthService.swift */; }; - 7C022803275DAE6700DFF8EC /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022802275DAE6700DFF8EC /* ImageService.swift */; }; 7C6382DD272777F600FED2F4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7C6382DF272777F600FED2F4 /* Localizable.strings */; }; 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E22727884000FED2F4 /* UIImageExtension.swift */; }; 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E52728807900FED2F4 /* UIColorsExtension.swift */; }; @@ -19,8 +16,6 @@ 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */; }; 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */; }; 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */; }; - 7C6C3BCE275CFE4700B6101F /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCD275CFE4700B6101F /* UserModel.swift */; }; - 7C6C3BD0275CFEA900B6101F /* TaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCF275CFEA900B6101F /* TaskService.swift */; }; 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */; }; 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */; }; 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; @@ -47,9 +42,11 @@ 83AF41A827431F9600CA8AAA /* FeedCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83AF41A727431F9600CA8AAA /* FeedCollectionViewCell.swift */; }; D893BC3F82A1BFD5850B5F99 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A133F16700AA4CCB04ED3F5D /* Pods_DoIt.framework */; }; E40B7953275FA1DA002DE826 /* KeyboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40B7952275FA1DA002DE826 /* KeyboardManager.swift */; }; + E455B5D727681AD20059130D /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D527681AD10059130D /* AuthService.swift */; }; + E455B5D827681AD20059130D /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D627681AD10059130D /* ImageService.swift */; }; + E455B5DA276820E60059130D /* SearchUsersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D9276820E60059130D /* SearchUsersViewModel.swift */; }; E49D6B20275BEF0C007C9A97 /* UserTasksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */; }; E4A95D4B275BE99A00EE3F59 /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D48275BE99900EE3F59 /* UserModel.swift */; }; - E4A95D4C275BE99A00EE3F59 /* UserStatisticsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D49275BE99A00EE3F59 /* UserStatisticsModel.swift */; }; E4A95D4D275BE99A00EE3F59 /* UserFollowingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */; }; E4A95D59275BEA8500EE3F59 /* ProfileEditViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D56275BEA8500EE3F59 /* ProfileEditViewController.swift */; }; E4A95D5A275BEA8600EE3F59 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D57275BEA8500EE3F59 /* ProfileViewController.swift */; }; @@ -101,9 +98,11 @@ 83AF41A727431F9600CA8AAA /* FeedCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCollectionViewCell.swift; sourceTree = ""; }; A133F16700AA4CCB04ED3F5D /* Pods_DoIt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DoIt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E40B7952275FA1DA002DE826 /* KeyboardManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardManager.swift; sourceTree = ""; }; + E455B5D527681AD10059130D /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; + E455B5D627681AD10059130D /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; + E455B5D9276820E60059130D /* SearchUsersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchUsersViewModel.swift; sourceTree = ""; }; E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTasksModel.swift; sourceTree = ""; }; E4A95D48275BE99900EE3F59 /* UserModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; - E4A95D49275BE99A00EE3F59 /* UserStatisticsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserStatisticsModel.swift; sourceTree = ""; }; E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserFollowingModel.swift; sourceTree = ""; }; E4A95D56275BEA8500EE3F59 /* ProfileEditViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileEditViewController.swift; sourceTree = ""; }; E4A95D57275BEA8500EE3F59 /* ProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; @@ -152,6 +151,7 @@ 7C6382CF2725C4F700FED2F4 /* ViewModels */ = { isa = PBXGroup; children = ( + E455B5D9276820E60059130D /* SearchUsersViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -185,9 +185,10 @@ 7C6382D52725C5E800FED2F4 /* Models */ = { isa = PBXGroup; children = ( + E455B5D527681AD10059130D /* AuthService.swift */, + E455B5D627681AD10059130D /* ImageService.swift */, E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */, E4A95D48275BE99900EE3F59 /* UserModel.swift */, - E4A95D49275BE99A00EE3F59 /* UserStatisticsModel.swift */, E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */, 83369A4D273857020025F3D9 /* Structures.swift */, 7C6C3BC3275C05E000B6101F /* UserService.swift */, @@ -195,8 +196,6 @@ 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, 7C6C3BCF275CFEA900B6101F /* TaskService.swift */, - 7C022800275D9C4800DFF8EC /* AuthService.swift */, - 7C022802275DAE6700DFF8EC /* ImageService.swift */, ); path = Models; sourceTree = ""; @@ -220,6 +219,7 @@ 7CAC5DCB27232C6000E2D70B /* Products */, 44250C609B2DD82274CFF714 /* Pods */, 7D03E0CC68346392C8995C87 /* Frameworks */, + E455B5D42767EA5C0059130D /* Recovered References */, ); sourceTree = ""; }; @@ -371,6 +371,14 @@ path = KeyboardManager; sourceTree = ""; }; + E455B5D42767EA5C0059130D /* Recovered References */ = { + isa = PBXGroup; + children = ( + 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */, + ); + name = "Recovered References"; + sourceTree = ""; + }; E4A95D4F275BEA0E00EE3F59 /* Profile */ = { isa = PBXGroup; children = ( @@ -505,23 +513,25 @@ 83AF41A827431F9600CA8AAA /* FeedCollectionViewCell.swift in Sources */, 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */, 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */, + E455B5D727681AD20059130D /* AuthService.swift in Sources */, 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */, 8383504027583E58008847E1 /* SearchUsersCell.swift in Sources */, E49D6B20275BEF0C007C9A97 /* UserTasksModel.swift in Sources */, E4A95D59275BEA8500EE3F59 /* ProfileEditViewController.swift in Sources */, 83AF41A227431EB500CA8AAA /* FeedController.swift in Sources */, 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, + E455B5D827681AD20059130D /* ImageService.swift in Sources */, 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */, 8383504227583E58008847E1 /* SignUpController.swift in Sources */, 8383504127583E58008847E1 /* SearchUsersController.swift in Sources */, - E4A95D4C275BE99A00EE3F59 /* UserStatisticsModel.swift in Sources */, E4A95D4B275BE99A00EE3F59 /* UserModel.swift in Sources */, 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */, E40B7953275FA1DA002DE826 /* KeyboardManager.swift in Sources */, E4A95D5B275BEA8600EE3F59 /* ProfileFollowingUserCell.swift in Sources */, 7C6382F02729CCC300FED2F4 /* StringExtension.swift in Sources */, 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */, + E455B5DA276820E60059130D /* SearchUsersViewModel.swift in Sources */, 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */, 8383503727583E58008847E1 /* SignInController.swift in Sources */, 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */, diff --git a/DoIt/Models/AuthService.swift b/DoIt/Models/AuthService.swift index 453d8ad..47605f9 100644 --- a/DoIt/Models/AuthService.swift +++ b/DoIt/Models/AuthService.swift @@ -27,7 +27,6 @@ class AuthService { UserDefaults.standard.set(uid, forKey: "current_user") - completion(.success) } } diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index ef184e3..6c8296b 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -29,4 +29,13 @@ class UserModel { self.image = nil self.name = nil } + + init(username: String) { + self.uid = "" + self.email = "" + self.username = username + self.summary = nil + self.image = nil + self.name = nil + } } diff --git a/DoIt/Models/UserStatisticsModel.swift b/DoIt/Models/UserStatisticsModel.swift deleted file mode 100644 index 0bda8f7..0000000 --- a/DoIt/Models/UserStatisticsModel.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// UserStatisticsModel.swift -// DoIt -// -// Created by Шестаков Никита on 23.11.2021. -// - -import Foundation - -struct UserStatisticsModel { - let inProgress: String - let outdated: String - let done: String - let total: String -} diff --git a/DoIt/ViewModels/SearchUsersViewModel.swift b/DoIt/ViewModels/SearchUsersViewModel.swift new file mode 100644 index 0000000..42d5930 --- /dev/null +++ b/DoIt/ViewModels/SearchUsersViewModel.swift @@ -0,0 +1,20 @@ +// +// SearchUsersViewModel.swift +// DoIt +// +// Created by Шестаков Никита on 14.12.2021. +// + +import Foundation + +class SearchUsersViewModel { + var userModel: UserModel? + + var userModels: [UserModel] = [] + + var filteredUsersModel: [UserModel]? { + didSet { +// tableView.reloadSections(IndexSet(integer: 0), with: .fade) + } + } +} diff --git a/DoIt/Views/Feed/FeedController.swift b/DoIt/Views/Feed/FeedController.swift index c7cbf42..20e6532 100644 --- a/DoIt/Views/Feed/FeedController.swift +++ b/DoIt/Views/Feed/FeedController.swift @@ -88,8 +88,10 @@ class FeedController: UIViewController { } private func configureNavigationController() { - navigationItem.title = (userModel?.isCurrentUser ?? false) ? FeedStrings.header.rawValue.localized : "Feed" - navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil + navigationItem.title = (userModel?.isCurrentUser ?? false) ? FeedStrings.header.rawValue.localized : FeedStrings.allTasksHeader.rawValue.localized + navigationItem.rightBarButtonItem = searchButton +// navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil + } private func layoutCollection() { diff --git a/DoIt/Views/Profile/ProfileViewController.swift b/DoIt/Views/Profile/ProfileViewController.swift index fe41cbf..66caa3f 100644 --- a/DoIt/Views/Profile/ProfileViewController.swift +++ b/DoIt/Views/Profile/ProfileViewController.swift @@ -297,7 +297,7 @@ class ProfileViewController: UIViewController { guard let userModel = userModel else { return } configureHeader(image: userModel.image, name: userModel.name, login: userModel.username, isFollowed: false, isMyScreen: false) configureInformation(summary: userModel.summary) -// configureStatistics(with: userModel.statistics) + configureStatistics(tasks: userTasksModel?.tasks ?? []) configureTasks(with: userTasksModel?.tasks ?? []) @@ -607,11 +607,27 @@ extension ProfileViewController { // MARK: - Statistics View - private func configureStatistics(with: UserStatisticsModel) { - inProgressNumberLabel.text = with.inProgress - outdatedNumberLabel.text = with.outdated - doneNumberLabel.text = with.done - totalNumberLabel.text = with.total + private func configureStatistics(tasks: [Task]) { + DispatchQueue.global().async { + var done = 0 + var outdated = 0 + var inProgress = 0 + let total = tasks.count + let currentDate = Date() + tasks.forEach { task in + guard !task.isDone else { done += 1; return } + guard let deadline = task.deadline else { inProgress += 1; return } + guard deadline < currentDate else { outdated += 1; return } + inProgress += 1 + } + + DispatchQueue.main.async { [weak self] in + self?.inProgressNumberLabel.text = "\(inProgress)" + self?.outdatedNumberLabel.text = "\(outdated)" + self?.doneNumberLabel.text = "\(done)" + self?.totalNumberLabel.text = "\(total)" + } + } } // MARK: - Tasks View diff --git a/DoIt/Views/Search Users/SearchUsersController.swift b/DoIt/Views/Search Users/SearchUsersController.swift index 725918c..218f538 100644 --- a/DoIt/Views/Search Users/SearchUsersController.swift +++ b/DoIt/Views/Search Users/SearchUsersController.swift @@ -61,9 +61,7 @@ final class SearchUsersController: UIViewController { return label }() - var userModel: UserModel? - - private var userModels: [UserModel] = [] + var viewModel: SearchUsersViewModel = SearchUsersViewModel() // MARK: - Lifecycle @@ -127,21 +125,21 @@ extension SearchUsersController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let profileViewController = ProfileViewController() - profileViewController.userModel = userModels[indexPath.row] + profileViewController.userModel = viewModel.filteredUsersModel?[indexPath.row] ?? viewModel.userModels[indexPath.row] navigationController?.pushViewController(profileViewController, animated: true) } } extension SearchUsersController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return userModels.count + return viewModel.filteredUsersModel?.count ?? viewModel.userModels.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchUsersCell.self), for: indexPath) as? SearchUsersCell else { return .init() } - cell.configureCell(with: userModels[indexPath.row]) + cell.configureCell(with: viewModel.filteredUsersModel?[indexPath.row] ?? viewModel.userModels[indexPath.row]) return cell } } @@ -149,6 +147,11 @@ extension SearchUsersController: UITableViewDataSource { // MARK: - Actions extension SearchUsersController: UISearchBarDelegate { + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { + guard !searchText.isEmpty else { viewModel.filteredUsersModel = nil; return } + viewModel.filteredUsersModel = viewModel.userModels.filter { $0.username.lowercased().contains(searchText.lowercased()) } + } + func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() searchBar.text = nil From acd97914001c5a5b4e75d067343227cf74e9df9b Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 14 Dec 2021 15:42:29 +0300 Subject: [PATCH 07/28] users vm --- DoIt.xcodeproj/project.pbxproj | 14 ++- DoIt/Models/TaskService.swift | 6 +- DoIt/Models/UserModel.swift | 14 +-- DoIt/ViewModels/ProfileEditViewModel.swift | 56 +++++++++++ DoIt/ViewModels/ProfileViewModel.swift | 75 +++++++++++++++ DoIt/ViewModels/SearchUsersViewModel.swift | 91 ++++++++++++++++-- DoIt/Views/Feed/FeedController.swift | 4 +- .../Profile/ProfileEditViewController.swift | 16 +++- .../Views/Profile/ProfileViewController.swift | 94 +++++++++++++------ DoIt/Views/Search Users/SearchUsersCell.swift | 22 ++++- .../Search Users/SearchUsersController.swift | 73 +++++++++++++- DoIt/Views/Tasks/TasksController.swift | 4 +- 12 files changed, 404 insertions(+), 65 deletions(-) create mode 100644 DoIt/ViewModels/ProfileEditViewModel.swift create mode 100644 DoIt/ViewModels/ProfileViewModel.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index df8b23f..e736642 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -42,6 +42,9 @@ 83AF41A827431F9600CA8AAA /* FeedCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83AF41A727431F9600CA8AAA /* FeedCollectionViewCell.swift */; }; D893BC3F82A1BFD5850B5F99 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A133F16700AA4CCB04ED3F5D /* Pods_DoIt.framework */; }; E40B7953275FA1DA002DE826 /* KeyboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40B7952275FA1DA002DE826 /* KeyboardManager.swift */; }; + E417CFD727689B2300C6E6B5 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E417CFD627689B2300C6E6B5 /* ProfileViewModel.swift */; }; + E417CFD927689D8A00C6E6B5 /* TaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E417CFD827689D8A00C6E6B5 /* TaskService.swift */; }; + E417CFDB2768BE1800C6E6B5 /* ProfileEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E417CFDA2768BE1800C6E6B5 /* ProfileEditViewModel.swift */; }; E455B5D727681AD20059130D /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D527681AD10059130D /* AuthService.swift */; }; E455B5D827681AD20059130D /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D627681AD10059130D /* ImageService.swift */; }; E455B5DA276820E60059130D /* SearchUsersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D9276820E60059130D /* SearchUsersViewModel.swift */; }; @@ -69,7 +72,6 @@ 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseConstants.swift; sourceTree = ""; }; 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 7C6C3BCD275CFE4700B6101F /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; - 7C6C3BCF275CFEA900B6101F /* TaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskService.swift; sourceTree = ""; }; 7CAC5DCA27232C6000E2D70B /* DoIt.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DoIt.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -98,6 +100,9 @@ 83AF41A727431F9600CA8AAA /* FeedCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedCollectionViewCell.swift; sourceTree = ""; }; A133F16700AA4CCB04ED3F5D /* Pods_DoIt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DoIt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E40B7952275FA1DA002DE826 /* KeyboardManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardManager.swift; sourceTree = ""; }; + E417CFD627689B2300C6E6B5 /* ProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewModel.swift; sourceTree = ""; }; + E417CFD827689D8A00C6E6B5 /* TaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskService.swift; sourceTree = ""; }; + E417CFDA2768BE1800C6E6B5 /* ProfileEditViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEditViewModel.swift; sourceTree = ""; }; E455B5D527681AD10059130D /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; E455B5D627681AD10059130D /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; E455B5D9276820E60059130D /* SearchUsersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchUsersViewModel.swift; sourceTree = ""; }; @@ -152,6 +157,8 @@ isa = PBXGroup; children = ( E455B5D9276820E60059130D /* SearchUsersViewModel.swift */, + E417CFD627689B2300C6E6B5 /* ProfileViewModel.swift */, + E417CFDA2768BE1800C6E6B5 /* ProfileEditViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -195,7 +202,7 @@ 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */, 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, - 7C6C3BCF275CFEA900B6101F /* TaskService.swift */, + E417CFD827689D8A00C6E6B5 /* TaskService.swift */, ); path = Models; sourceTree = ""; @@ -512,14 +519,17 @@ 8383503B27583E58008847E1 /* OnboardingCell.swift in Sources */, 83AF41A827431F9600CA8AAA /* FeedCollectionViewCell.swift in Sources */, 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */, + E417CFD727689B2300C6E6B5 /* ProfileViewModel.swift in Sources */, 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */, E455B5D727681AD20059130D /* AuthService.swift in Sources */, + E417CFD927689D8A00C6E6B5 /* TaskService.swift in Sources */, 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */, 8383504027583E58008847E1 /* SearchUsersCell.swift in Sources */, E49D6B20275BEF0C007C9A97 /* UserTasksModel.swift in Sources */, E4A95D59275BEA8500EE3F59 /* ProfileEditViewController.swift in Sources */, 83AF41A227431EB500CA8AAA /* FeedController.swift in Sources */, 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, + E417CFDB2768BE1800C6E6B5 /* ProfileEditViewModel.swift in Sources */, E455B5D827681AD20059130D /* ImageService.swift in Sources */, 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */, diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift index 8ed50b0..dd357f3 100644 --- a/DoIt/Models/TaskService.swift +++ b/DoIt/Models/TaskService.swift @@ -14,7 +14,7 @@ class TaskService { func uploadTask(task: Task, completion: @escaping(Error?, DatabaseReference)->Void){ guard let uid = Auth.auth().currentUser?.uid else {return} - var values = [ + let values = [ "title": task.title, "description": task.description ?? "", "deadline": Int(task.deadline?.timeIntervalSince1970 ?? 0), @@ -42,7 +42,6 @@ class TaskService { guard let description = dictionary["description"] as? String else { return } guard let deadline = dictionary["deadline"] as? Int else { return } guard let isDone = dictionary["is_done"] as? Bool else { return } - guard let creatorId = dictionary["uid"] as? String else { return } guard let color = dictionary["color"] as? [Int] else { return } @@ -54,7 +53,6 @@ class TaskService { description: description, deadline: Date(timeIntervalSince1970: TimeInterval(deadline)), isDone: isDone, - creatorId: 0, color: UIColor(red: CGFloat(color[0]) * 255.0, green: CGFloat(color[1]) * 255.0, blue: CGFloat(color[2]) * 255.0, alpha: 1.0) ) completion(task) @@ -62,7 +60,7 @@ class TaskService { } } - func fetchTasks(forUser user: User, completion: @escaping([Task]) -> Void) { + func fetchTasks(forUser user: UserModel, completion: @escaping([Task]) -> Void) { var tasks = [Task]() REF_USER_TASKS.child(user.uid).observe(.childAdded) { snapshot in let taskId = snapshot.key diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index 6c8296b..7ec9bc3 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -21,6 +21,8 @@ class UserModel { return Auth.auth().currentUser?.uid == uid } + var isFollowed: Bool? + init(uid: String, dictionary: [String: AnyObject]) { self.uid = uid self.email = dictionary["email"] as? String ?? "" @@ -30,12 +32,12 @@ class UserModel { self.name = nil } - init(username: String) { - self.uid = "" - self.email = "" + init(uid: String, email: String, username: String, summary: String?, image: UIImage?, name: String?) { + self.uid = uid + self.email = email self.username = username - self.summary = nil - self.image = nil - self.name = nil + self.summary = summary + self.image = image + self.name = name } } diff --git a/DoIt/ViewModels/ProfileEditViewModel.swift b/DoIt/ViewModels/ProfileEditViewModel.swift new file mode 100644 index 0000000..95ed8b2 --- /dev/null +++ b/DoIt/ViewModels/ProfileEditViewModel.swift @@ -0,0 +1,56 @@ +// +// ProfileEditViewModel.swift +// DoIt +// +// Created by Шестаков Никита on 14.12.2021. +// + +import Foundation +import UIKit + +final class ProfileEditViewModel { + private let userService = UserService.shared + var userModel: Observable = Observable() + + func updateUserProfile(image: UIImage?, name: String?, username: String, summary: String?) { + DispatchQueue.global().sync { [weak self] in + guard let userModel = userModel.value else { + return + } + var wasChanged = false + + var newImage = userModel.image + if let image = image, image != newImage { + newImage = image + wasChanged = true + } + + var newName = userModel.name + if let name = name, name != newName { + newName = name + wasChanged = true + } + + var newSummary = userModel.summary + if let summary = summary, summary != newSummary { + newSummary = summary + } + + if username != userModel.username { + wasChanged = true + } + + guard wasChanged else { + return + } + + let newUserModel = UserModel(uid: userModel.uid, email: userModel.email, username: username, summary: newSummary, image: newImage, name: newName) + + self?.userService.updateUserData(user: newUserModel, completion: { error, _ in + if error != nil { + + } + }) + } + } +} diff --git a/DoIt/ViewModels/ProfileViewModel.swift b/DoIt/ViewModels/ProfileViewModel.swift new file mode 100644 index 0000000..cd1ffa8 --- /dev/null +++ b/DoIt/ViewModels/ProfileViewModel.swift @@ -0,0 +1,75 @@ +// +// ProfileViewModel.swift +// DoIt +// +// Created by Шестаков Никита on 14.12.2021. +// + +import Foundation + +final class ProfileViewModel { + private let userService = UserService.shared + private let taskService = TaskService.shared + + var userModel: Observable = Observable() + + var userFollowingModel: Observable = Observable() + + var userTasksModel: Observable = Observable() + + func getUserTasks() { + DispatchQueue.global().async { [weak self] in + guard let user = self?.userModel.value else { + + return + } + self?.taskService.fetchTasks(forUser: user, completion: { [weak self] tasks in + self?.userTasksModel.value = UserTasksModel(login: user.username, tasks: tasks) + }) + } + } + + func getUserFollowings() { + DispatchQueue.global().async { [weak self] in + guard let user = self?.userModel.value else { + + return + } + self?.userService.fetchUserFollowing(uid: user.uid, completion: { uids in + var followings: [UserModel] = [] + uids.forEach { uid in + self?.userService.fetchUser(uid: uid, completion: { followings.append($0) }) + } + self?.userFollowingModel.value = UserFollowingModel(login: user.username, followings: followings) + }) + } + } + + func followUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { + DispatchQueue.global().async { [weak self] in + self?.userService.followUser(uid: user.uid) { error, _ in + guard error == nil else { + print(error!.localizedDescription) + completion(false) + return + } + self?.userModel.value?.isFollowed = true + completion(true) + } + } + } + + func unfollowUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { + DispatchQueue.global().async { [weak self] in + self?.userService.unfollowUser(uid: user.uid) { error, _ in + guard error == nil else { + print(error!.localizedDescription) + completion(false) + return + } + self?.userModel.value?.isFollowed = true + completion(true) + } + } + } +} diff --git a/DoIt/ViewModels/SearchUsersViewModel.swift b/DoIt/ViewModels/SearchUsersViewModel.swift index 42d5930..fcdac20 100644 --- a/DoIt/ViewModels/SearchUsersViewModel.swift +++ b/DoIt/ViewModels/SearchUsersViewModel.swift @@ -6,15 +6,94 @@ // import Foundation +import Firebase -class SearchUsersViewModel { - var userModel: UserModel? +final class Observable { + var value: T? { + didSet { + listener?(value) + } + } - var userModels: [UserModel] = [] + init(_ value: T? = nil) { + self.value = value + } - var filteredUsersModel: [UserModel]? { - didSet { -// tableView.reloadSections(IndexSet(integer: 0), with: .fade) + private var listener: ((T?) -> ())? + + func bind(_ listener: @escaping (T?) -> ()) { + listener(value) + self.listener = listener + } +} + +final class SearchUsersViewModel { + private let userService = UserService.shared + + var userModel: Observable = Observable() + + var userModels: Observable<[UserModel]> = Observable([]) + + var filteredUsersModel: Observable<[UserModel]> = Observable() + + func getCurrentUser() { + DispatchQueue.global(qos: .userInitiated).async { [weak self] in + guard let uid = Auth.auth().currentUser?.uid else { + return + } + self?.userService.fetchUser(uid: uid) { [weak self] user in + self?.userModel.value = user + } + } + } + + func getAllUsers() { + DispatchQueue.global(qos: .userInitiated).async { [weak self] in + self?.userService.fetchUsers(completion: { [weak self] users in + users.forEach { user in + self?.userService.isUserFollowed(uid: user.uid) { user.isFollowed = $0 } + } + self?.userModels.value = users + }) + } + } + + func followUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { + DispatchQueue.global().async { [weak self] in + self?.userService.followUser(uid: user.uid) { error, _ in + guard error == nil else { + print(error!.localizedDescription) + completion(false) + return + } + user.isFollowed = true + completion(true) + } + } + } + + func unfollowUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { + DispatchQueue.global().async { [weak self] in + self?.userService.unfollowUser(uid: user.uid) { error, _ in + guard error == nil else { + print(error!.localizedDescription) + completion(false) + return + } + user.isFollowed = true + completion(true) + } + } + } + + func filtering(username: String) { + DispatchQueue.global().async { [weak self] in + self?.filteredUsersModel.value = self?.userModels.value?.filter { $0.username.lowercased().contains(username.lowercased()) } } } + + func stopFiltering() { + filteredUsersModel.value = nil + } } + diff --git a/DoIt/Views/Feed/FeedController.swift b/DoIt/Views/Feed/FeedController.swift index 20e6532..33dd727 100644 --- a/DoIt/Views/Feed/FeedController.swift +++ b/DoIt/Views/Feed/FeedController.swift @@ -113,8 +113,7 @@ extension FeedController: UICollectionViewDataSource { guard let userInfo = following.first(where: { $0.username == followingUsersTasks[indexPath.row].uid }) else { return .init(frame: .zero) } cell.tapOnUser = { [weak self] in let profileViewController = ProfileViewController() - profileViewController.userModel = userInfo - profileViewController.userTasksModel = UserTasksModel(login: userInfo.username, tasks: self?.followingUsersTasks.filter({ $0.uid == userInfo.username }) ?? []) + profileViewController.viewModel.userModel.value = userInfo self?.navigationController?.pushViewController(profileViewController, animated: true) } cell.configureCell(taskInfo: followingUsersTasks[indexPath.row], userInfo: userInfo) @@ -137,7 +136,6 @@ extension FeedController { @objc private func openSearch() { let searchUsersController = SearchUsersController() - searchUsersController.userModel = userModel navigationController?.pushViewController(searchUsersController, animated: true) } diff --git a/DoIt/Views/Profile/ProfileEditViewController.swift b/DoIt/Views/Profile/ProfileEditViewController.swift index c2dfef1..1fb7aa1 100644 --- a/DoIt/Views/Profile/ProfileEditViewController.swift +++ b/DoIt/Views/Profile/ProfileEditViewController.swift @@ -124,7 +124,8 @@ final class ProfileEditViewController: UIViewController { }() private let keyboardManager = KeyboardManager.shared - var userModel: UserModel? + private var imageWasChanged: Bool = false + var viewModel: ProfileEditViewModel = ProfileEditViewModel() // MARK: - Lifecycle @@ -136,13 +137,17 @@ final class ProfileEditViewController: UIViewController { view.snapshotView(afterScreenUpdates: true) + viewModel.userModel.bind { [weak self] user in + self?.configure() + } + configureUI() } // MARK: - Helpers private func configure() { - guard let userModel = userModel else { return } + guard let userModel = viewModel.userModel.value else { return } summaryTextView.text = userModel.summary guard let image = userModel.image else { profileImageView.layoutIfNeeded() @@ -191,7 +196,11 @@ final class ProfileEditViewController: UIViewController { extension ProfileEditViewController { @objc private func doneEditing() { - + guard let userModel = viewModel.userModel.value else { return } + viewModel.updateUserProfile(image: imageWasChanged ? profileImageView.image : nil, + name: nameInputField.textField.text, + username: loginInputField.textField.text ?? userModel.username, + summary: summaryTextView.textView.text.isEmpty ? nil : summaryTextView.textView.text) } } @@ -208,6 +217,7 @@ extension ProfileEditViewController: UIImagePickerControllerDelegate, UINavigati func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { guard let image = info[.editedImage] as? UIImage else { return } profileImageView.image = image + imageWasChanged = true dismiss(animated: true, completion: nil) } } diff --git a/DoIt/Views/Profile/ProfileViewController.swift b/DoIt/Views/Profile/ProfileViewController.swift index 66caa3f..385d4e9 100644 --- a/DoIt/Views/Profile/ProfileViewController.swift +++ b/DoIt/Views/Profile/ProfileViewController.swift @@ -277,31 +277,38 @@ class ProfileViewController: UIViewController { // MARK: - Configuration - var userModel: UserModel? - - var userFollowingModel: UserFollowingModel? - - var userTasksModel: UserTasksModel? + var viewModel: ProfileViewModel = ProfileViewModel() // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() + viewModel.userModel.bind { [weak self] _ in + self?.configureCells() + self?.viewModel.getUserTasks() + self?.viewModel.getUserFollowings() + } + + viewModel.userTasksModel.bind { [weak self] _ in + self?.configureTasks() + self?.configureStatistics() + } + + viewModel.userFollowingModel.bind { [weak self] _ in + self?.configureFollowing() + } + configureUI() } // MARK: - Helpers private func configureCells() { - guard let userModel = userModel else { return } - configureHeader(image: userModel.image, name: userModel.name, login: userModel.username, isFollowed: false, isMyScreen: false) + guard let userModel = viewModel.userModel.value else { return } + configureHeader(image: userModel.image, name: userModel.name, login: userModel.username, isFollowed: userModel.isFollowed ?? false, isMyScreen: userModel.isCurrentUser) configureInformation(summary: userModel.summary) - configureStatistics(tasks: userTasksModel?.tasks ?? []) - - configureTasks(with: userTasksModel?.tasks ?? []) - - configureFollowing(isFollowingEmpty: (userFollowingModel?.followings ?? []).count == 0 ? true : false) + configureStatistics() } private func configureUI() { @@ -309,7 +316,7 @@ class ProfileViewController: UIViewController { layoutScrollView() layoutCellsStackView() - configureNavigationController(title: userModel?.username ?? "", isMyScreen: userModel?.isCurrentUser ?? false) + configureNavigationController(title: viewModel.userModel.value?.username ?? "", isMyScreen: viewModel.userModel.value?.isCurrentUser ?? false) configureCells() } @@ -559,6 +566,17 @@ extension ProfileViewController { innerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true return view } + + private func switchFollowButtonAnimated() { + UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) { + self.configureFollowButton(isFollowed: !self.followButton.isSelected) + self.followButton.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) + } completion: { _ in + UIView.animate(withDuration: 0.2) { + self.followButton.transform = CGAffineTransform.identity + } + } + } } // MARK: - Configuration @@ -607,7 +625,8 @@ extension ProfileViewController { // MARK: - Statistics View - private func configureStatistics(tasks: [Task]) { + private func configureStatistics() { + let tasks = viewModel.userTasksModel.value?.tasks ?? [] DispatchQueue.global().async { var done = 0 var outdated = 0 @@ -632,7 +651,8 @@ extension ProfileViewController { // MARK: - Tasks View - private func configureTasks(with: [Task]) { + private func configureTasks() { + let with = viewModel.userTasksModel.value?.tasks ?? [] let taskToConfigure = min(with.count, taskViews.count) for i in 0.. Int { - return userFollowingModel?.followings.count ?? 0 + return viewModel.userFollowingModel.value?.followings.count ?? 0 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: ProfileFollowingUserCell.self), for: indexPath) as? ProfileFollowingUserCell else { return .init(frame: .zero) } - guard let userFollowingModel = userFollowingModel else { return .init() } + guard let userFollowingModel = viewModel.userFollowingModel.value else { return .init() } cell.configureCell(with: userFollowingModel.followings[indexPath.row]) return cell } @@ -710,7 +731,7 @@ extension ProfileViewController: UICollectionViewDelegateFlowLayout { } extension ProfileViewController { @objc private func showAllTasks() { - guard let userModel = userModel else { return } + guard let userModel = viewModel.userModel.value else { return } guard !userModel.isCurrentUser else { NotificationCenter.default.post(name: .openTasksFromProfile, object: nil) navigationController?.popToRootViewController(animated: true) @@ -719,7 +740,7 @@ extension ProfileViewController { let viewController = FeedController() viewController.userModel = userModel viewController.following = [userModel] - viewController.followingUsersTasks = userTasksModel?.tasks ?? [] + viewController.followingUsersTasks = viewModel.userTasksModel.value?.tasks ?? [] navigationController?.pushViewController(viewController, animated: true) } @@ -729,19 +750,34 @@ extension ProfileViewController { guard let i = taskViews.firstIndex(where: { $0.taskView == view } ) else { return } let taskViewController = TaskViewController() - taskViewController.taskModel = userTasksModel?.tasks[i] + taskViewController.taskModel = viewModel.userTasksModel.value?.tasks[i] taskViewController.hidesBottomBarWhenPushed = true navigationController?.pushViewController(taskViewController, animated: true) } @objc private func didTapFollowButton() { - UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) { - self.configureFollowButton(isFollowed: !self.followButton.isSelected) - self.followButton.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) - } completion: { _ in - UIView.animate(withDuration: 0.2) { - self.followButton.transform = CGAffineTransform.identity + guard let userModel = viewModel.userModel.value else { return } + guard let isFollowed = userModel.isFollowed else { return } + if isFollowed { + viewModel.unfollowUser(userModel) { [weak self] done in + guard done else { + + return + } + DispatchQueue.main.async { + self?.switchFollowButtonAnimated() + } + } + } else { + viewModel.followUser(userModel) { [weak self] done in + guard done else { + + return + } + DispatchQueue.main.async { + self?.switchFollowButtonAnimated() + } } } } @@ -749,7 +785,7 @@ extension ProfileViewController { @objc private func openSettings() { let profileEditViewController = ProfileEditViewController() - profileEditViewController.userModel = userModel + profileEditViewController.viewModel.userModel.value = viewModel.userModel.value profileEditViewController.hidesBottomBarWhenPushed = true navigationController?.pushViewController(profileEditViewController, animated: true) } diff --git a/DoIt/Views/Search Users/SearchUsersCell.swift b/DoIt/Views/Search Users/SearchUsersCell.swift index 9daf14c..e43de46 100644 --- a/DoIt/Views/Search Users/SearchUsersCell.swift +++ b/DoIt/Views/Search Users/SearchUsersCell.swift @@ -7,6 +7,10 @@ import UIKit +protocol SearchUsersCellDelegate: AnyObject { + func didTapFollowButton(_ indexPath: Int?, completion: @escaping () -> ()) +} + final class SearchUsersCell: UITableViewCell { // MARK: - Private Properties @@ -75,6 +79,10 @@ final class SearchUsersCell: UITableViewCell { button.addTarget(self, action: #selector(didTapFollowButton), for: .touchUpInside) return button }() + + var indexPathRow: Int? + + weak var delegate: SearchUsersCellDelegate? // MARK: - Lifecycle @@ -93,7 +101,7 @@ final class SearchUsersCell: UITableViewCell { func configureCell(with model: UserModel) { loginLabel.text = model.username configureSummeryLabel(text: model.summary) -// configureFollowButton(isFollowed: model.isFollowed) + configureFollowButton(isFollowed: model.isFollowed ?? false) configureImageView(image: model.image, name: model.name, login: model.username) } @@ -149,10 +157,7 @@ final class SearchUsersCell: UITableViewCell { followButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true } - // MARK: - Actions - - @objc - private func didTapFollowButton() { + private func switchFollowButtonAnimated() { UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) { self.configureFollowButton(isFollowed: !self.followButton.isSelected) self.followButton.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) @@ -162,4 +167,11 @@ final class SearchUsersCell: UITableViewCell { } } } + + // MARK: - Actions + + @objc + private func didTapFollowButton() { + delegate?.didTapFollowButton(indexPathRow, completion: switchFollowButtonAnimated) + } } diff --git a/DoIt/Views/Search Users/SearchUsersController.swift b/DoIt/Views/Search Users/SearchUsersController.swift index 218f538..577f4cd 100644 --- a/DoIt/Views/Search Users/SearchUsersController.swift +++ b/DoIt/Views/Search Users/SearchUsersController.swift @@ -67,6 +67,23 @@ final class SearchUsersController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + + viewModel.userModel.bind { [weak self] _ in + self?.viewModel.getAllUsers() + } + + viewModel.userModels.bind { [weak self] _ in + DispatchQueue.main.async { + self?.tableView.reloadSections(IndexSet(integer: 0), with: .fade) + } + } + + viewModel.filteredUsersModel.bind { [weak self] _ in + DispatchQueue.main.async { + self?.tableView.reloadSections(IndexSet(integer: 0), with: .fade) + } + } + configureUI() } @@ -125,21 +142,31 @@ extension SearchUsersController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let profileViewController = ProfileViewController() - profileViewController.userModel = viewModel.filteredUsersModel?[indexPath.row] ?? viewModel.userModels[indexPath.row] + profileViewController.viewModel.userModel.value = viewModel.filteredUsersModel.value?[indexPath.row] ?? viewModel.userModels.value?[indexPath.row] navigationController?.pushViewController(profileViewController, animated: true) } } extension SearchUsersController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModel.filteredUsersModel?.count ?? viewModel.userModels.count + if let filteredUsersModel = viewModel.filteredUsersModel.value { + return filteredUsersModel.count + } + return viewModel.userModels.value?.count ?? 0 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchUsersCell.self), for: indexPath) as? SearchUsersCell else { return .init() } - cell.configureCell(with: viewModel.filteredUsersModel?[indexPath.row] ?? viewModel.userModels[indexPath.row]) + cell.indexPathRow = indexPath.row + guard viewModel.filteredUsersModel.value == nil else { + cell.configureCell(with: viewModel.filteredUsersModel.value![indexPath.row]) + return cell + } + if let userModels = viewModel.userModels.value { + cell.configureCell(with: userModels[indexPath.row]) + } return cell } } @@ -148,8 +175,8 @@ extension SearchUsersController: UITableViewDataSource { extension SearchUsersController: UISearchBarDelegate { func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { - guard !searchText.isEmpty else { viewModel.filteredUsersModel = nil; return } - viewModel.filteredUsersModel = viewModel.userModels.filter { $0.username.lowercased().contains(searchText.lowercased()) } + guard !searchText.isEmpty else { viewModel.stopFiltering(); return } + viewModel.filtering(username: searchText) } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { @@ -161,6 +188,42 @@ extension SearchUsersController: UISearchBarDelegate { } } +extension SearchUsersController: SearchUsersCellDelegate { + func didTapFollowButton(_ indexPath: Int?, completion: @escaping () -> ()) { + guard let indexPath = indexPath else { return } + var userModel: UserModel? + if let user = viewModel.filteredUsersModel.value?[indexPath] { userModel = user } + if let user = viewModel.userModels.value?[indexPath] { userModel = user } + guard let userModel = userModel else { return } + guard let isFollowed = userModel.isFollowed else { return } + isFollowed ? unfollowUser(userModel, completion: completion) : followUser(userModel, completion: completion) + } + + private func followUser(_ user: UserModel, completion: @escaping () -> ()) { + viewModel.followUser(user) { done in + guard done else { + + return + } + DispatchQueue.main.async { + completion() + } + } + } + + private func unfollowUser(_ user: UserModel, completion: @escaping () -> ()) { + viewModel.unfollowUser(user) { done in + guard done else { + + return + } + DispatchQueue.main.async { + completion() + } + } + } +} + extension SearchUsersController { @objc private func addSearchBarView() { diff --git a/DoIt/Views/Tasks/TasksController.swift b/DoIt/Views/Tasks/TasksController.swift index 3206fff..6f3ce19 100644 --- a/DoIt/Views/Tasks/TasksController.swift +++ b/DoIt/Views/Tasks/TasksController.swift @@ -157,12 +157,12 @@ extension TasksController { @objc private func openProfile() { let profileViewController = ProfileViewController() - profileViewController.userModel = userModel + profileViewController.viewModel.userModel.value = userModel guard let userModel = userModel else { navigationController?.pushViewController(profileViewController, animated: true) return } - profileViewController.userTasksModel = UserTasksModel(login: userModel.username, tasks: tasks) + profileViewController.viewModel.userTasksModel.value = UserTasksModel(login: userModel.username, tasks: tasks) navigationController?.pushViewController(profileViewController, animated: true) } } From 0ef2a4b2ed87eef29f33e879382e7dfd343d9286 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 14 Dec 2021 18:03:56 +0300 Subject: [PATCH 08/28] fix profile image --- DoIt/ViewModels/ProfileEditViewModel.swift | 3 ++- .../Feed/FeedCollectionView/FeedCollectionViewCell.swift | 1 + DoIt/Views/Feed/FeedController.swift | 5 ++--- DoIt/Views/Profile/ProfileEditViewController.swift | 3 ++- DoIt/Views/Profile/ProfileViewController.swift | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/DoIt/ViewModels/ProfileEditViewModel.swift b/DoIt/ViewModels/ProfileEditViewModel.swift index 95ed8b2..235e6fd 100644 --- a/DoIt/ViewModels/ProfileEditViewModel.swift +++ b/DoIt/ViewModels/ProfileEditViewModel.swift @@ -12,7 +12,7 @@ final class ProfileEditViewModel { private let userService = UserService.shared var userModel: Observable = Observable() - func updateUserProfile(image: UIImage?, name: String?, username: String, summary: String?) { + func updateUserProfile(image: UIImage?, name: String?, username: String, summary: String?, complition: @escaping () -> ()) { DispatchQueue.global().sync { [weak self] in guard let userModel = userModel.value else { return @@ -50,6 +50,7 @@ final class ProfileEditViewModel { if error != nil { } + complition() }) } } diff --git a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift index 9c17624..039b5cd 100644 --- a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift +++ b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift @@ -93,6 +93,7 @@ class FeedCollectionViewCell: UICollectionViewCell { layer.cornerRadius = UIConstants.cornerRadius backgroundColor = .systemBackground contentView.isUserInteractionEnabled = false + backgroundColor = .AppColors.feedBackgroundColor configureTaskImage() configureTaskLabel() diff --git a/DoIt/Views/Feed/FeedController.swift b/DoIt/Views/Feed/FeedController.swift index 33dd727..45c3b83 100644 --- a/DoIt/Views/Feed/FeedController.swift +++ b/DoIt/Views/Feed/FeedController.swift @@ -36,7 +36,7 @@ class FeedController: UIViewController { collectionView.delegate = self collectionView.dataSource = self collectionView.register(FeedCollectionViewCell.self, forCellWithReuseIdentifier: FeedCollectionViewCell.self.description()) - collectionView.backgroundColor = UIColor.AppColors.feedBackgroundColor + collectionView.backgroundColor = .systemBackground collectionView.translatesAutoresizingMaskIntoConstraints = false return collectionView }() @@ -89,8 +89,7 @@ class FeedController: UIViewController { private func configureNavigationController() { navigationItem.title = (userModel?.isCurrentUser ?? false) ? FeedStrings.header.rawValue.localized : FeedStrings.allTasksHeader.rawValue.localized - navigationItem.rightBarButtonItem = searchButton -// navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil + navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil } diff --git a/DoIt/Views/Profile/ProfileEditViewController.swift b/DoIt/Views/Profile/ProfileEditViewController.swift index 1fb7aa1..2484ff6 100644 --- a/DoIt/Views/Profile/ProfileEditViewController.swift +++ b/DoIt/Views/Profile/ProfileEditViewController.swift @@ -200,7 +200,8 @@ extension ProfileEditViewController { viewModel.updateUserProfile(image: imageWasChanged ? profileImageView.image : nil, name: nameInputField.textField.text, username: loginInputField.textField.text ?? userModel.username, - summary: summaryTextView.textView.text.isEmpty ? nil : summaryTextView.textView.text) + summary: summaryTextView.textView.text.isEmpty ? nil : summaryTextView.textView.text, + complition: { [weak self] in self?.navigationController?.popViewController(animated: true) }) } } diff --git a/DoIt/Views/Profile/ProfileViewController.swift b/DoIt/Views/Profile/ProfileViewController.swift index 385d4e9..88bfb33 100644 --- a/DoIt/Views/Profile/ProfileViewController.swift +++ b/DoIt/Views/Profile/ProfileViewController.swift @@ -284,6 +284,8 @@ class ProfileViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + configureUI() + viewModel.userModel.bind { [weak self] _ in self?.configureCells() self?.viewModel.getUserTasks() @@ -298,8 +300,6 @@ class ProfileViewController: UIViewController { viewModel.userFollowingModel.bind { [weak self] _ in self?.configureFollowing() } - - configureUI() } // MARK: - Helpers From 62f7191382a904629929bba3c8625893e538e9ad Mon Sep 17 00:00:00 2001 From: danil-ivanov Date: Tue, 14 Dec 2021 18:04:57 +0300 Subject: [PATCH 09/28] nothing --- DoIt.xcodeproj/project.pbxproj | 40 ++++++++++++++++++---- DoIt/ViewModels/Dynamic.swift | 30 ++++++++++++++++ DoIt/ViewModels/SignUpViewModel.swift | 16 +++++++++ DoIt/ViewModels/TasksScreenViewModel.swift | 18 ++++++++++ DoIt/ViewModels/TasksViewModel.swift | 12 +++++++ DoIt/Views/Tasks/TasksController.swift | 6 ++++ 6 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 DoIt/ViewModels/Dynamic.swift create mode 100644 DoIt/ViewModels/SignUpViewModel.swift create mode 100644 DoIt/ViewModels/TasksScreenViewModel.swift create mode 100644 DoIt/ViewModels/TasksViewModel.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 92908b3..d107d2f 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -7,9 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 5038435A2AA2F8CD2F8BEF43 /* Pods_DoIt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08B69A42E301E7239EBE517D /* Pods_DoIt.framework */; }; - 7C022801275D9C4800DFF8EC /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022800275D9C4800DFF8EC /* AuthService.swift */; }; - 7C022803275DAE6700DFF8EC /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C022802275DAE6700DFF8EC /* ImageService.swift */; }; 7C6382DD272777F600FED2F4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7C6382DF272777F600FED2F4 /* Localizable.strings */; }; 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E22727884000FED2F4 /* UIImageExtension.swift */; }; 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6382E52728807900FED2F4 /* UIColorsExtension.swift */; }; @@ -19,10 +16,14 @@ 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */; }; 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */; }; 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */; }; - 7C6C3BCE275CFE4700B6101F /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCD275CFE4700B6101F /* UserModel.swift */; }; - 7C6C3BD0275CFEA900B6101F /* TaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCF275CFEA900B6101F /* TaskService.swift */; }; 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */; }; 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */; }; + 83349BD627681AF0008D4786 /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BD527681AF0008D4786 /* SignUpViewModel.swift */; }; + 83349BDB27681CC2008D4786 /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BD927681CC2008D4786 /* ImageService.swift */; }; + 83349BDC27681CC2008D4786 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDA27681CC2008D4786 /* AuthService.swift */; }; + 83349BE027682D58008D4786 /* Dynamic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDF27682D58008D4786 /* Dynamic.swift */; }; + 83349BE227682D72008D4786 /* TasksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE127682D72008D4786 /* TasksViewModel.swift */; }; + 83349BE427683051008D4786 /* TasksScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE327683051008D4786 /* TasksScreenViewModel.swift */; }; 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; 83369A44273856240025F3D9 /* TaskTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A43273856240025F3D9 /* TaskTableViewCell.swift */; }; 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A49273856950025F3D9 /* ChapterCollectionCell.swift */; }; @@ -77,6 +78,12 @@ 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7CAC5DDB27232C6300E2D70B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 83349BD527681AF0008D4786 /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = ""; }; + 83349BD927681CC2008D4786 /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; + 83349BDA27681CC2008D4786 /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; + 83349BDF27682D58008D4786 /* Dynamic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dynamic.swift; sourceTree = ""; }; + 83349BE127682D72008D4786 /* TasksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksViewModel.swift; sourceTree = ""; }; + 83349BE327683051008D4786 /* TasksScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksScreenViewModel.swift; sourceTree = ""; }; 83369A3F273855BD0025F3D9 /* TasksController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksController.swift; sourceTree = ""; }; 83369A43273856240025F3D9 /* TaskTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskTableViewCell.swift; sourceTree = ""; }; 83369A49273856950025F3D9 /* ChapterCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChapterCollectionCell.swift; sourceTree = ""; }; @@ -152,6 +159,10 @@ 7C6382CF2725C4F700FED2F4 /* ViewModels */ = { isa = PBXGroup; children = ( + 83349BDF27682D58008D4786 /* Dynamic.swift */, + 83349BD527681AF0008D4786 /* SignUpViewModel.swift */, + 83349BE127682D72008D4786 /* TasksViewModel.swift */, + 83349BE327683051008D4786 /* TasksScreenViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -185,6 +196,8 @@ 7C6382D52725C5E800FED2F4 /* Models */ = { isa = PBXGroup; children = ( + 83349BDA27681CC2008D4786 /* AuthService.swift */, + 83349BD927681CC2008D4786 /* ImageService.swift */, E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */, E4A95D48275BE99900EE3F59 /* UserModel.swift */, E4A95D49275BE99A00EE3F59 /* UserStatisticsModel.swift */, @@ -195,8 +208,6 @@ 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, 7C6C3BCF275CFEA900B6101F /* TaskService.swift */, - 7C022800275D9C4800DFF8EC /* AuthService.swift */, - 7C022802275DAE6700DFF8EC /* ImageService.swift */, ); path = Models; sourceTree = ""; @@ -220,6 +231,7 @@ 7CAC5DCB27232C6000E2D70B /* Products */, 44250C609B2DD82274CFF714 /* Pods */, 7D03E0CC68346392C8995C87 /* Frameworks */, + 83349BD42768118E008D4786 /* Recovered References */, ); sourceTree = ""; }; @@ -256,6 +268,14 @@ name = Frameworks; sourceTree = ""; }; + 83349BD42768118E008D4786 /* Recovered References */ = { + isa = PBXGroup; + children = ( + 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */, + ); + name = "Recovered References"; + sourceTree = ""; + }; 83369A452738564B0025F3D9 /* TasksTableView */ = { isa = PBXGroup; children = ( @@ -500,12 +520,14 @@ files = ( 83369A44273856240025F3D9 /* TaskTableViewCell.swift in Sources */, E4A95D4D275BE99A00EE3F59 /* UserFollowingModel.swift in Sources */, + 83349BD627681AF0008D4786 /* SignUpViewModel.swift in Sources */, 8383503F27583E58008847E1 /* TaskCategory.swift in Sources */, 8383503B27583E58008847E1 /* OnboardingCell.swift in Sources */, 83AF41A827431F9600CA8AAA /* FeedCollectionViewCell.swift in Sources */, 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */, 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */, 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */, + 83349BDC27681CC2008D4786 /* AuthService.swift in Sources */, 8383504027583E58008847E1 /* SearchUsersCell.swift in Sources */, E49D6B20275BEF0C007C9A97 /* UserTasksModel.swift in Sources */, E4A95D59275BEA8500EE3F59 /* ProfileEditViewController.swift in Sources */, @@ -517,6 +539,7 @@ 8383504127583E58008847E1 /* SearchUsersController.swift in Sources */, E4A95D4C275BE99A00EE3F59 /* UserStatisticsModel.swift in Sources */, E4A95D4B275BE99A00EE3F59 /* UserModel.swift in Sources */, + 83349BE227682D72008D4786 /* TasksViewModel.swift in Sources */, 7C6382E32727884000FED2F4 /* UIImageExtension.swift in Sources */, E40B7953275FA1DA002DE826 /* KeyboardManager.swift in Sources */, E4A95D5B275BEA8600EE3F59 /* ProfileFollowingUserCell.swift in Sources */, @@ -524,6 +547,7 @@ 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */, 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */, 8383503727583E58008847E1 /* SignInController.swift in Sources */, + 83349BE027682D58008D4786 /* Dynamic.swift in Sources */, 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */, E4A95D5D275BEAAA00EE3F59 /* Profile.swift in Sources */, E4A95D5A275BEA8600EE3F59 /* ProfileViewController.swift in Sources */, @@ -531,12 +555,14 @@ 8383504A27583F93008847E1 /* Strings.swift in Sources */, 83369A4E273857020025F3D9 /* Structures.swift in Sources */, 8383503A27583E58008847E1 /* OnboardingStruct.swift in Sources */, + 83349BE427683051008D4786 /* TasksScreenViewModel.swift in Sources */, E4BC75FE276537E40016B6E2 /* NotificationNameExtension.swift in Sources */, 83AF41A027429B5500CA8AAA /* CustomTabBarController.swift in Sources */, 8383503627583E58008847E1 /* CustomNavigationController.swift in Sources */, 8383503527583E58008847E1 /* Auth.swift in Sources */, 7C6C3BC4275C05E000B6101F /* UserService.swift in Sources */, 8383503C27583E58008847E1 /* TaskEditViewController.swift in Sources */, + 83349BDB27681CC2008D4786 /* ImageService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DoIt/ViewModels/Dynamic.swift b/DoIt/ViewModels/Dynamic.swift new file mode 100644 index 0000000..078dd8e --- /dev/null +++ b/DoIt/ViewModels/Dynamic.swift @@ -0,0 +1,30 @@ +// +// Dynamic.swift +// DoIt +// +// Created by Данил Иванов on 14.12.2021. +// + +class Dynamic { + typealias Listener = (T) -> () + var listener: Listener? + + func bind(_ listener: Listener?) { + self.listener = listener + } + + func bindAndFire(_ listener: Listener?) { + self.listener = listener + listener?(value) + } + + var value: T { + didSet { + listener?(value) + } + } + + init(_ v: T) { + value = v + } +} diff --git a/DoIt/ViewModels/SignUpViewModel.swift b/DoIt/ViewModels/SignUpViewModel.swift new file mode 100644 index 0000000..31e842f --- /dev/null +++ b/DoIt/ViewModels/SignUpViewModel.swift @@ -0,0 +1,16 @@ +// +// SignUpViewModel.swift +// DoIt +// +// Created by Данил Иванов on 14.12.2021. +// + +import Foundation + +class SignUpViewModel: NSObject { + private var authService = AuthService() + var isSuccesed = false + + func singUp(withEmail: String, withUsername: String, withPassword: String) { + } +} diff --git a/DoIt/ViewModels/TasksScreenViewModel.swift b/DoIt/ViewModels/TasksScreenViewModel.swift new file mode 100644 index 0000000..830ad48 --- /dev/null +++ b/DoIt/ViewModels/TasksScreenViewModel.swift @@ -0,0 +1,18 @@ +// +// TasksScreenViewModel.swift +// DoIt +// +// Created by Данил Иванов on 14.12.2021. +// + +import Foundation + +class TasksScreenViewModel: NSObject, TasksViewModel { + var preparedTasks: Dynamic<[Task]> + var allTasks: [Task] + let taskService = TaskS + + override init() { + allTasks = taskService. + } +} diff --git a/DoIt/ViewModels/TasksViewModel.swift b/DoIt/ViewModels/TasksViewModel.swift new file mode 100644 index 0000000..112a715 --- /dev/null +++ b/DoIt/ViewModels/TasksViewModel.swift @@ -0,0 +1,12 @@ +// +// TasksViewModel.swift +// DoIt +// +// Created by Данил Иванов on 14.12.2021. +// + +import Foundation + +protocol TasksViewModel { + var preparedTasks: Dynamic<[Task]> { get } +} diff --git a/DoIt/Views/Tasks/TasksController.swift b/DoIt/Views/Tasks/TasksController.swift index 3206fff..fcb642f 100644 --- a/DoIt/Views/Tasks/TasksController.swift +++ b/DoIt/Views/Tasks/TasksController.swift @@ -53,6 +53,12 @@ class TasksController: UIViewController { return tableView }() + private var viewModel: TasksViewModel? { + didSet { + + } + } + var tasks: [Task] = [ // Task(image: UIImage(named: "bob"), title: "Task 1: Get ready for an exam", description: nil, deadline: nil, isDone: true, creatorId: "1", color: .black, chapterId: 0, creationTime: Date(), isMyTask: true), // Task(image: UIImage(named: "bob"), title: "Task 2: Get ready for an exam", description: nil, deadline: nil, isDone: false, creatorId: "2", color: .yellow, chapterId: 1, creationTime: Date(), isMyTask: true), From ccf27fa5b0e0efa031716e5c276b5dcca602eb33 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 00:22:05 +0300 Subject: [PATCH 10/28] Add updating profile picture --- DoIt/Models/FirebaseConstants.swift | 2 +- DoIt/Models/UserService.swift | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/DoIt/Models/FirebaseConstants.swift b/DoIt/Models/FirebaseConstants.swift index b986d1b..3f55a1e 100644 --- a/DoIt/Models/FirebaseConstants.swift +++ b/DoIt/Models/FirebaseConstants.swift @@ -9,7 +9,7 @@ import Firebase let STORAGE_REF = Storage.storage().reference() -let STORAGE_IMAGES = STORAGE_REF.child("images") +let STORAGE_PROFILE_IMAGES = STORAGE_REF.child("profile_images") let DB_REF = Database.database().reference() diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index ea728fa..077eca2 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -21,9 +21,23 @@ class UserService { completion(user) } } - - // TODO: - Update profile picture - + + func updateUserPhoto(image: UIImage, completion: @escaping(URL?)-> Void){ + guard let imageData = image.jpegData(compressionQuality: 1.0) else {return} + guard let uid = Auth.auth().currentUser?.uid else {return} + let ref = STORAGE_PROFILE_IMAGES.child(NSUUID().uuidString) + + ref.putData(imageData, metadata: nil) { (meta, err) in + ref.downloadURL { (url, err) in + guard let userPhotoUrl = url?.absoluteString else {return} + let values = ["userPhotoUrl": userPhotoUrl] + REF_USERS.child(uid).updateChildValues(values) { (err, ref) in + completion(url) + } + } + } + } + func updateUserData(user: UserModel, completion: @escaping(DatabaseCompletion)){ guard let uid = Auth.auth().currentUser?.uid else {return} let values = ["username": user.username, "summary": user.summary ?? ""] From f30241b2659d8938aa3ab5c6b2f601af79543d48 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 00:33:22 +0300 Subject: [PATCH 11/28] Add updating task image --- DoIt/Models/FirebaseConstants.swift | 1 + DoIt/Models/TaskService.swift | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/DoIt/Models/FirebaseConstants.swift b/DoIt/Models/FirebaseConstants.swift index 3f55a1e..0dae4f1 100644 --- a/DoIt/Models/FirebaseConstants.swift +++ b/DoIt/Models/FirebaseConstants.swift @@ -10,6 +10,7 @@ import Firebase let STORAGE_REF = Storage.storage().reference() let STORAGE_PROFILE_IMAGES = STORAGE_REF.child("profile_images") +let STORAGE_TASK_IMAGES = STORAGE_REF.child("task_images") let DB_REF = Database.database().reference() diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift index dd357f3..3b3ca64 100644 --- a/DoIt/Models/TaskService.swift +++ b/DoIt/Models/TaskService.swift @@ -33,6 +33,22 @@ class TaskService { } } + func updateTaskImage(taskId: String, image: UIImage, completion: @escaping(URL?)-> Void){ + guard let imageData = image.jpegData(compressionQuality: 1.0) else {return} + guard let uid = Auth.auth().currentUser?.uid else {return} + let ref = STORAGE_TASK_IMAGES.child(NSUUID().uuidString) + + ref.putData(imageData, metadata: nil) { (meta, err) in + ref.downloadURL { (url, err) in + guard let taskImageUrl = url?.absoluteString else {return} + let values = ["taskImageUrl": taskImageUrl] + REF_TASKS.child(taskId).updateChildValues(values) { (err, ref) in + completion(url) + } + } + } + } + func fetchTask(taskId: String, completion: @escaping(Task) -> Void){ REF_TASKS.child(taskId).observeSingleEvent(of: .value) { snapshot in guard let dictionary = snapshot.value as? [String: Any] else {return} From 4cc64c16225606a31e27802da44764c43c2803c7 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 01:14:04 +0300 Subject: [PATCH 12/28] Network is done, but nothing works --- DoIt/Models/Structures.swift | 48 +++++++++++++++++++------ DoIt/Models/UserModel.swift | 25 +++++++------ Podfile.lock | 68 ++++++++++++++++++------------------ 3 files changed, 87 insertions(+), 54 deletions(-) diff --git a/DoIt/Models/Structures.swift b/DoIt/Models/Structures.swift index f464954..26ed563 100644 --- a/DoIt/Models/Structures.swift +++ b/DoIt/Models/Structures.swift @@ -9,7 +9,7 @@ import UIKit import Firebase class Task { - let image: UIImage? + let image: URL? let title: String let description: String? let deadline: Date? @@ -23,17 +23,45 @@ class Task { return Auth.auth().currentUser?.uid == uid } - init(image: UIImage?, title: String, description: String?, deadline: Date?, isDone: Bool, color: UIColor, uid: String = "") { - self.image = image - self.title = title - self.description = description - self.deadline = deadline - self.isDone = isDone + init(uid: User, id: String, dictionary: [String: AnyObject]) { + if let profileImageUrlString = dictionary["userPhotoUrl"] as? String { + guard let url = URL(string: profileImageUrlString) else {return} + self.image = url + } + self.title = dictionary["title"] as? String ?? "" + self.description = dictionary["description"] as? String ?? "" + if let deadlineTimestamp = dictionary["deadline"] as? Double { + self.deadline = Date(timeIntervalSince1970: deadlineTimestamp) + } + self.isDone = dictionary["is_done"] as? Bool ?? false + + // TODO: - FIX IT self.uid = "" - self.color = color - self.creationTime = Date() - self.chapterId = 0 + + // TODO: - FIX IT + self.color = .systemBlue + + if let creationTimestamp = dictionary["timestamp"] as? Double { + self.creationTime = Date(timeIntervalSince1970: creationTimestamp) + } + + // NOT DONE + self.chapterId = dictionary["chapter_id"] as? Int ?? 0 } + + // TODO: - FIX IT + +// init(image: UIImage?, title: String, description: String?, deadline: Date?, isDone: Bool, color: UIColor, uid: String = "") { +// self.image = image +// self.title = title +// self.description = description +// self.deadline = deadline +// self.isDone = isDone +// self.uid = "" +// self.color = color +// self.creationTime = Date() +// self.chapterId = 0 +// } } struct Chapter { diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index 7ec9bc3..24cdb5d 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -14,7 +14,7 @@ class UserModel { let email: String var username: String var summary: String? - let image: UIImage? + var image: URL? let name: String? var isCurrentUser: Bool { @@ -28,16 +28,21 @@ class UserModel { self.email = dictionary["email"] as? String ?? "" self.username = dictionary["username"] as? String ?? "" self.summary = dictionary["summary"] as? String - self.image = nil self.name = nil + if let profileImageUrlString = dictionary["userPhotoUrl"] as? String { + guard let url = URL(string: profileImageUrlString) else {return} + self.image = url + } } - init(uid: String, email: String, username: String, summary: String?, image: UIImage?, name: String?) { - self.uid = uid - self.email = email - self.username = username - self.summary = summary - self.image = image - self.name = name - } + // TODO: - FIX IT + +// init(uid: String, email: String, username: String, summary: String?, image: UIImage?, name: String?) { +// self.uid = uid +// self.email = email +// self.username = username +// self.summary = summary +// self.image = image +// self.name = name +// } } diff --git a/Podfile.lock b/Podfile.lock index 6ef48ed..00a4ae9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,21 +1,21 @@ PODS: - EasyNotificationBadge (1.2.5) - - Firebase/Auth (8.10.0): + - Firebase/Auth (8.9.0): - Firebase/CoreOnly - - FirebaseAuth (~> 8.10.0) - - Firebase/Core (8.10.0): + - FirebaseAuth (~> 8.9.0) + - Firebase/Core (8.9.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 8.10.0) - - Firebase/CoreOnly (8.10.0): - - FirebaseCore (= 8.10.0) - - Firebase/Database (8.10.0): + - FirebaseAnalytics (~> 8.9.0) + - Firebase/CoreOnly (8.9.0): + - FirebaseCore (= 8.9.0) + - Firebase/Database (8.9.0): - Firebase/CoreOnly - - FirebaseDatabase (~> 8.10.0) - - Firebase/Storage (8.10.0): + - FirebaseDatabase (~> 8.9.0) + - Firebase/Storage (8.9.0): - Firebase/CoreOnly - - FirebaseStorage (~> 8.10.0) - - FirebaseAnalytics (8.10.0): - - FirebaseAnalytics/AdIdSupport (= 8.10.0) + - FirebaseStorage (~> 8.9.0) + - FirebaseAnalytics (8.9.0): + - FirebaseAnalytics/AdIdSupport (= 8.9.0) - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) @@ -23,55 +23,55 @@ PODS: - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAnalytics/AdIdSupport (8.10.0): + - FirebaseAnalytics/AdIdSupport (8.9.0): - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - - GoogleAppMeasurement (= 8.10.0) + - GoogleAppMeasurement (= 8.9.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAuth (8.10.0): + - FirebaseAuth (8.9.0): - FirebaseCore (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/Environment (~> 7.6) - GTMSessionFetcher/Core (~> 1.5) - - FirebaseCore (8.10.0): + - FirebaseCore (8.9.0): - FirebaseCoreDiagnostics (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - - FirebaseCoreDiagnostics (8.10.0): + - FirebaseCoreDiagnostics (8.9.0): - GoogleDataTransport (~> 9.1) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - nanopb (~> 2.30908.0) - - FirebaseDatabase (8.10.0): + - FirebaseDatabase (8.9.0): - FirebaseCore (~> 8.0) - leveldb-library (~> 1.22) - - FirebaseInstallations (8.10.0): + - FirebaseInstallations (8.9.0): - FirebaseCore (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/UserDefaults (~> 7.6) - PromisesObjC (< 3.0, >= 1.2) - - FirebaseStorage (8.10.0): + - FirebaseStorage (8.9.0): - FirebaseCore (~> 8.0) - GTMSessionFetcher/Core (~> 1.5) - - GoogleAppMeasurement (8.10.0): - - GoogleAppMeasurement/AdIdSupport (= 8.10.0) + - GoogleAppMeasurement (8.9.0): + - GoogleAppMeasurement/AdIdSupport (= 8.9.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.10.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) + - GoogleAppMeasurement/AdIdSupport (8.9.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): + - GoogleAppMeasurement/WithoutAdIdSupport (8.9.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) @@ -143,15 +143,15 @@ SPEC REPOS: SPEC CHECKSUMS: EasyNotificationBadge: a3ebbcb1de0c0558e102e954380c75801f352702 - Firebase: 44213362f1dcc52555b935dc925ed35ac55f1b20 - FirebaseAnalytics: 319c9b3b1bdd400d60e2f415dff0c5f6959e6760 - FirebaseAuth: 59a2d2b933b5b79e18fb1e6ad230c6abdaa73d26 - FirebaseCore: 04186597c095da37d90ff9fd3e53bc61a1ff2440 - FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18 - FirebaseDatabase: 5f3e83b0a0d8759378fbd5d05661244d14dfbbb0 - FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425 - FirebaseStorage: 815410224b548172c578f02554a86bbc8f817f50 - GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 + Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95 + FirebaseAnalytics: 3a11ed901750e1ebcbe35e75915ff079878ea385 + FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b + FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b + FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 + FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc + FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85 + FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 + GoogleAppMeasurement: b54a857d347703d67c7a6f23713760c9bcfe9008 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 From 8f43c36386066299cbcebfd3ee1312d13a35cf40 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 01:15:37 +0300 Subject: [PATCH 13/28] Remove unnecessary file --- DoIt.xcodeproj/project.pbxproj | 4 ---- DoIt/Models/ImageService.swift | 25 ------------------------- 2 files changed, 29 deletions(-) diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index e736642..051868a 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -46,7 +46,6 @@ E417CFD927689D8A00C6E6B5 /* TaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E417CFD827689D8A00C6E6B5 /* TaskService.swift */; }; E417CFDB2768BE1800C6E6B5 /* ProfileEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E417CFDA2768BE1800C6E6B5 /* ProfileEditViewModel.swift */; }; E455B5D727681AD20059130D /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D527681AD10059130D /* AuthService.swift */; }; - E455B5D827681AD20059130D /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D627681AD10059130D /* ImageService.swift */; }; E455B5DA276820E60059130D /* SearchUsersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E455B5D9276820E60059130D /* SearchUsersViewModel.swift */; }; E49D6B20275BEF0C007C9A97 /* UserTasksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */; }; E4A95D4B275BE99A00EE3F59 /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D48275BE99900EE3F59 /* UserModel.swift */; }; @@ -104,7 +103,6 @@ E417CFD827689D8A00C6E6B5 /* TaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskService.swift; sourceTree = ""; }; E417CFDA2768BE1800C6E6B5 /* ProfileEditViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEditViewModel.swift; sourceTree = ""; }; E455B5D527681AD10059130D /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; - E455B5D627681AD10059130D /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; E455B5D9276820E60059130D /* SearchUsersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchUsersViewModel.swift; sourceTree = ""; }; E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTasksModel.swift; sourceTree = ""; }; E4A95D48275BE99900EE3F59 /* UserModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; @@ -193,7 +191,6 @@ isa = PBXGroup; children = ( E455B5D527681AD10059130D /* AuthService.swift */, - E455B5D627681AD10059130D /* ImageService.swift */, E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */, E4A95D48275BE99900EE3F59 /* UserModel.swift */, E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */, @@ -530,7 +527,6 @@ 83AF41A227431EB500CA8AAA /* FeedController.swift in Sources */, 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, E417CFDB2768BE1800C6E6B5 /* ProfileEditViewModel.swift in Sources */, - E455B5D827681AD20059130D /* ImageService.swift in Sources */, 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */, 8383504227583E58008847E1 /* SignUpController.swift in Sources */, diff --git a/DoIt/Models/ImageService.swift b/DoIt/Models/ImageService.swift index 904fb13..8b13789 100644 --- a/DoIt/Models/ImageService.swift +++ b/DoIt/Models/ImageService.swift @@ -1,26 +1 @@ -// -// ImageService.swift -// DoIt -// -// Created by Yulia on 06.12.2021. -// -import Firebase -import UIKit - -class ImageService { - - static let shared = ImageService() - - func uploadImage(image: UIImage!) { - let filename = NSUUID().uuidString - let storageRef = STORAGE_IMAGES.child(filename) - if let imageData = image.pngData() { - storageRef.putData(imageData, metadata: nil) { (meta, error) in - storageRef.downloadURL { (url, error) in - guard let profileImageUrl = url?.absoluteString else {return} - } - } - } - } -} From 1e714f85295095f9b3c95845600158b7941cafd9 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 02:10:11 +0300 Subject: [PATCH 14/28] Add extension that sets UIImage from URL --- DoIt/Extensions/UIImageExtension.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/DoIt/Extensions/UIImageExtension.swift b/DoIt/Extensions/UIImageExtension.swift index a74fb88..894b38c 100644 --- a/DoIt/Extensions/UIImageExtension.swift +++ b/DoIt/Extensions/UIImageExtension.swift @@ -48,3 +48,18 @@ extension UIImage { static var feedIcon: UIImage { UIImage(systemName: "square.grid.2x2")! } } } + +extension UIImage { + func setImage(urlAddress: String?, completion: @escaping (UIImage?) -> Void) { + guard let urlAddress = urlAddress, let url = URL(string: urlAddress) else { + return completion(nil) + } + let task = URLSession.shared.dataTask(with: url) { data, response, error in + guard let data = data, error == nil else { return } + DispatchQueue.main.async { + completion(UIImage(data: data)) + } + } + task.resume() + } +} From bf6e70bc5d55a1ab7812ed8909e920e279f75d02 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 02:41:00 +0300 Subject: [PATCH 15/28] fixes --- DoIt/Extensions/UIImageExtension.swift | 16 +--------------- DoIt/Views/Search Users/SearchUsersCell.swift | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/DoIt/Extensions/UIImageExtension.swift b/DoIt/Extensions/UIImageExtension.swift index 894b38c..ebf9619 100644 --- a/DoIt/Extensions/UIImageExtension.swift +++ b/DoIt/Extensions/UIImageExtension.swift @@ -6,6 +6,7 @@ // import UIKit +import Firebase extension UIImage { struct AuthIcons { @@ -48,18 +49,3 @@ extension UIImage { static var feedIcon: UIImage { UIImage(systemName: "square.grid.2x2")! } } } - -extension UIImage { - func setImage(urlAddress: String?, completion: @escaping (UIImage?) -> Void) { - guard let urlAddress = urlAddress, let url = URL(string: urlAddress) else { - return completion(nil) - } - let task = URLSession.shared.dataTask(with: url) { data, response, error in - guard let data = data, error == nil else { return } - DispatchQueue.main.async { - completion(UIImage(data: data)) - } - } - task.resume() - } -} diff --git a/DoIt/Views/Search Users/SearchUsersCell.swift b/DoIt/Views/Search Users/SearchUsersCell.swift index e43de46..f7081c9 100644 --- a/DoIt/Views/Search Users/SearchUsersCell.swift +++ b/DoIt/Views/Search Users/SearchUsersCell.swift @@ -102,7 +102,23 @@ final class SearchUsersCell: UITableViewCell { loginLabel.text = model.username configureSummeryLabel(text: model.summary) configureFollowButton(isFollowed: model.isFollowed ?? false) - configureImageView(image: model.image, name: model.name, login: model.username) + // MARK: - IMAGE FROM URL + //**************************************************************** + //*** + //*** + var cellImage: UIImage? = nil + + if let data = try? Data(contentsOf: model.image!) { + // Create Image and Update Image View + cellImage = UIImage(data: data) + } + + configureImageView(image: cellImage, name: model.name, login: model.username) + //*** + //*** + //**************************************************************** + // MARK: - OLD VERSION +// configureImageView(image: model.image, name: model.name, login: model.username) } private func configureImageView(image: UIImage?, name: String?, login: String) { From 1baee805f623b4c752ebcf29fc73affea7d860b9 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 03:24:46 +0300 Subject: [PATCH 16/28] Add convertation hex -> color && color -> hex --- DoIt/Extensions/UIColorsExtension.swift | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/DoIt/Extensions/UIColorsExtension.swift b/DoIt/Extensions/UIColorsExtension.swift index 39216eb..c7a2109 100644 --- a/DoIt/Extensions/UIColorsExtension.swift +++ b/DoIt/Extensions/UIColorsExtension.swift @@ -61,4 +61,23 @@ extension UIColor { static let brown: UIColor = .brown } } - +extension UIColor { + + func ColorFromHex(rgbValue: Int) -> UIColor { + let red = CGFloat((rgbValue & 0xFF0000) >> 16) / 0xFF + let green = CGFloat((rgbValue & 0x00FF00) >> 8) / 0xFF + let blue = CGFloat(rgbValue & 0x0000FF) / 0xFF + let alpha = CGFloat(1.0) + return UIColor(red: red, green: green, blue: blue, alpha: alpha) + } + + func HexFromColor(color: UIColor) -> Int { + var r: CGFloat = 0 + var g: CGFloat = 0 + var b: CGFloat = 0 + var a: CGFloat = 0 + color.getRed(&r, green: &g, blue: &b, alpha: &a) + let hex = (Int(r * 255) << 16) | (Int(g * 255) << 8) | (Int(g * 255)) + return hex + } +} From 05f647a5533b6e0b02fa5231163be125f54e1e11 Mon Sep 17 00:00:00 2001 From: Yulia Date: Wed, 15 Dec 2021 03:42:56 +0300 Subject: [PATCH 17/28] . --- DoIt.xcodeproj/project.pbxproj | 8 ++++---- DoIt/Models/{Structures.swift => TaskModel.swift} | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) rename DoIt/Models/{Structures.swift => TaskModel.swift} (95%) diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 051868a..941df11 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -21,7 +21,7 @@ 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; 83369A44273856240025F3D9 /* TaskTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A43273856240025F3D9 /* TaskTableViewCell.swift */; }; 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A49273856950025F3D9 /* ChapterCollectionCell.swift */; }; - 83369A4E273857020025F3D9 /* Structures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A4D273857020025F3D9 /* Structures.swift */; }; + 83369A4E273857020025F3D9 /* TaskModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A4D273857020025F3D9 /* TaskModel.swift */; }; 8383503527583E58008847E1 /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8383502227583E57008847E1 /* Auth.swift */; }; 8383503627583E58008847E1 /* CustomNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8383502327583E57008847E1 /* CustomNavigationController.swift */; }; 8383503727583E58008847E1 /* SignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8383502527583E57008847E1 /* SignInController.swift */; }; @@ -78,7 +78,7 @@ 83369A3F273855BD0025F3D9 /* TasksController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksController.swift; sourceTree = ""; }; 83369A43273856240025F3D9 /* TaskTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskTableViewCell.swift; sourceTree = ""; }; 83369A49273856950025F3D9 /* ChapterCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChapterCollectionCell.swift; sourceTree = ""; }; - 83369A4D273857020025F3D9 /* Structures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Structures.swift; sourceTree = ""; }; + 83369A4D273857020025F3D9 /* TaskModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskModel.swift; sourceTree = ""; }; 8383502227583E57008847E1 /* Auth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Auth.swift; sourceTree = ""; }; 8383502327583E57008847E1 /* CustomNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomNavigationController.swift; sourceTree = ""; }; 8383502527583E57008847E1 /* SignInController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignInController.swift; sourceTree = ""; }; @@ -194,7 +194,7 @@ E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */, E4A95D48275BE99900EE3F59 /* UserModel.swift */, E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */, - 83369A4D273857020025F3D9 /* Structures.swift */, + 83369A4D273857020025F3D9 /* TaskModel.swift */, 7C6C3BC3275C05E000B6101F /* UserService.swift */, 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */, 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, @@ -545,7 +545,7 @@ E4A95D5A275BEA8600EE3F59 /* ProfileViewController.swift in Sources */, 7C6382E8272883AC00FED2F4 /* Printer.swift in Sources */, 8383504A27583F93008847E1 /* Strings.swift in Sources */, - 83369A4E273857020025F3D9 /* Structures.swift in Sources */, + 83369A4E273857020025F3D9 /* TaskModel.swift in Sources */, 8383503A27583E58008847E1 /* OnboardingStruct.swift in Sources */, E4BC75FE276537E40016B6E2 /* NotificationNameExtension.swift in Sources */, 83AF41A027429B5500CA8AAA /* CustomTabBarController.swift in Sources */, diff --git a/DoIt/Models/Structures.swift b/DoIt/Models/TaskModel.swift similarity index 95% rename from DoIt/Models/Structures.swift rename to DoIt/Models/TaskModel.swift index 26ed563..cad3001 100644 --- a/DoIt/Models/Structures.swift +++ b/DoIt/Models/TaskModel.swift @@ -38,8 +38,7 @@ class Task { // TODO: - FIX IT self.uid = "" - // TODO: - FIX IT - self.color = .systemBlue + self.color = UIColor().ColorFromHex(rgbValue: dictionary["color"] as! Int) if let creationTimestamp = dictionary["timestamp"] as? Double { self.creationTime = Date(timeIntervalSince1970: creationTimestamp) From 707ba8958980c40af1000e3a0d1e16295d993ec2 Mon Sep 17 00:00:00 2001 From: danil-ivanov Date: Wed, 15 Dec 2021 04:00:11 +0300 Subject: [PATCH 18/28] Doinf viewmodels --- DoIt.xcodeproj/project.pbxproj | 14 +++------ DoIt/ViewModels/AuthViewModel.swift | 31 ++++++++++++++++++++ DoIt/ViewModels/SignUpViewModel.swift | 16 ---------- DoIt/ViewModels/TasksScreenViewModel.swift | 18 ++++++------ DoIt/ViewModels/TasksViewModel.swift | 31 ++++++++++++++++++-- DoIt/Views/SignIn/SignInController.swift | 6 +++- DoIt/Views/SignUp/SignUpController.swift | 13 +++++++++ DoIt/Views/Tasks/TasksController.swift | 34 +++++++++++++++------- 8 files changed, 114 insertions(+), 49 deletions(-) create mode 100644 DoIt/ViewModels/AuthViewModel.swift delete mode 100644 DoIt/ViewModels/SignUpViewModel.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index a1cf8c0..eef34dd 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -18,12 +18,11 @@ 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */; }; 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */; }; 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */; }; - 83349BD627681AF0008D4786 /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BD527681AF0008D4786 /* SignUpViewModel.swift */; }; 83349BDB27681CC2008D4786 /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BD927681CC2008D4786 /* ImageService.swift */; }; 83349BDC27681CC2008D4786 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDA27681CC2008D4786 /* AuthService.swift */; }; 83349BE027682D58008D4786 /* Dynamic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDF27682D58008D4786 /* Dynamic.swift */; }; 83349BE227682D72008D4786 /* TasksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE127682D72008D4786 /* TasksViewModel.swift */; }; - 83349BE427683051008D4786 /* TasksScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE327683051008D4786 /* TasksScreenViewModel.swift */; }; + 83349BE6276959F4008D4786 /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE5276959F4008D4786 /* AuthViewModel.swift */; }; 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; 83369A44273856240025F3D9 /* TaskTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A43273856240025F3D9 /* TaskTableViewCell.swift */; }; 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A49273856950025F3D9 /* ChapterCollectionCell.swift */; }; @@ -82,12 +81,11 @@ 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7CAC5DDB27232C6300E2D70B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 83349BD527681AF0008D4786 /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = ""; }; 83349BD927681CC2008D4786 /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; 83349BDA27681CC2008D4786 /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; 83349BDF27682D58008D4786 /* Dynamic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dynamic.swift; sourceTree = ""; }; 83349BE127682D72008D4786 /* TasksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksViewModel.swift; sourceTree = ""; }; - 83349BE327683051008D4786 /* TasksScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksScreenViewModel.swift; sourceTree = ""; }; + 83349BE5276959F4008D4786 /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = ""; }; 83369A3F273855BD0025F3D9 /* TasksController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksController.swift; sourceTree = ""; }; 83369A43273856240025F3D9 /* TaskTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskTableViewCell.swift; sourceTree = ""; }; 83369A49273856950025F3D9 /* ChapterCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChapterCollectionCell.swift; sourceTree = ""; }; @@ -169,9 +167,8 @@ isa = PBXGroup; children = ( 83349BDF27682D58008D4786 /* Dynamic.swift */, - 83349BD527681AF0008D4786 /* SignUpViewModel.swift */, + 83349BE5276959F4008D4786 /* AuthViewModel.swift */, 83349BE127682D72008D4786 /* TasksViewModel.swift */, - 83349BE327683051008D4786 /* TasksScreenViewModel.swift */, E455B5D9276820E60059130D /* SearchUsersViewModel.swift */, E417CFD627689B2300C6E6B5 /* ProfileViewModel.swift */, E417CFDA2768BE1800C6E6B5 /* ProfileEditViewModel.swift */, @@ -220,7 +217,6 @@ 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */, 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, - 7C6C3BCF275CFEA900B6101F /* TaskService.swift */, E417CFD827689D8A00C6E6B5 /* TaskService.swift */, ); path = Models; @@ -286,7 +282,6 @@ 83349BD42768118E008D4786 /* Recovered References */ = { isa = PBXGroup; children = ( - 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */, ); name = "Recovered References"; sourceTree = ""; @@ -543,7 +538,6 @@ files = ( 83369A44273856240025F3D9 /* TaskTableViewCell.swift in Sources */, E4A95D4D275BE99A00EE3F59 /* UserFollowingModel.swift in Sources */, - 83349BD627681AF0008D4786 /* SignUpViewModel.swift in Sources */, 8383503F27583E58008847E1 /* TaskCategory.swift in Sources */, 8383503B27583E58008847E1 /* OnboardingCell.swift in Sources */, 83AF41A827431F9600CA8AAA /* FeedCollectionViewCell.swift in Sources */, @@ -561,6 +555,7 @@ 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, E417CFDB2768BE1800C6E6B5 /* ProfileEditViewModel.swift in Sources */, E455B5D827681AD20059130D /* ImageService.swift in Sources */, + 83349BE6276959F4008D4786 /* AuthViewModel.swift in Sources */, 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */, 8383504227583E58008847E1 /* SignUpController.swift in Sources */, @@ -583,7 +578,6 @@ 8383504A27583F93008847E1 /* Strings.swift in Sources */, 83369A4E273857020025F3D9 /* Structures.swift in Sources */, 8383503A27583E58008847E1 /* OnboardingStruct.swift in Sources */, - 83349BE427683051008D4786 /* TasksScreenViewModel.swift in Sources */, E4BC75FE276537E40016B6E2 /* NotificationNameExtension.swift in Sources */, 83AF41A027429B5500CA8AAA /* CustomTabBarController.swift in Sources */, 8383503627583E58008847E1 /* CustomNavigationController.swift in Sources */, diff --git a/DoIt/ViewModels/AuthViewModel.swift b/DoIt/ViewModels/AuthViewModel.swift new file mode 100644 index 0000000..0d9a154 --- /dev/null +++ b/DoIt/ViewModels/AuthViewModel.swift @@ -0,0 +1,31 @@ +// +// AuthViewModel.swift +// DoIt +// +// Created by Данил Иванов on 15.12.2021. +// + +import Foundation + +final class AuthViewModel { + private let authService = AuthService.shared + + var authResultModel: Observable = Observable() + + func signUp(email: String?, username: String?, password: String?) { + self.authService.signUp(email: email, username: username, password: password) { [weak self] authResult in + self?.authResultModel.value = authResult + } + } + + func signIn(email: String?, password: String?) { + self.authService.signIn(email: email, password: password) { authResult in + switch authResult { + case .success: + print("Auth success") + case .failure(let error): + print("Auth was failured: ", error.localizedDescription) + } + } + } +} diff --git a/DoIt/ViewModels/SignUpViewModel.swift b/DoIt/ViewModels/SignUpViewModel.swift deleted file mode 100644 index 31e842f..0000000 --- a/DoIt/ViewModels/SignUpViewModel.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// SignUpViewModel.swift -// DoIt -// -// Created by Данил Иванов on 14.12.2021. -// - -import Foundation - -class SignUpViewModel: NSObject { - private var authService = AuthService() - var isSuccesed = false - - func singUp(withEmail: String, withUsername: String, withPassword: String) { - } -} diff --git a/DoIt/ViewModels/TasksScreenViewModel.swift b/DoIt/ViewModels/TasksScreenViewModel.swift index 830ad48..439c9c6 100644 --- a/DoIt/ViewModels/TasksScreenViewModel.swift +++ b/DoIt/ViewModels/TasksScreenViewModel.swift @@ -7,12 +7,12 @@ import Foundation -class TasksScreenViewModel: NSObject, TasksViewModel { - var preparedTasks: Dynamic<[Task]> - var allTasks: [Task] - let taskService = TaskS - - override init() { - allTasks = taskService. - } -} +//class TasksScreenViewModel: NSObject, TasksViewModel { +// var preparedTasks: Dynamic<[Task]> +// var allTasks: [Task] +// let taskService = TaskS +// +// override init() { +// allTasks = taskService. +// } +//} diff --git a/DoIt/ViewModels/TasksViewModel.swift b/DoIt/ViewModels/TasksViewModel.swift index 112a715..5be4b10 100644 --- a/DoIt/ViewModels/TasksViewModel.swift +++ b/DoIt/ViewModels/TasksViewModel.swift @@ -7,6 +7,33 @@ import Foundation -protocol TasksViewModel { - var preparedTasks: Dynamic<[Task]> { get } +final class TasksViewModel { + private let taskService = TaskService.shared + + var taskModels: Observable<[Task]> = Observable([]) + + var taskModel: Observable = Observable() + //var onTasksChanged: (([Task]) -> Void)? + + func getTasks(forUser: UserModel) { + self.taskService.fetchTasks(forUser: forUser) { [weak self] tasks in + self?.taskModels.value = tasks + //self?.onTasksChanged?(tasks) + } + } + + func getTask(withId: String) { + self.taskService.fetchTask(taskId: withId) { [weak self] task in + self?.taskModel.value = task + } + } + + func uploadTask(task: Task) { + self.taskService.uploadTask(task: task) { error, _ in + if error != nil { + //костыль + print("Task Upload Failed") + } + } + } } diff --git a/DoIt/Views/SignIn/SignInController.swift b/DoIt/Views/SignIn/SignInController.swift index bcece3c..126e54b 100644 --- a/DoIt/Views/SignIn/SignInController.swift +++ b/DoIt/Views/SignIn/SignInController.swift @@ -26,6 +26,8 @@ class SignInController: UIViewController { return button }() + private let viewModel = AuthViewModel() + override func viewDidLoad() { super.viewDidLoad() configureView() @@ -52,9 +54,11 @@ class SignInController: UIViewController { } @objc private func signInButtonPressed(_ sender: UIButton) { + self.viewModel.signIn(email: usernameInputView.textField.text, password: passwordInputView.textField.text) + let tabbarController = CustomTabBarController() tabbarController.modalPresentationStyle = .fullScreen - present(tabbarController, animated: true) + //present(tabbarController, animated: true) } diff --git a/DoIt/Views/SignUp/SignUpController.swift b/DoIt/Views/SignUp/SignUpController.swift index 0b6df3a..045b52d 100644 --- a/DoIt/Views/SignUp/SignUpController.swift +++ b/DoIt/Views/SignUp/SignUpController.swift @@ -32,7 +32,14 @@ class SignUpController: UIViewController { return button }() + private let viewModel = AuthViewModel() + //private var authResult = AuthResult + override func viewDidLoad() { +// viewModel.authResultModel.bind { [weak self] _ in +// self?.authResult = viewModel.authResultModel.value +// } + super.viewDidLoad() configureView() } @@ -58,6 +65,12 @@ class SignUpController: UIViewController { } @objc private func registerButtonPressed(_ sender: UIButton) { + self.viewModel.signUp(email: envelopeInputView.textField.text, + username: usernameInputView.textField.text, + password: passwordInputView.textField.text) + + case viewModel.authResultModel + let onboardingViewController = OnboardingViewController() onboardingViewController.modalPresentationStyle = .fullScreen present(onboardingViewController, animated: true) diff --git a/DoIt/Views/Tasks/TasksController.swift b/DoIt/Views/Tasks/TasksController.swift index a26814b..dcc7c29 100644 --- a/DoIt/Views/Tasks/TasksController.swift +++ b/DoIt/Views/Tasks/TasksController.swift @@ -53,18 +53,14 @@ class TasksController: UIViewController { return tableView }() - private var viewModel: TasksViewModel? { - didSet { - - } - } + private let viewModel: TasksViewModel = TasksViewModel() - var tasks: [Task] = [ -// Task(image: UIImage(named: "bob"), title: "Task 1: Get ready for an exam", description: nil, deadline: nil, isDone: true, creatorId: "1", color: .black, chapterId: 0, creationTime: Date(), isMyTask: true), -// Task(image: UIImage(named: "bob"), title: "Task 2: Get ready for an exam", description: nil, deadline: nil, isDone: false, creatorId: "2", color: .yellow, chapterId: 1, creationTime: Date(), isMyTask: true), -// Task(image: UIImage(named: "bob"), title: "Task 3: Get ready for an exam", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: nil, isDone: false, creatorId: "2", color: .red, chapterId: 2, creationTime: Date(), isMyTask: true), -// Task(image: UIImage(named: "bob"), title: "Task 4: Get ready for an exam", description: "Math exam. jad;lfajslf;jasl;dfjlskfja;sldf", deadline: Date(timeIntervalSinceNow: 50), isDone: true, creatorId: "1", color: .orange, chapterId: 3, creationTime: Date(), isMyTask: true) - ] + //костыль + private lazy var tasks: [Task] = { + return [Task(image: nil, title: "", description: nil, deadline: nil, isDone: false, color: .black), + Task(image: nil, title: "", description: nil, deadline: nil, isDone: false, color: .black), + Task(image: nil, title: "", description: nil, deadline: nil, isDone: false, color: .black)] + }() private var selectedTasks: [Task]? { didSet { @@ -79,7 +75,16 @@ class TasksController: UIViewController { //MARK: - Override Methods override func viewDidLoad() { + super.viewDidLoad() + viewModel.taskModels.bind { [weak self] _ in + DispatchQueue.main.async { + self?.reload() + } + } + + //let currentUser = UserModel(uid: UserDefaults.standard.string(forKey: "current_user")!, email: "", username: "", summary: nil, image: nil, name: nil) + //viewModel.getTasks(forUser: currentUser) view.backgroundColor = .systemBackground configureNavigationController() view.addSubview(table) @@ -88,6 +93,12 @@ class TasksController: UIViewController { } //MARK: - Private Methods + private func reload() { + table.reloadData() + //guard let userTasks = viewModel.taskModels.value else { return } + //tasks = userTasks + } + private func configureNavigationController() { navigationItem.title = TasksStrings.header.rawValue.localized navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? profileButton : nil @@ -117,6 +128,7 @@ extension TasksController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TaskTableViewCell.self), for: indexPath) as? TaskTableViewCell else { return .init(frame: .zero) } + //тут отрисовываем ячейки с данными из modelView.sortedtasks cell.configureCell(taskInfo: selectedTasks?[indexPath.row] ?? tasks[indexPath.row]) return cell } From 51fdd7ec7699ea5713b711988eb88d47b67997fb Mon Sep 17 00:00:00 2001 From: danil-ivanov Date: Wed, 15 Dec 2021 13:51:42 +0300 Subject: [PATCH 19/28] signupviewmodel --- DoIt.xcodeproj/project.pbxproj | 6 ++---- DoIt/Views/SignUp/SignUpController.swift | 24 +++++++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 886a510..a4d5934 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -551,9 +551,7 @@ 83AF41A227431EB500CA8AAA /* FeedController.swift in Sources */, 8383503927583E58008847E1 /* OnboardingViewController.swift in Sources */, E417CFDB2768BE1800C6E6B5 /* ProfileEditViewModel.swift in Sources */, - E455B5D827681AD20059130D /* ImageService.swift in Sources */, 83349BE6276959F4008D4786 /* AuthViewModel.swift in Sources */, - 8383503D27583E58008847E1 /* TaskViewController.swift in Sources */, 7C6C3BC8275C06B400B6101F /* AuthResultsModel.swift in Sources */, 8383504227583E58008847E1 /* SignUpController.swift in Sources */, @@ -748,7 +746,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt; + PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -777,7 +775,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt; + PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/DoIt/Views/SignUp/SignUpController.swift b/DoIt/Views/SignUp/SignUpController.swift index 045b52d..437d135 100644 --- a/DoIt/Views/SignUp/SignUpController.swift +++ b/DoIt/Views/SignUp/SignUpController.swift @@ -41,6 +41,17 @@ class SignUpController: UIViewController { // } super.viewDidLoad() + + viewModel.authResultModel.bind { authResult in + switch authResult { + case .success: + print("auth successed") + case .failure(let error): + print("Auth was failured: ", error.localizedDescription) + case .none: + return + } + } configureView() } @@ -64,17 +75,16 @@ class SignUpController: UIViewController { stack.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true } + private func presentOnboarding() { + let onboardingViewController = OnboardingViewController() + onboardingViewController.modalPresentationStyle = .fullScreen + present(onboardingViewController, animated: true) + } + @objc private func registerButtonPressed(_ sender: UIButton) { self.viewModel.signUp(email: envelopeInputView.textField.text, username: usernameInputView.textField.text, password: passwordInputView.textField.text) - - case viewModel.authResultModel - - let onboardingViewController = OnboardingViewController() - onboardingViewController.modalPresentationStyle = .fullScreen - present(onboardingViewController, animated: true) - } @objc private func signInButtonPressed(_ sender: UIButton) { From 81296cfa758d6f9a29b005b9af8ebe8383376ba3 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 15 Dec 2021 22:11:16 +0300 Subject: [PATCH 20/28] change firebase and images download/upload --- DoIt.xcodeproj/project.pbxproj | 4 +- DoIt/Models/TaskModel.swift | 43 ++++++----- DoIt/Models/TaskService.swift | 30 +++----- DoIt/Models/UserModel.swift | 19 +++-- DoIt/ViewModels/ProfileEditViewModel.swift | 30 +++++++- DoIt/ViewModels/ProfileViewModel.swift | 15 ++++ DoIt/ViewModels/SearchUsersViewModel.swift | 14 ++++ .../FeedCollectionViewCell.swift | 5 +- DoIt/Views/Feed/FeedController.swift | 3 +- .../Profile/ProfileEditViewController.swift | 28 ++++--- .../Profile/ProfileFollowingUserCell.swift | 11 +-- .../Views/Profile/ProfileViewController.swift | 69 ++++++++++++----- DoIt/Views/Search Users/SearchUsersCell.swift | 23 +----- .../Search Users/SearchUsersController.swift | 10 +++ .../Task Screen/TaskEditViewController.swift | 2 +- .../Task Screen/TaskViewController.swift | 2 +- .../TasksTableView/TaskTableViewCell.swift | 2 +- GoogleService-Info.plist | 30 ++++---- Podfile | 3 +- Podfile.lock | 74 +++++++++---------- 20 files changed, 245 insertions(+), 172 deletions(-) diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 941df11..8ebced4 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -718,7 +718,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt; + PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -747,7 +747,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt; + PRODUCT_BUNDLE_IDENTIFIER = com.vkproj.doIt1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/DoIt/Models/TaskModel.swift b/DoIt/Models/TaskModel.swift index cad3001..ae82245 100644 --- a/DoIt/Models/TaskModel.swift +++ b/DoIt/Models/TaskModel.swift @@ -8,13 +8,14 @@ import UIKit import Firebase -class Task { +final class Task { + let taskId: String let image: URL? let title: String let description: String? let deadline: Date? let isDone: Bool - let uid: String? + let uid: String let color: UIColor let chapterId: Int let creationTime: Date @@ -23,29 +24,33 @@ class Task { return Auth.auth().currentUser?.uid == uid } - init(uid: User, id: String, dictionary: [String: AnyObject]) { + init(id: String, dictionary: [String: AnyObject]) { + taskId = id if let profileImageUrlString = dictionary["userPhotoUrl"] as? String { - guard let url = URL(string: profileImageUrlString) else {return} - self.image = url + image = URL(string: profileImageUrlString) + } else { + image = nil } - self.title = dictionary["title"] as? String ?? "" - self.description = dictionary["description"] as? String ?? "" + title = dictionary["title"] as? String ?? "" + description = dictionary["description"] as? String if let deadlineTimestamp = dictionary["deadline"] as? Double { - self.deadline = Date(timeIntervalSince1970: deadlineTimestamp) + deadline = Date(timeIntervalSince1970: deadlineTimestamp) + } else { + deadline = nil + } + isDone = dictionary["is_done"] as? Bool ?? false + uid = dictionary["uid"] as? String ?? "" + if let colorHex = dictionary["color"] as? Int { + color = UIColor().ColorFromHex(rgbValue: colorHex) + } else { + color = .clear } - self.isDone = dictionary["is_done"] as? Bool ?? false - - // TODO: - FIX IT - self.uid = "" - - self.color = UIColor().ColorFromHex(rgbValue: dictionary["color"] as! Int) - if let creationTimestamp = dictionary["timestamp"] as? Double { - self.creationTime = Date(timeIntervalSince1970: creationTimestamp) + creationTime = Date(timeIntervalSince1970: creationTimestamp) + } else { + creationTime = Date(timeIntervalSince1970: 0) } - - // NOT DONE - self.chapterId = dictionary["chapter_id"] as? Int ?? 0 + chapterId = dictionary["chapter_id"] as? Int ?? 0 } // TODO: - FIX IT diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift index 3b3ca64..d6565a6 100644 --- a/DoIt/Models/TaskService.swift +++ b/DoIt/Models/TaskService.swift @@ -51,28 +51,16 @@ class TaskService { func fetchTask(taskId: String, completion: @escaping(Task) -> Void){ REF_TASKS.child(taskId).observeSingleEvent(of: .value) { snapshot in - guard let dictionary = snapshot.value as? [String: Any] else {return} - guard let uid = dictionary["uid"] as? String else {return} - guard let image = dictionary["image"] as? String else { return } - guard let title = dictionary["title"] as? String else { return } - guard let description = dictionary["description"] as? String else { return } - guard let deadline = dictionary["deadline"] as? Int else { return } - guard let isDone = dictionary["is_done"] as? Bool else { return } - guard let color = dictionary["color"] as? [Int] else { return } + guard let dictionary = snapshot.value as? [String: AnyObject] else {return} +// guard let uid = dictionary["uid"] as? String else {return} +// guard let image = dictionary["image"] as? String else { return } +// guard let title = dictionary["title"] as? String else { return } +// guard let description = dictionary["description"] as? String else { return } +// guard let deadline = dictionary["deadline"] as? Int else { return } +// guard let isDone = dictionary["is_done"] as? Bool else { return } +// guard let color = dictionary["color"] as? [Int] else { return } - - UserService.shared.fetchUser(uid: uid) { (user) in - - let task = Task( - image: nil, - title: title, - description: description, - deadline: Date(timeIntervalSince1970: TimeInterval(deadline)), - isDone: isDone, - color: UIColor(red: CGFloat(color[0]) * 255.0, green: CGFloat(color[1]) * 255.0, blue: CGFloat(color[2]) * 255.0, alpha: 1.0) - ) - completion(task) - } + completion(Task(id: taskId, dictionary: dictionary)) } } diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index 24cdb5d..b0a3bef 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -30,19 +30,18 @@ class UserModel { self.summary = dictionary["summary"] as? String self.name = nil if let profileImageUrlString = dictionary["userPhotoUrl"] as? String { - guard let url = URL(string: profileImageUrlString) else {return} - self.image = url + self.image = URL(string: profileImageUrlString) } } // TODO: - FIX IT -// init(uid: String, email: String, username: String, summary: String?, image: UIImage?, name: String?) { -// self.uid = uid -// self.email = email -// self.username = username -// self.summary = summary -// self.image = image -// self.name = name -// } + init(uid: String, email: String, username: String, summary: String?, imageURL: URL?, name: String?) { + self.uid = uid + self.email = email + self.username = username + self.summary = summary + self.image = imageURL + self.name = name + } } diff --git a/DoIt/ViewModels/ProfileEditViewModel.swift b/DoIt/ViewModels/ProfileEditViewModel.swift index 235e6fd..a777217 100644 --- a/DoIt/ViewModels/ProfileEditViewModel.swift +++ b/DoIt/ViewModels/ProfileEditViewModel.swift @@ -15,13 +15,20 @@ final class ProfileEditViewModel { func updateUserProfile(image: UIImage?, name: String?, username: String, summary: String?, complition: @escaping () -> ()) { DispatchQueue.global().sync { [weak self] in guard let userModel = userModel.value else { + complition() return } var wasChanged = false - var newImage = userModel.image - if let image = image, image != newImage { - newImage = image + var newImageURL: URL? = nil + if let image = image { + userService.updateUserPhoto(image: image) { url in + newImageURL = url + } + guard newImageURL != nil else { + complition() + return + } wasChanged = true } @@ -41,10 +48,11 @@ final class ProfileEditViewModel { } guard wasChanged else { + complition() return } - let newUserModel = UserModel(uid: userModel.uid, email: userModel.email, username: username, summary: newSummary, image: newImage, name: newName) + let newUserModel = UserModel(uid: userModel.uid, email: userModel.email, username: username, summary: newSummary, imageURL: newImageURL, name: newName) self?.userService.updateUserData(user: newUserModel, completion: { error, _ in if error != nil { @@ -54,4 +62,18 @@ final class ProfileEditViewModel { }) } } + + func downloadImage(_ url: URL?, completion: @escaping (UIImage?) -> ()) { + DispatchQueue.global().async { + var cellImage: UIImage? = nil + guard let url = url else { + completion(cellImage) + return + } + if let data = try? Data(contentsOf: url) { + cellImage = UIImage(data: data) + } + completion(cellImage) + } + } } diff --git a/DoIt/ViewModels/ProfileViewModel.swift b/DoIt/ViewModels/ProfileViewModel.swift index cd1ffa8..40e737f 100644 --- a/DoIt/ViewModels/ProfileViewModel.swift +++ b/DoIt/ViewModels/ProfileViewModel.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit final class ProfileViewModel { private let userService = UserService.shared @@ -72,4 +73,18 @@ final class ProfileViewModel { } } } + + func downloadImage(_ url: URL?, completion: @escaping (UIImage?) -> ()) { + DispatchQueue.global().async { + var cellImage: UIImage? = nil + guard let url = url else { + completion(cellImage) + return + } + if let data = try? Data(contentsOf: url) { + cellImage = UIImage(data: data) + } + completion(cellImage) + } + } } diff --git a/DoIt/ViewModels/SearchUsersViewModel.swift b/DoIt/ViewModels/SearchUsersViewModel.swift index fcdac20..d3482be 100644 --- a/DoIt/ViewModels/SearchUsersViewModel.swift +++ b/DoIt/ViewModels/SearchUsersViewModel.swift @@ -86,6 +86,20 @@ final class SearchUsersViewModel { } } + func downloadImage(_ url: URL?, completion: @escaping (UIImage?) -> ()) { + DispatchQueue.global().async { + var cellImage: UIImage? = nil + guard let url = url else { + completion(cellImage) + return + } + if let data = try? Data(contentsOf: url) { + cellImage = UIImage(data: data) + } + completion(cellImage) + } + } + func filtering(username: String) { DispatchQueue.global().async { [weak self] in self?.filteredUsersModel.value = self?.userModels.value?.filter { $0.username.lowercased().contains(username.lowercased()) } diff --git a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift index 039b5cd..16d1a03 100644 --- a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift +++ b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift @@ -77,7 +77,8 @@ class FeedCollectionViewCell: UICollectionViewCell { //MARK: - Public Methods func configureCell(taskInfo: Task, userInfo: UserModel) { - taskImage.image = taskInfo.image ?? UIImage.TaskIcons.defaultImage + // MARK: - CHANGE +// taskImage.image = taskInfo.image ?? UIImage.TaskIcons.defaultImage taskLabel.text = taskInfo.title creatorLabel.text = "@" + userInfo.username guard let image = userInfo.image else { @@ -85,7 +86,7 @@ class FeedCollectionViewCell: UICollectionViewCell { creatorImage.setImageForName(userInfo.name ?? userInfo.username, circular: false, textAttributes: nil) return } - creatorImage.image = image +// creatorImage.image = image } private func configureUI() { diff --git a/DoIt/Views/Feed/FeedController.swift b/DoIt/Views/Feed/FeedController.swift index 45c3b83..caf5fe3 100644 --- a/DoIt/Views/Feed/FeedController.swift +++ b/DoIt/Views/Feed/FeedController.swift @@ -89,7 +89,8 @@ class FeedController: UIViewController { private func configureNavigationController() { navigationItem.title = (userModel?.isCurrentUser ?? false) ? FeedStrings.header.rawValue.localized : FeedStrings.allTasksHeader.rawValue.localized - navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil +// navigationItem.rightBarButtonItem = (userModel?.isCurrentUser ?? false) ? searchButton : nil + navigationItem.rightBarButtonItem = searchButton } diff --git a/DoIt/Views/Profile/ProfileEditViewController.swift b/DoIt/Views/Profile/ProfileEditViewController.swift index 2484ff6..ad9c9ce 100644 --- a/DoIt/Views/Profile/ProfileEditViewController.swift +++ b/DoIt/Views/Profile/ProfileEditViewController.swift @@ -137,11 +137,9 @@ final class ProfileEditViewController: UIViewController { view.snapshotView(afterScreenUpdates: true) - viewModel.userModel.bind { [weak self] user in - self?.configure() - } - configureUI() + + configure() } // MARK: - Helpers @@ -149,12 +147,19 @@ final class ProfileEditViewController: UIViewController { private func configure() { guard let userModel = viewModel.userModel.value else { return } summaryTextView.text = userModel.summary - guard let image = userModel.image else { - profileImageView.layoutIfNeeded() - profileImageView.setImageForName(userModel.name ?? userModel.username, circular: false, textAttributes: nil) + profileImageView.layoutIfNeeded() + profileImageView.setImageForName(userModel.name ?? userModel.username, circular: false, textAttributes: nil) + guard let imageURL = userModel.image else { return } - profileImageView.image = image + viewModel.downloadImage(imageURL) { image in + guard let image = image else { + return + } + DispatchQueue.main.async { [weak self] in + self?.profileImageView.image = image + } + } } private func configureUI() { @@ -163,7 +168,6 @@ final class ProfileEditViewController: UIViewController { layoutScrollView() layoutStackView() layoutWidthInputFields() - configure() } private func configureNavigationController() { @@ -201,7 +205,11 @@ extension ProfileEditViewController { name: nameInputField.textField.text, username: loginInputField.textField.text ?? userModel.username, summary: summaryTextView.textView.text.isEmpty ? nil : summaryTextView.textView.text, - complition: { [weak self] in self?.navigationController?.popViewController(animated: true) }) + complition: { + DispatchQueue.main.async { [weak self] in + self?.navigationController?.popViewController(animated: true) + } + }) } } diff --git a/DoIt/Views/Profile/ProfileFollowingUserCell.swift b/DoIt/Views/Profile/ProfileFollowingUserCell.swift index 644fe11..158e45d 100644 --- a/DoIt/Views/Profile/ProfileFollowingUserCell.swift +++ b/DoIt/Views/Profile/ProfileFollowingUserCell.swift @@ -52,11 +52,12 @@ class ProfileFollowingUserCell: UICollectionViewCell { // MARK: - Helpers func configureCell(with: UserModel) { loginLabel.text = "@" + with.username - guard let image = with.image else { - profileImageView.layoutIfNeeded() - profileImageView.setImageForName(with.name ?? with.username, circular: false, textAttributes: nil) - return - } + profileImageView.layoutIfNeeded() + profileImageView.setImageForName(with.name ?? with.username, circular: false, textAttributes: nil) + } + + func configureImage(_ image: UIImage?) { + guard let image = image else { return } profileImageView.image = image } diff --git a/DoIt/Views/Profile/ProfileViewController.swift b/DoIt/Views/Profile/ProfileViewController.swift index 88bfb33..85e7573 100644 --- a/DoIt/Views/Profile/ProfileViewController.swift +++ b/DoIt/Views/Profile/ProfileViewController.swift @@ -286,27 +286,34 @@ class ProfileViewController: UIViewController { configureUI() - viewModel.userModel.bind { [weak self] _ in - self?.configureCells() - self?.viewModel.getUserTasks() - self?.viewModel.getUserFollowings() + viewModel.userModel.bind { _ in + DispatchQueue.main.async { [weak self] in + self?.configureCells() + } } - viewModel.userTasksModel.bind { [weak self] _ in - self?.configureTasks() - self?.configureStatistics() + viewModel.userTasksModel.bind { _ in + DispatchQueue.main.async { [weak self] in + self?.configureTasks() + self?.configureStatistics() + } } - viewModel.userFollowingModel.bind { [weak self] _ in - self?.configureFollowing() + viewModel.userFollowingModel.bind { _ in + DispatchQueue.main.async { [weak self] in + self?.configureFollowing() + } } + + viewModel.getUserTasks() + viewModel.getUserFollowings() } // MARK: - Helpers private func configureCells() { guard let userModel = viewModel.userModel.value else { return } - configureHeader(image: userModel.image, name: userModel.name, login: userModel.username, isFollowed: userModel.isFollowed ?? false, isMyScreen: userModel.isCurrentUser) + configureHeader(imageURL: userModel.image, name: userModel.name, login: userModel.username, isFollowed: userModel.isFollowed ?? false, isMyScreen: userModel.isCurrentUser) configureInformation(summary: userModel.summary) configureStatistics() } @@ -584,9 +591,9 @@ extension ProfileViewController { extension ProfileViewController { // MARK: - Header - private func configureHeader(image: UIImage?, name: String?, login: String, isFollowed: Bool, isMyScreen: Bool) { + private func configureHeader(imageURL: URL?, name: String?, login: String, isFollowed: Bool, isMyScreen: Bool) { configureHeaderHeight(withName: name != nil, isMyScreen: isMyScreen) - configureProfileImage(image: image, name: name, login: login) + configureProfileImage(imageURL: imageURL, name: name, login: login) nameLabel.text = name loginLabel.text = "@" + login @@ -608,13 +615,20 @@ extension ProfileViewController { } } - private func configureProfileImage(image: UIImage?, name: String?, login: String) { - guard let image = image else { + private func configureProfileImage(imageURL: URL?, name: String?, login: String) { + guard let imageURL = imageURL else { profileImageView.layoutIfNeeded() profileImageView.setImageForName(name ?? login, circular: false, textAttributes: nil) return } - profileImageView.image = image + viewModel.downloadImage(imageURL) { image in + guard let image = image else { + return + } + DispatchQueue.main.async { [weak self] in + self?.profileImageView.image = image + } + } } // MARK: - Information View @@ -636,7 +650,7 @@ extension ProfileViewController { tasks.forEach { task in guard !task.isDone else { done += 1; return } guard let deadline = task.deadline else { inProgress += 1; return } - guard deadline < currentDate else { outdated += 1; return } + guard deadline > currentDate else { outdated += 1; return } inProgress += 1 } @@ -679,10 +693,21 @@ extension ProfileViewController { private func configureTaskView(index: Int, with: Task) { guard index < taskViews.count else { return } taskViews[index].chapterTaskIndicatorView.backgroundColor = with.color - taskViews[index].imageTaskLabel.image = with.image ?? .TaskIcons.defaultImage + taskViews[index].imageTaskLabel.image = .TaskIcons.defaultImage taskViews[index].titleTaskLabel.text = with.title taskViews[index].desciptionTaskLabel.text = with.description ?? TaskString.description.rawValue.localized taskViews[index].dividerTaskView.backgroundColor = with.color + + if let taskURL = with.image { + viewModel.downloadImage(taskURL) { image in + guard let image = image else { + return + } + DispatchQueue.main.async { [weak self] in + self?.taskViews[index].imageTaskLabel.image = image + } + } + } guard let date = with.deadline else { taskViews[index].deadlineTaskLabel.text = TaskString.deadline.rawValue.localized return @@ -720,6 +745,14 @@ extension ProfileViewController: UICollectionViewDataSource { } guard let userFollowingModel = viewModel.userFollowingModel.value else { return .init() } cell.configureCell(with: userFollowingModel.followings[indexPath.row]) + viewModel.downloadImage(userFollowingModel.followings[indexPath.row].image) { image in + guard let image = image else { + return + } + DispatchQueue.main.async { + cell.configureImage(image) + } + } return cell } } @@ -785,7 +818,7 @@ extension ProfileViewController { @objc private func openSettings() { let profileEditViewController = ProfileEditViewController() - profileEditViewController.viewModel.userModel.value = viewModel.userModel.value + profileEditViewController.viewModel.userModel = viewModel.userModel profileEditViewController.hidesBottomBarWhenPushed = true navigationController?.pushViewController(profileEditViewController, animated: true) } diff --git a/DoIt/Views/Search Users/SearchUsersCell.swift b/DoIt/Views/Search Users/SearchUsersCell.swift index f7081c9..c59e9a1 100644 --- a/DoIt/Views/Search Users/SearchUsersCell.swift +++ b/DoIt/Views/Search Users/SearchUsersCell.swift @@ -102,29 +102,12 @@ final class SearchUsersCell: UITableViewCell { loginLabel.text = model.username configureSummeryLabel(text: model.summary) configureFollowButton(isFollowed: model.isFollowed ?? false) - // MARK: - IMAGE FROM URL - //**************************************************************** - //*** - //*** - var cellImage: UIImage? = nil - - if let data = try? Data(contentsOf: model.image!) { - // Create Image and Update Image View - cellImage = UIImage(data: data) - } - - configureImageView(image: cellImage, name: model.name, login: model.username) - //*** - //*** - //**************************************************************** - // MARK: - OLD VERSION -// configureImageView(image: model.image, name: model.name, login: model.username) + profileImageView.layoutIfNeeded() + profileImageView.setImageForName(model.name ?? model.username, circular: false, textAttributes: nil) } - private func configureImageView(image: UIImage?, name: String?, login: String) { - profileImageView.layoutIfNeeded() + func configureImage(image: UIImage?) { guard let image = image else { - profileImageView.setImageForName(name ?? login, circular: false, textAttributes: nil) return } profileImageView.image = image diff --git a/DoIt/Views/Search Users/SearchUsersController.swift b/DoIt/Views/Search Users/SearchUsersController.swift index 577f4cd..e4a6237 100644 --- a/DoIt/Views/Search Users/SearchUsersController.swift +++ b/DoIt/Views/Search Users/SearchUsersController.swift @@ -162,10 +162,20 @@ extension SearchUsersController: UITableViewDataSource { cell.indexPathRow = indexPath.row guard viewModel.filteredUsersModel.value == nil else { cell.configureCell(with: viewModel.filteredUsersModel.value![indexPath.row]) + viewModel.downloadImage(viewModel.filteredUsersModel.value![indexPath.row].image) { image in + DispatchQueue.main.async { + cell.configureImage(image: image) + } + } return cell } if let userModels = viewModel.userModels.value { cell.configureCell(with: userModels[indexPath.row]) + viewModel.downloadImage(userModels[indexPath.row].image) { image in + DispatchQueue.main.async { + cell.configureImage(image: image) + } + } } return cell } diff --git a/DoIt/Views/Task Screen/TaskEditViewController.swift b/DoIt/Views/Task Screen/TaskEditViewController.swift index 537dbf3..9a94f46 100644 --- a/DoIt/Views/Task Screen/TaskEditViewController.swift +++ b/DoIt/Views/Task Screen/TaskEditViewController.swift @@ -154,7 +154,7 @@ class TaskEditViewController: UIViewController { taskLabel.textField.text = taskModel.title taskChapter.text = TaskCategory(index: taskModel.chapterId).chapter.title taskDescription.text = taskModel.description - taskImage.image = taskModel.image +// taskImage.image = taskModel.image guard let deadline = taskModel.deadline else { return } timerLabel.text = dateFormatter.string(from: deadline) } diff --git a/DoIt/Views/Task Screen/TaskViewController.swift b/DoIt/Views/Task Screen/TaskViewController.swift index 9a7b13b..2e5ec28 100644 --- a/DoIt/Views/Task Screen/TaskViewController.swift +++ b/DoIt/Views/Task Screen/TaskViewController.swift @@ -107,7 +107,7 @@ class TaskViewController: UIViewController { private func configure() { guard let taskModel = taskModel else { return } - taskImage.image = taskModel.image ?? .TaskIcons.defaultImage +// taskImage.image = taskModel.image ?? .TaskIcons.defaultImage taskDescription.text = taskModel.description taskChapter.text = TaskCategory(index: taskModel.chapterId).chapter.title configureNavigationBar(title: taskModel.title, isDone: taskModel.isDone) diff --git a/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift b/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift index 6ebf4b2..d2d657c 100644 --- a/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift +++ b/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift @@ -66,7 +66,7 @@ class TaskTableViewCell: UITableViewCell { func configureCell(taskInfo: Task) { chapterIndicator.backgroundColor = taskInfo.color taskInfo.isDone ? checkBox.setImage(.TaskIcons.done, for: .normal) : checkBox.setImage(.TaskIcons.notDone, for: .normal) - image.image = taskInfo.image ?? .TaskIcons.defaultImage +// image.image = taskInfo.image ?? .TaskIcons.defaultImage title.text = taskInfo.title taskDescription.text = taskInfo.description ?? TaskString.description.rawValue.localized divider.backgroundColor = taskInfo.color diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist index d9885d2..8a0748e 100644 --- a/GoogleService-Info.plist +++ b/GoogleService-Info.plist @@ -3,34 +3,32 @@ CLIENT_ID - 562011549386-m8uaj5enlra65cq7qlrg3jk91mv66fk5.apps.googleusercontent.com + 602688246846-qrh1cc9j0t3jp82esmfohto1npg4fajn.apps.googleusercontent.com REVERSED_CLIENT_ID - com.googleusercontent.apps.562011549386-m8uaj5enlra65cq7qlrg3jk91mv66fk5 + com.googleusercontent.apps.602688246846-qrh1cc9j0t3jp82esmfohto1npg4fajn API_KEY - AIzaSyC6JYyF7IDY-kw3AH9Hl6v9E4b7L7Gj-Is + AIzaSyDSEhOuurCP73LiF9FHZPjBPP2-dl3c2Tc GCM_SENDER_ID - 562011549386 + 602688246846 PLIST_VERSION 1 BUNDLE_ID - com.vkproj.doIt + com.vkproj.doIt1 PROJECT_ID - doit-b9c45 + doit-d4f58 STORAGE_BUCKET - doit-b9c45.appspot.com + doit-d4f58.appspot.com IS_ADS_ENABLED - + IS_ANALYTICS_ENABLED - + IS_APPINVITE_ENABLED - + IS_GCM_ENABLED - + IS_SIGNIN_ENABLED - - DATABASE_URL - https://doit-b9c45-default-rtdb.firebaseio.com/ + GOOGLE_APP_ID - 1:562011549386:ios:6fcfaa37eaad2ceab88e33 + 1:602688246846:ios:ac3f4f04a7c992f0e22d6f - + \ No newline at end of file diff --git a/Podfile b/Podfile index 208e79c..a29d436 100644 --- a/Podfile +++ b/Podfile @@ -6,11 +6,10 @@ target 'DoIt' do use_frameworks! # Pods for DoIt - pod "EasyNotificationBadge" pod "InitialsImageView" pod 'SwipeableTabBarController' pod 'Firebase/Core' pod 'Firebase/Database' pod 'Firebase/Storage' pod 'Firebase/Auth' -end \ No newline at end of file +end diff --git a/Podfile.lock b/Podfile.lock index 00a4ae9..e69f803 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,21 +1,20 @@ PODS: - - EasyNotificationBadge (1.2.5) - - Firebase/Auth (8.9.0): + - Firebase/Auth (8.10.0): - Firebase/CoreOnly - - FirebaseAuth (~> 8.9.0) - - Firebase/Core (8.9.0): + - FirebaseAuth (~> 8.10.0) + - Firebase/Core (8.10.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 8.9.0) - - Firebase/CoreOnly (8.9.0): - - FirebaseCore (= 8.9.0) - - Firebase/Database (8.9.0): + - FirebaseAnalytics (~> 8.10.0) + - Firebase/CoreOnly (8.10.0): + - FirebaseCore (= 8.10.0) + - Firebase/Database (8.10.0): - Firebase/CoreOnly - - FirebaseDatabase (~> 8.9.0) - - Firebase/Storage (8.9.0): + - FirebaseDatabase (~> 8.10.0) + - Firebase/Storage (8.10.0): - Firebase/CoreOnly - - FirebaseStorage (~> 8.9.0) - - FirebaseAnalytics (8.9.0): - - FirebaseAnalytics/AdIdSupport (= 8.9.0) + - FirebaseStorage (~> 8.10.0) + - FirebaseAnalytics (8.10.0): + - FirebaseAnalytics/AdIdSupport (= 8.10.0) - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) @@ -23,55 +22,55 @@ PODS: - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAnalytics/AdIdSupport (8.9.0): + - FirebaseAnalytics/AdIdSupport (8.10.0): - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - - GoogleAppMeasurement (= 8.9.0) + - GoogleAppMeasurement (= 8.10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAuth (8.9.0): + - FirebaseAuth (8.10.0): - FirebaseCore (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/Environment (~> 7.6) - GTMSessionFetcher/Core (~> 1.5) - - FirebaseCore (8.9.0): + - FirebaseCore (8.10.0): - FirebaseCoreDiagnostics (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - - FirebaseCoreDiagnostics (8.9.0): + - FirebaseCoreDiagnostics (8.10.0): - GoogleDataTransport (~> 9.1) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - nanopb (~> 2.30908.0) - - FirebaseDatabase (8.9.0): + - FirebaseDatabase (8.10.0): - FirebaseCore (~> 8.0) - leveldb-library (~> 1.22) - - FirebaseInstallations (8.9.0): + - FirebaseInstallations (8.10.0): - FirebaseCore (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/UserDefaults (~> 7.6) - PromisesObjC (< 3.0, >= 1.2) - - FirebaseStorage (8.9.0): + - FirebaseStorage (8.10.0): - FirebaseCore (~> 8.0) - GTMSessionFetcher/Core (~> 1.5) - - GoogleAppMeasurement (8.9.0): - - GoogleAppMeasurement/AdIdSupport (= 8.9.0) + - GoogleAppMeasurement (8.10.0): + - GoogleAppMeasurement/AdIdSupport (= 8.10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.9.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.0) + - GoogleAppMeasurement/AdIdSupport (8.10.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.9.0): + - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) @@ -112,7 +111,6 @@ PODS: - SwipeableTabBarController (3.4.2) DEPENDENCIES: - - EasyNotificationBadge - Firebase/Auth - Firebase/Core - Firebase/Database @@ -122,7 +120,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - - EasyNotificationBadge - Firebase - FirebaseAnalytics - FirebaseAuth @@ -142,16 +139,15 @@ SPEC REPOS: - SwipeableTabBarController SPEC CHECKSUMS: - EasyNotificationBadge: a3ebbcb1de0c0558e102e954380c75801f352702 - Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95 - FirebaseAnalytics: 3a11ed901750e1ebcbe35e75915ff079878ea385 - FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b - FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b - FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 - FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc - FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85 - FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 - GoogleAppMeasurement: b54a857d347703d67c7a6f23713760c9bcfe9008 + Firebase: 44213362f1dcc52555b935dc925ed35ac55f1b20 + FirebaseAnalytics: 319c9b3b1bdd400d60e2f415dff0c5f6959e6760 + FirebaseAuth: 59a2d2b933b5b79e18fb1e6ad230c6abdaa73d26 + FirebaseCore: 04186597c095da37d90ff9fd3e53bc61a1ff2440 + FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18 + FirebaseDatabase: 5f3e83b0a0d8759378fbd5d05661244d14dfbbb0 + FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425 + FirebaseStorage: 815410224b548172c578f02554a86bbc8f817f50 + GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 @@ -161,6 +157,6 @@ SPEC CHECKSUMS: PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 SwipeableTabBarController: 9a218bdee9426d1bfe36d7962f852024bb08d61b -PODFILE CHECKSUM: e86f5144469dc5aa19b2281cf74b6d407d9d4397 +PODFILE CHECKSUM: fb210c43b30722ec9ba1eaf713b5c1e4fda3d02d COCOAPODS: 1.11.2 From 9bb56a64e03365d009ceff108c31a3b6d11b76a5 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 15 Dec 2021 22:14:20 +0300 Subject: [PATCH 21/28] remove dynamic --- DoIt.xcodeproj/project.pbxproj | 4 ---- DoIt/ViewModels/Dynamic.swift | 30 ------------------------------ 2 files changed, 34 deletions(-) delete mode 100644 DoIt/ViewModels/Dynamic.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index a4d5934..9e292a4 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -20,7 +20,6 @@ 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */; }; 83349BDB27681CC2008D4786 /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BD927681CC2008D4786 /* ImageService.swift */; }; 83349BDC27681CC2008D4786 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDA27681CC2008D4786 /* AuthService.swift */; }; - 83349BE027682D58008D4786 /* Dynamic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDF27682D58008D4786 /* Dynamic.swift */; }; 83349BE227682D72008D4786 /* TasksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE127682D72008D4786 /* TasksViewModel.swift */; }; 83349BE6276959F4008D4786 /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE5276959F4008D4786 /* AuthViewModel.swift */; }; 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; @@ -82,7 +81,6 @@ 7CAC5DDB27232C6300E2D70B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 83349BD927681CC2008D4786 /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; 83349BDA27681CC2008D4786 /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; - 83349BDF27682D58008D4786 /* Dynamic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dynamic.swift; sourceTree = ""; }; 83349BE127682D72008D4786 /* TasksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksViewModel.swift; sourceTree = ""; }; 83349BE5276959F4008D4786 /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = ""; }; 83369A3F273855BD0025F3D9 /* TasksController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksController.swift; sourceTree = ""; }; @@ -164,7 +162,6 @@ 7C6382CF2725C4F700FED2F4 /* ViewModels */ = { isa = PBXGroup; children = ( - 83349BDF27682D58008D4786 /* Dynamic.swift */, 83349BE5276959F4008D4786 /* AuthViewModel.swift */, 83349BE127682D72008D4786 /* TasksViewModel.swift */, E455B5D9276820E60059130D /* SearchUsersViewModel.swift */, @@ -566,7 +563,6 @@ E455B5DA276820E60059130D /* SearchUsersViewModel.swift in Sources */, 7C6C3BCA275C072E00B6101F /* FirebaseConstants.swift in Sources */, 8383503727583E58008847E1 /* SignInController.swift in Sources */, - 83349BE027682D58008D4786 /* Dynamic.swift in Sources */, 7C6382E62728807900FED2F4 /* UIColorsExtension.swift in Sources */, E4A95D5D275BEAAA00EE3F59 /* Profile.swift in Sources */, E4A95D5A275BEA8600EE3F59 /* ProfileViewController.swift in Sources */, diff --git a/DoIt/ViewModels/Dynamic.swift b/DoIt/ViewModels/Dynamic.swift deleted file mode 100644 index 078dd8e..0000000 --- a/DoIt/ViewModels/Dynamic.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Dynamic.swift -// DoIt -// -// Created by Данил Иванов on 14.12.2021. -// - -class Dynamic { - typealias Listener = (T) -> () - var listener: Listener? - - func bind(_ listener: Listener?) { - self.listener = listener - } - - func bindAndFire(_ listener: Listener?) { - self.listener = listener - listener?(value) - } - - var value: T { - didSet { - listener?(value) - } - } - - init(_ v: T) { - value = v - } -} From d1d5fcd18a4151e6f72df4610932f5bf549e2132 Mon Sep 17 00:00:00 2001 From: danil-ivanov Date: Wed, 15 Dec 2021 22:17:21 +0300 Subject: [PATCH 22/28] just something --- .../FeedCollectionViewCell.swift | 13 ++++++-- .../Profile/ProfileFollowingUserCell.swift | 8 ++++- DoIt/Views/SignIn/SignInController.swift | 1 - DoIt/Views/SignUp/SignUpController.swift | 33 +++++++++++++++++++ .../TasksTableView/TaskTableViewCell.swift | 8 ++++- 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift index 039b5cd..86a9f42 100644 --- a/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift +++ b/DoIt/Views/Feed/FeedCollectionView/FeedCollectionViewCell.swift @@ -77,10 +77,19 @@ class FeedCollectionViewCell: UICollectionViewCell { //MARK: - Public Methods func configureCell(taskInfo: Task, userInfo: UserModel) { - taskImage.image = taskInfo.image ?? UIImage.TaskIcons.defaultImage + var cellImage: UIImage? = nil + if let data = try? Data(contentsOf: taskInfo.image!) { + cellImage = UIImage(data: data) + } + taskImage.image = cellImage ?? UIImage.TaskIcons.defaultImage taskLabel.text = taskInfo.title creatorLabel.text = "@" + userInfo.username - guard let image = userInfo.image else { + + var userImage: UIImage? = nil + if let data = try? Data(contentsOf: userInfo.image!) { + userImage = UIImage(data: data) + } + guard let image = userImage else { creatorImage.layoutIfNeeded() creatorImage.setImageForName(userInfo.name ?? userInfo.username, circular: false, textAttributes: nil) return diff --git a/DoIt/Views/Profile/ProfileFollowingUserCell.swift b/DoIt/Views/Profile/ProfileFollowingUserCell.swift index 644fe11..3a25d8a 100644 --- a/DoIt/Views/Profile/ProfileFollowingUserCell.swift +++ b/DoIt/Views/Profile/ProfileFollowingUserCell.swift @@ -52,7 +52,13 @@ class ProfileFollowingUserCell: UICollectionViewCell { // MARK: - Helpers func configureCell(with: UserModel) { loginLabel.text = "@" + with.username - guard let image = with.image else { + + var cellImage: UIImage? = nil + if let data = try? Data(contentsOf: with.image!) { + cellImage = UIImage(data: data) + } + + guard let image = cellImage else { profileImageView.layoutIfNeeded() profileImageView.setImageForName(with.name ?? with.username, circular: false, textAttributes: nil) return diff --git a/DoIt/Views/SignIn/SignInController.swift b/DoIt/Views/SignIn/SignInController.swift index 126e54b..3fe93a2 100644 --- a/DoIt/Views/SignIn/SignInController.swift +++ b/DoIt/Views/SignIn/SignInController.swift @@ -55,7 +55,6 @@ class SignInController: UIViewController { @objc private func signInButtonPressed(_ sender: UIButton) { self.viewModel.signIn(email: usernameInputView.textField.text, password: passwordInputView.textField.text) - let tabbarController = CustomTabBarController() tabbarController.modalPresentationStyle = .fullScreen //present(tabbarController, animated: true) diff --git a/DoIt/Views/SignUp/SignUpController.swift b/DoIt/Views/SignUp/SignUpController.swift index 437d135..d6206f8 100644 --- a/DoIt/Views/SignUp/SignUpController.swift +++ b/DoIt/Views/SignUp/SignUpController.swift @@ -42,6 +42,39 @@ class SignUpController: UIViewController { super.viewDidLoad() + +//из старой версии, с попапом на будущее + +// let title = AuthStrings.signInSuccessful.rawValue.localized +// let message = AuthStrings.welcome.rawValue.localized +// +// lazy var popup : PopupDialog = { +// let pop = PopupDialog(title: title, message: message) +// let button = CancelButton(title: AuthStrings.invitation.rawValue.localized) { +// let profileView = ProfileController(email: email) +// self.present(profileView, animated: true, completion: nil) +// } +// pop.addButton(button) +// return pop +// }() +// +// self.present(popup, animated: true, completion: nil) +// case .failure(let error): +// +// let title = AuthStrings.signInUnsuccessful.rawValue.localized +// let message = error.localizedDescription +// +// lazy var popup : PopupDialog = { +// let pop = PopupDialog(title: title, message: message) +// let button = CancelButton(title: AuthStrings.accept.rawValue.localized) {} +// pop.addButton(button) +// return pop +// }() + + //self.present(popup, animated: true, completion: nil) + + + viewModel.authResultModel.bind { authResult in switch authResult { case .success: diff --git a/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift b/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift index 6ebf4b2..9205bdc 100644 --- a/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift +++ b/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift @@ -66,7 +66,13 @@ class TaskTableViewCell: UITableViewCell { func configureCell(taskInfo: Task) { chapterIndicator.backgroundColor = taskInfo.color taskInfo.isDone ? checkBox.setImage(.TaskIcons.done, for: .normal) : checkBox.setImage(.TaskIcons.notDone, for: .normal) - image.image = taskInfo.image ?? .TaskIcons.defaultImage + + var cellImage: UIImage? = nil + if let data = try? Data(contentsOf: taskInfo.image!) { + cellImage = UIImage(data: data) + } + + image.image = cellImage ?? .TaskIcons.defaultImage title.text = taskInfo.title taskDescription.text = taskInfo.description ?? TaskString.description.rawValue.localized divider.backgroundColor = taskInfo.color From eb2ea8896865d1b09a07e819b34ba795a1cd28cb Mon Sep 17 00:00:00 2001 From: danil-ivanov Date: Wed, 15 Dec 2021 23:25:18 +0300 Subject: [PATCH 23/28] Sign In Up works --- DoIt/ViewModels/AuthViewModel.swift | 9 ++------- DoIt/ViewModels/TasksViewModel.swift | 15 +++++++++++++++ DoIt/Views/SignIn/SignInController.swift | 22 ++++++++++++++++++---- DoIt/Views/SignUp/SignUpController.swift | 8 ++++---- DoIt/Views/Tasks/TasksController.swift | 4 +--- 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/DoIt/ViewModels/AuthViewModel.swift b/DoIt/ViewModels/AuthViewModel.swift index 0d9a154..e8bfae7 100644 --- a/DoIt/ViewModels/AuthViewModel.swift +++ b/DoIt/ViewModels/AuthViewModel.swift @@ -19,13 +19,8 @@ final class AuthViewModel { } func signIn(email: String?, password: String?) { - self.authService.signIn(email: email, password: password) { authResult in - switch authResult { - case .success: - print("Auth success") - case .failure(let error): - print("Auth was failured: ", error.localizedDescription) - } + self.authService.signIn(email: email, password: password) { [weak self] authResult in + self?.authResultModel.value = authResult } } } diff --git a/DoIt/ViewModels/TasksViewModel.swift b/DoIt/ViewModels/TasksViewModel.swift index 5be4b10..f6a6286 100644 --- a/DoIt/ViewModels/TasksViewModel.swift +++ b/DoIt/ViewModels/TasksViewModel.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit final class TasksViewModel { private let taskService = TaskService.shared @@ -36,4 +37,18 @@ final class TasksViewModel { } } } + + func downloadImage(_ url: URL?, completion: @escaping (UIImage?) -> ()) { + DispatchQueue.global().async { + var cellImage: UIImage? = nil + guard let url = url else { + completion(cellImage) + return + } + if let data = try? Data(contentsOf: url) { + cellImage = UIImage(data: data) + } + completion(cellImage) + } + } } diff --git a/DoIt/Views/SignIn/SignInController.swift b/DoIt/Views/SignIn/SignInController.swift index 3fe93a2..2c6684e 100644 --- a/DoIt/Views/SignIn/SignInController.swift +++ b/DoIt/Views/SignIn/SignInController.swift @@ -30,6 +30,18 @@ class SignInController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + + viewModel.authResultModel.bind { [weak self] authResult in + switch authResult { + case .success: + print("SignIn successed") + self?.presentTabBar() + case .failure(let error): + print("SignIn was failured: ", error.localizedDescription) + case .none: + return + } + } configureView() } @@ -53,12 +65,14 @@ class SignInController: UIViewController { stack.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true } - @objc private func signInButtonPressed(_ sender: UIButton) { - self.viewModel.signIn(email: usernameInputView.textField.text, password: passwordInputView.textField.text) + private func presentTabBar() { let tabbarController = CustomTabBarController() tabbarController.modalPresentationStyle = .fullScreen - //present(tabbarController, animated: true) - + present(tabbarController, animated: true) + } + + @objc private func signInButtonPressed(_ sender: UIButton) { + self.viewModel.signIn(email: usernameInputView.textField.text, password: passwordInputView.textField.text) } @objc private func signUpButtonPressed(_ sender: UIButton) { diff --git a/DoIt/Views/SignUp/SignUpController.swift b/DoIt/Views/SignUp/SignUpController.swift index d6206f8..f605a58 100644 --- a/DoIt/Views/SignUp/SignUpController.swift +++ b/DoIt/Views/SignUp/SignUpController.swift @@ -70,17 +70,17 @@ class SignUpController: UIViewController { // pop.addButton(button) // return pop // }() - //self.present(popup, animated: true, completion: nil) - viewModel.authResultModel.bind { authResult in + viewModel.authResultModel.bind { [weak self] authResult in switch authResult { case .success: - print("auth successed") + print("SignUp successed") + self?.presentOnboarding() case .failure(let error): - print("Auth was failured: ", error.localizedDescription) + print("SignUp was failured: ", error.localizedDescription) case .none: return } diff --git a/DoIt/Views/Tasks/TasksController.swift b/DoIt/Views/Tasks/TasksController.swift index dcc7c29..9f8959d 100644 --- a/DoIt/Views/Tasks/TasksController.swift +++ b/DoIt/Views/Tasks/TasksController.swift @@ -57,9 +57,7 @@ class TasksController: UIViewController { //костыль private lazy var tasks: [Task] = { - return [Task(image: nil, title: "", description: nil, deadline: nil, isDone: false, color: .black), - Task(image: nil, title: "", description: nil, deadline: nil, isDone: false, color: .black), - Task(image: nil, title: "", description: nil, deadline: nil, isDone: false, color: .black)] + return [Task(id: "", dictionary: [:])] }() private var selectedTasks: [Task]? { From a53cb329f3e226f8c403037fd6c5dc4d6f2f4608 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 15 Dec 2021 23:38:07 +0300 Subject: [PATCH 24/28] remove useless and image cacher --- DoIt.xcodeproj/project.pbxproj | 22 +++++++------------ DoIt/Models/ImageChacher.swift | 40 ++++++++++++++++++++++++++++++++++ DoIt/Models/ImageService.swift | 1 - 3 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 DoIt/Models/ImageChacher.swift delete mode 100644 DoIt/Models/ImageService.swift diff --git a/DoIt.xcodeproj/project.pbxproj b/DoIt.xcodeproj/project.pbxproj index 9e292a4..e7e5c7f 100644 --- a/DoIt.xcodeproj/project.pbxproj +++ b/DoIt.xcodeproj/project.pbxproj @@ -18,8 +18,6 @@ 7C6C3BCC275C176C00B6101F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */; }; 7CAC5DCE27232C6000E2D70B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */; }; 7CAC5DD027232C6000E2D70B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */; }; - 83349BDB27681CC2008D4786 /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BD927681CC2008D4786 /* ImageService.swift */; }; - 83349BDC27681CC2008D4786 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BDA27681CC2008D4786 /* AuthService.swift */; }; 83349BE227682D72008D4786 /* TasksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE127682D72008D4786 /* TasksViewModel.swift */; }; 83349BE6276959F4008D4786 /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83349BE5276959F4008D4786 /* AuthViewModel.swift */; }; 83369A40273855BD0025F3D9 /* TasksController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83369A3F273855BD0025F3D9 /* TasksController.swift */; }; @@ -58,6 +56,7 @@ E4A95D5A275BEA8600EE3F59 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D57275BEA8500EE3F59 /* ProfileViewController.swift */; }; E4A95D5B275BEA8600EE3F59 /* ProfileFollowingUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D58275BEA8500EE3F59 /* ProfileFollowingUserCell.swift */; }; E4A95D5D275BEAAA00EE3F59 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A95D5C275BEAAA00EE3F59 /* Profile.swift */; }; + E4AB3EF7276A89490038D8AD /* ImageChacher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4AB3EF6276A89490038D8AD /* ImageChacher.swift */; }; E4BC75FE276537E40016B6E2 /* NotificationNameExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BC75FD276537E40016B6E2 /* NotificationNameExtension.swift */; }; /* End PBXBuildFile section */ @@ -74,13 +73,10 @@ 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthResultsModel.swift; sourceTree = ""; }; 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseConstants.swift; sourceTree = ""; }; 7C6C3BCB275C176C00B6101F /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 7C6C3BCD275CFE4700B6101F /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; 7CAC5DCA27232C6000E2D70B /* DoIt.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DoIt.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7CAC5DCD27232C6000E2D70B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7CAC5DCF27232C6000E2D70B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7CAC5DDB27232C6300E2D70B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 83349BD927681CC2008D4786 /* ImageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; - 83349BDA27681CC2008D4786 /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; 83349BE127682D72008D4786 /* TasksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksViewModel.swift; sourceTree = ""; }; 83349BE5276959F4008D4786 /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = ""; }; 83369A3F273855BD0025F3D9 /* TasksController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TasksController.swift; sourceTree = ""; }; @@ -119,6 +115,7 @@ E4A95D57275BEA8500EE3F59 /* ProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; E4A95D58275BEA8500EE3F59 /* ProfileFollowingUserCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileFollowingUserCell.swift; sourceTree = ""; }; E4A95D5C275BEAAA00EE3F59 /* Profile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Profile.swift; sourceTree = ""; }; + E4AB3EF6276A89490038D8AD /* ImageChacher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageChacher.swift; sourceTree = ""; }; E4BC75FD276537E40016B6E2 /* NotificationNameExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationNameExtension.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -200,18 +197,16 @@ 7C6382D52725C5E800FED2F4 /* Models */ = { isa = PBXGroup; children = ( - 83349BDA27681CC2008D4786 /* AuthService.swift */, - 83349BD927681CC2008D4786 /* ImageService.swift */, - E455B5D527681AD10059130D /* AuthService.swift */, - E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */, + 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */, E4A95D48275BE99900EE3F59 /* UserModel.swift */, E49D6B1F275BEF0C007C9A97 /* UserTasksModel.swift */, + E4A95D4A275BE99A00EE3F59 /* UserFollowingModel.swift */, 83369A4D273857020025F3D9 /* TaskModel.swift */, + E455B5D527681AD10059130D /* AuthService.swift */, 7C6C3BC3275C05E000B6101F /* UserService.swift */, - 7C6C3BC7275C06B400B6101F /* AuthResultsModel.swift */, - 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, - 7C6C3BCD275CFE4700B6101F /* UserModel.swift */, E417CFD827689D8A00C6E6B5 /* TaskService.swift */, + 7C6C3BC9275C072E00B6101F /* FirebaseConstants.swift */, + E4AB3EF6276A89490038D8AD /* ImageChacher.swift */, ); path = Models; sourceTree = ""; @@ -541,7 +536,6 @@ E455B5D727681AD20059130D /* AuthService.swift in Sources */, E417CFD927689D8A00C6E6B5 /* TaskService.swift in Sources */, 83369A4A273856950025F3D9 /* ChapterCollectionCell.swift in Sources */, - 83349BDC27681CC2008D4786 /* AuthService.swift in Sources */, 8383504027583E58008847E1 /* SearchUsersCell.swift in Sources */, E49D6B20275BEF0C007C9A97 /* UserTasksModel.swift in Sources */, E4A95D59275BEA8500EE3F59 /* ProfileEditViewController.swift in Sources */, @@ -575,8 +569,8 @@ 8383503627583E58008847E1 /* CustomNavigationController.swift in Sources */, 8383503527583E58008847E1 /* Auth.swift in Sources */, 7C6C3BC4275C05E000B6101F /* UserService.swift in Sources */, + E4AB3EF7276A89490038D8AD /* ImageChacher.swift in Sources */, 8383503C27583E58008847E1 /* TaskEditViewController.swift in Sources */, - 83349BDB27681CC2008D4786 /* ImageService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DoIt/Models/ImageChacher.swift b/DoIt/Models/ImageChacher.swift new file mode 100644 index 0000000..6c5930c --- /dev/null +++ b/DoIt/Models/ImageChacher.swift @@ -0,0 +1,40 @@ +// +// ImageChacher.swift +// DoIt +// +// Created by Шестаков Никита on 15.12.2021. +// + +import Foundation +import UIKit + +class ImageCache { + private let cache = NSCache() + private var observer: NSObjectProtocol? + + static let shared = ImageCache() + + private init() { + observer = NotificationCenter.default.addObserver( + forName: UIApplication.didReceiveMemoryWarningNotification, + object: nil, queue: nil) { [weak self] notification in + self?.cache.removeAllObjects() + } + } + + deinit { + guard let observer = observer else { + return + } + + NotificationCenter.default.removeObserver(observer) + } + + func getImage(forKey key: String) -> UIImage? { + return cache.object(forKey: key as NSString) + } + + func save(image: UIImage, forKey key: String) { + cache.setObject(image, forKey: key as NSString) + } +} diff --git a/DoIt/Models/ImageService.swift b/DoIt/Models/ImageService.swift deleted file mode 100644 index 8b13789..0000000 --- a/DoIt/Models/ImageService.swift +++ /dev/null @@ -1 +0,0 @@ - From e0adef029f7e1caeb0cdb236e4d2a735562039f9 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 15 Dec 2021 23:48:34 +0300 Subject: [PATCH 25/28] add user name --- DoIt/Models/UserModel.swift | 2 +- DoIt/Models/UserService.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index b0a3bef..dd126b8 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -28,7 +28,7 @@ class UserModel { self.email = dictionary["email"] as? String ?? "" self.username = dictionary["username"] as? String ?? "" self.summary = dictionary["summary"] as? String - self.name = nil + self.name = dictionary["name"] as? String if let profileImageUrlString = dictionary["userPhotoUrl"] as? String { self.image = URL(string: profileImageUrlString) } diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index 077eca2..50a3007 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -40,7 +40,7 @@ class UserService { func updateUserData(user: UserModel, completion: @escaping(DatabaseCompletion)){ guard let uid = Auth.auth().currentUser?.uid else {return} - let values = ["username": user.username, "summary": user.summary ?? ""] + let values = ["username": user.username, "summary": user.summary ?? "", "name": user.name ?? ""] REF_USERS.child(uid).updateChildValues(values, withCompletionBlock: completion) } From 1f7b7b8537c80f5e878233a2933463fa04b67cf2 Mon Sep 17 00:00:00 2001 From: Yulia Date: Thu, 16 Dec 2021 00:15:41 +0300 Subject: [PATCH 26/28] hotfix --- DoIt/Models/TaskModel.swift | 2 +- DoIt/Models/TaskService.swift | 7 ++-- DoIt/Models/UserService.swift | 6 ++-- Podfile.lock | 68 +++++++++++++++++------------------ 4 files changed, 40 insertions(+), 43 deletions(-) diff --git a/DoIt/Models/TaskModel.swift b/DoIt/Models/TaskModel.swift index ae82245..66b8db3 100644 --- a/DoIt/Models/TaskModel.swift +++ b/DoIt/Models/TaskModel.swift @@ -32,7 +32,7 @@ final class Task { image = nil } title = dictionary["title"] as? String ?? "" - description = dictionary["description"] as? String + description = dictionary["description"] as? String ?? "" if let deadlineTimestamp = dictionary["deadline"] as? Double { deadline = Date(timeIntervalSince1970: deadlineTimestamp) } else { diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift index d6565a6..4b14fd8 100644 --- a/DoIt/Models/TaskService.swift +++ b/DoIt/Models/TaskService.swift @@ -21,10 +21,7 @@ class TaskService { "is_done": task.isDone, "uid": uid, "timestamp": Int(NSDate().timeIntervalSince1970), - "color": [task.color.cgColor.components?[0], - task.color.cgColor.components?[1], - task.color.cgColor.components?[2] - ] + "color": UIColor().HexFromColor(color: task.color) ] as [String : Any] REF_TASKS.childByAutoId().updateChildValues(values) { (error, ref) in @@ -71,8 +68,8 @@ class TaskService { self.fetchTask(taskId: taskId) { task in tasks.append(task) - completion(tasks) } } + completion(tasks) } } diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index 50a3007..467b98e 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -52,8 +52,8 @@ class UserService { guard let dictionary = snapshot.value as? [String: AnyObject] else {return} let user = UserModel(uid: uid, dictionary: dictionary) users.append(user) - completion(users) } + completion(users) } func followUser(uid: String, completion: @escaping(DatabaseCompletion)){ @@ -85,8 +85,8 @@ class UserService { let follower_uid = snapshot.key users_uid.append(follower_uid) - completion(users_uid) } + completion(users_uid) } func fetchUserFollowing(uid: String, completion: @escaping([String])->Void) { @@ -95,8 +95,8 @@ class UserService { let following_uid = snapshot.key users_uid.append(following_uid) - completion(users_uid) } + completion(users_uid) } } diff --git a/Podfile.lock b/Podfile.lock index e69f803..f1f3f3e 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,20 +1,20 @@ PODS: - - Firebase/Auth (8.10.0): + - Firebase/Auth (8.9.0): - Firebase/CoreOnly - - FirebaseAuth (~> 8.10.0) - - Firebase/Core (8.10.0): + - FirebaseAuth (~> 8.9.0) + - Firebase/Core (8.9.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 8.10.0) - - Firebase/CoreOnly (8.10.0): - - FirebaseCore (= 8.10.0) - - Firebase/Database (8.10.0): + - FirebaseAnalytics (~> 8.9.0) + - Firebase/CoreOnly (8.9.0): + - FirebaseCore (= 8.9.0) + - Firebase/Database (8.9.0): - Firebase/CoreOnly - - FirebaseDatabase (~> 8.10.0) - - Firebase/Storage (8.10.0): + - FirebaseDatabase (~> 8.9.0) + - Firebase/Storage (8.9.0): - Firebase/CoreOnly - - FirebaseStorage (~> 8.10.0) - - FirebaseAnalytics (8.10.0): - - FirebaseAnalytics/AdIdSupport (= 8.10.0) + - FirebaseStorage (~> 8.9.0) + - FirebaseAnalytics (8.9.0): + - FirebaseAnalytics/AdIdSupport (= 8.9.0) - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) @@ -22,55 +22,55 @@ PODS: - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAnalytics/AdIdSupport (8.10.0): + - FirebaseAnalytics/AdIdSupport (8.9.0): - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - - GoogleAppMeasurement (= 8.10.0) + - GoogleAppMeasurement (= 8.9.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAuth (8.10.0): + - FirebaseAuth (8.9.0): - FirebaseCore (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/Environment (~> 7.6) - GTMSessionFetcher/Core (~> 1.5) - - FirebaseCore (8.10.0): + - FirebaseCore (8.9.0): - FirebaseCoreDiagnostics (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - - FirebaseCoreDiagnostics (8.10.0): + - FirebaseCoreDiagnostics (8.9.0): - GoogleDataTransport (~> 9.1) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - nanopb (~> 2.30908.0) - - FirebaseDatabase (8.10.0): + - FirebaseDatabase (8.9.0): - FirebaseCore (~> 8.0) - leveldb-library (~> 1.22) - - FirebaseInstallations (8.10.0): + - FirebaseInstallations (8.9.0): - FirebaseCore (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/UserDefaults (~> 7.6) - PromisesObjC (< 3.0, >= 1.2) - - FirebaseStorage (8.10.0): + - FirebaseStorage (8.9.0): - FirebaseCore (~> 8.0) - GTMSessionFetcher/Core (~> 1.5) - - GoogleAppMeasurement (8.10.0): - - GoogleAppMeasurement/AdIdSupport (= 8.10.0) + - GoogleAppMeasurement (8.9.0): + - GoogleAppMeasurement/AdIdSupport (= 8.9.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.10.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) + - GoogleAppMeasurement/AdIdSupport (8.9.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): + - GoogleAppMeasurement/WithoutAdIdSupport (8.9.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) @@ -139,15 +139,15 @@ SPEC REPOS: - SwipeableTabBarController SPEC CHECKSUMS: - Firebase: 44213362f1dcc52555b935dc925ed35ac55f1b20 - FirebaseAnalytics: 319c9b3b1bdd400d60e2f415dff0c5f6959e6760 - FirebaseAuth: 59a2d2b933b5b79e18fb1e6ad230c6abdaa73d26 - FirebaseCore: 04186597c095da37d90ff9fd3e53bc61a1ff2440 - FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18 - FirebaseDatabase: 5f3e83b0a0d8759378fbd5d05661244d14dfbbb0 - FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425 - FirebaseStorage: 815410224b548172c578f02554a86bbc8f817f50 - GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 + Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95 + FirebaseAnalytics: 3a11ed901750e1ebcbe35e75915ff079878ea385 + FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b + FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b + FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 + FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc + FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85 + FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 + GoogleAppMeasurement: b54a857d347703d67c7a6f23713760c9bcfe9008 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 From b8fe2e6083df05a167992a906bb452a7e145a96c Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 16 Dec 2021 01:17:46 +0300 Subject: [PATCH 27/28] fb fix --- DoIt/Models/AuthService.swift | 3 +- DoIt/Models/TaskService.swift | 8 --- DoIt/Models/UserService.swift | 6 +- .../TasksTableView/TaskTableViewCell.swift | 6 +- GoogleService-Info.plist | 2 + Podfile.lock | 68 +++++++++---------- 6 files changed, 44 insertions(+), 49 deletions(-) diff --git a/DoIt/Models/AuthService.swift b/DoIt/Models/AuthService.swift index 47605f9..eaec2d9 100644 --- a/DoIt/Models/AuthService.swift +++ b/DoIt/Models/AuthService.swift @@ -50,7 +50,8 @@ class AuthService { let values = ["email": email, "username": username] - let usersReferense = Database.database().reference().child("users").child(uid) + + let usersReferense = Database.database().reference().child("users") usersReferense.child(uid).updateChildValues(values) completion(.success) } diff --git a/DoIt/Models/TaskService.swift b/DoIt/Models/TaskService.swift index 4b14fd8..98085b7 100644 --- a/DoIt/Models/TaskService.swift +++ b/DoIt/Models/TaskService.swift @@ -49,14 +49,6 @@ class TaskService { func fetchTask(taskId: String, completion: @escaping(Task) -> Void){ REF_TASKS.child(taskId).observeSingleEvent(of: .value) { snapshot in guard let dictionary = snapshot.value as? [String: AnyObject] else {return} -// guard let uid = dictionary["uid"] as? String else {return} -// guard let image = dictionary["image"] as? String else { return } -// guard let title = dictionary["title"] as? String else { return } -// guard let description = dictionary["description"] as? String else { return } -// guard let deadline = dictionary["deadline"] as? Int else { return } -// guard let isDone = dictionary["is_done"] as? Bool else { return } -// guard let color = dictionary["color"] as? [Int] else { return } - completion(Task(id: taskId, dictionary: dictionary)) } } diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index 467b98e..50a3007 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -52,8 +52,8 @@ class UserService { guard let dictionary = snapshot.value as? [String: AnyObject] else {return} let user = UserModel(uid: uid, dictionary: dictionary) users.append(user) + completion(users) } - completion(users) } func followUser(uid: String, completion: @escaping(DatabaseCompletion)){ @@ -85,8 +85,8 @@ class UserService { let follower_uid = snapshot.key users_uid.append(follower_uid) + completion(users_uid) } - completion(users_uid) } func fetchUserFollowing(uid: String, completion: @escaping([String])->Void) { @@ -95,8 +95,8 @@ class UserService { let following_uid = snapshot.key users_uid.append(following_uid) + completion(users_uid) } - completion(users_uid) } } diff --git a/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift b/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift index d5d8cbc..9767880 100644 --- a/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift +++ b/DoIt/Views/Tasks/TasksTableView/TaskTableViewCell.swift @@ -68,9 +68,9 @@ class TaskTableViewCell: UITableViewCell { taskInfo.isDone ? checkBox.setImage(.TaskIcons.done, for: .normal) : checkBox.setImage(.TaskIcons.notDone, for: .normal) var cellImage: UIImage? = nil - if let data = try? Data(contentsOf: taskInfo.image!) { - cellImage = UIImage(data: data) - } +// if let data = try? Data(contentsOf: taskInfo.image!) { +// cellImage = UIImage(data: data) +// } image.image = cellImage ?? .TaskIcons.defaultImage diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist index 8a0748e..ab71a05 100644 --- a/GoogleService-Info.plist +++ b/GoogleService-Info.plist @@ -30,5 +30,7 @@ GOOGLE_APP_ID 1:602688246846:ios:ac3f4f04a7c992f0e22d6f + DATABASE_URL + https://doit-d4f58-default-rtdb.europe-west1.firebasedatabase.app \ No newline at end of file diff --git a/Podfile.lock b/Podfile.lock index f1f3f3e..e69f803 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,20 +1,20 @@ PODS: - - Firebase/Auth (8.9.0): + - Firebase/Auth (8.10.0): - Firebase/CoreOnly - - FirebaseAuth (~> 8.9.0) - - Firebase/Core (8.9.0): + - FirebaseAuth (~> 8.10.0) + - Firebase/Core (8.10.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 8.9.0) - - Firebase/CoreOnly (8.9.0): - - FirebaseCore (= 8.9.0) - - Firebase/Database (8.9.0): + - FirebaseAnalytics (~> 8.10.0) + - Firebase/CoreOnly (8.10.0): + - FirebaseCore (= 8.10.0) + - Firebase/Database (8.10.0): - Firebase/CoreOnly - - FirebaseDatabase (~> 8.9.0) - - Firebase/Storage (8.9.0): + - FirebaseDatabase (~> 8.10.0) + - Firebase/Storage (8.10.0): - Firebase/CoreOnly - - FirebaseStorage (~> 8.9.0) - - FirebaseAnalytics (8.9.0): - - FirebaseAnalytics/AdIdSupport (= 8.9.0) + - FirebaseStorage (~> 8.10.0) + - FirebaseAnalytics (8.10.0): + - FirebaseAnalytics/AdIdSupport (= 8.10.0) - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) @@ -22,55 +22,55 @@ PODS: - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAnalytics/AdIdSupport (8.9.0): + - FirebaseAnalytics/AdIdSupport (8.10.0): - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - - GoogleAppMeasurement (= 8.9.0) + - GoogleAppMeasurement (= 8.10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - FirebaseAuth (8.9.0): + - FirebaseAuth (8.10.0): - FirebaseCore (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/Environment (~> 7.6) - GTMSessionFetcher/Core (~> 1.5) - - FirebaseCore (8.9.0): + - FirebaseCore (8.10.0): - FirebaseCoreDiagnostics (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - - FirebaseCoreDiagnostics (8.9.0): + - FirebaseCoreDiagnostics (8.10.0): - GoogleDataTransport (~> 9.1) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/Logger (~> 7.6) - nanopb (~> 2.30908.0) - - FirebaseDatabase (8.9.0): + - FirebaseDatabase (8.10.0): - FirebaseCore (~> 8.0) - leveldb-library (~> 1.22) - - FirebaseInstallations (8.9.0): + - FirebaseInstallations (8.10.0): - FirebaseCore (~> 8.0) - GoogleUtilities/Environment (~> 7.6) - GoogleUtilities/UserDefaults (~> 7.6) - PromisesObjC (< 3.0, >= 1.2) - - FirebaseStorage (8.9.0): + - FirebaseStorage (8.10.0): - FirebaseCore (~> 8.0) - GTMSessionFetcher/Core (~> 1.5) - - GoogleAppMeasurement (8.9.0): - - GoogleAppMeasurement/AdIdSupport (= 8.9.0) + - GoogleAppMeasurement (8.10.0): + - GoogleAppMeasurement/AdIdSupport (= 8.10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.9.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.0) + - GoogleAppMeasurement/AdIdSupport (8.10.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) - "GoogleUtilities/NSData+zlib (~> 7.6)" - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.9.0): + - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - GoogleUtilities/MethodSwizzler (~> 7.6) - GoogleUtilities/Network (~> 7.6) @@ -139,15 +139,15 @@ SPEC REPOS: - SwipeableTabBarController SPEC CHECKSUMS: - Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95 - FirebaseAnalytics: 3a11ed901750e1ebcbe35e75915ff079878ea385 - FirebaseAuth: 2b78b2a32c07b3ecfa4970bdf1d3632b8304099b - FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b - FirebaseCoreDiagnostics: 5daa63f1c1409d981a2d5007daa100b36eac6a34 - FirebaseDatabase: 2236b804cf0cac165b4620669bedf7ee643a2bcc - FirebaseInstallations: caa7c8e0d3e2345b8829d2fa9ca1b4dfbf2fcc85 - FirebaseStorage: 452c98c31ccb40b819764bf3039426c4388d9939 - GoogleAppMeasurement: b54a857d347703d67c7a6f23713760c9bcfe9008 + Firebase: 44213362f1dcc52555b935dc925ed35ac55f1b20 + FirebaseAnalytics: 319c9b3b1bdd400d60e2f415dff0c5f6959e6760 + FirebaseAuth: 59a2d2b933b5b79e18fb1e6ad230c6abdaa73d26 + FirebaseCore: 04186597c095da37d90ff9fd3e53bc61a1ff2440 + FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18 + FirebaseDatabase: 5f3e83b0a0d8759378fbd5d05661244d14dfbbb0 + FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425 + FirebaseStorage: 815410224b548172c578f02554a86bbc8f817f50 + GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 From b6b4dce39a4432dd1404a871a1c976103354cc59 Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 16 Dec 2021 03:55:05 +0300 Subject: [PATCH 28/28] profile edit network --- DoIt/Models/AuthService.swift | 4 +- DoIt/Models/UserModel.swift | 31 +++++----- DoIt/Models/UserService.swift | 5 +- DoIt/ViewModels/ProfileEditViewModel.swift | 58 ++++++++++++------- DoIt/ViewModels/ProfileViewModel.swift | 24 ++++++-- DoIt/ViewModels/SearchUsersViewModel.swift | 12 ++-- DoIt/Views/Custom Views/Auth.swift | 4 +- .../Custom Views/CustomTabBarController.swift | 5 -- .../Profile/ProfileEditViewController.swift | 9 ++- .../Views/Profile/ProfileViewController.swift | 1 + .../Search Users/SearchUsersController.swift | 3 + 11 files changed, 94 insertions(+), 62 deletions(-) diff --git a/DoIt/Models/AuthService.swift b/DoIt/Models/AuthService.swift index eaec2d9..047d382 100644 --- a/DoIt/Models/AuthService.swift +++ b/DoIt/Models/AuthService.swift @@ -7,7 +7,7 @@ import Firebase -class AuthService { +final class AuthService { static let shared = AuthService() @@ -31,7 +31,7 @@ class AuthService { } } - public func signUp(email: String?, username: String?, password: String?, completion: @escaping (AuthResult) -> Void) { + func signUp(email: String?, username: String?, password: String?, completion: @escaping (AuthResult) -> Void) { guard let email = email, let username = username, let password = password else { completion(.failure(AuthError.unknownError)) diff --git a/DoIt/Models/UserModel.swift b/DoIt/Models/UserModel.swift index dd126b8..97346ea 100644 --- a/DoIt/Models/UserModel.swift +++ b/DoIt/Models/UserModel.swift @@ -13,9 +13,9 @@ class UserModel { let uid: String let email: String var username: String - var summary: String? + var summary: String? = nil var image: URL? - let name: String? + var name: String? = nil var isCurrentUser: Bool { return Auth.auth().currentUser?.uid == uid @@ -27,21 +27,20 @@ class UserModel { self.uid = uid self.email = dictionary["email"] as? String ?? "" self.username = dictionary["username"] as? String ?? "" - self.summary = dictionary["summary"] as? String - self.name = dictionary["name"] as? String + if let summary = dictionary["summary"] as? String { + if !summary.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + self.summary = summary + } + } + if let name = dictionary["name"] as? String { + if !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + self.name = name + } + } if let profileImageUrlString = dictionary["userPhotoUrl"] as? String { - self.image = URL(string: profileImageUrlString) + if !profileImageUrlString.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + self.image = URL(string: profileImageUrlString) + } } } - - // TODO: - FIX IT - - init(uid: String, email: String, username: String, summary: String?, imageURL: URL?, name: String?) { - self.uid = uid - self.email = email - self.username = username - self.summary = summary - self.image = imageURL - self.name = name - } } diff --git a/DoIt/Models/UserService.swift b/DoIt/Models/UserService.swift index 50a3007..4c356d4 100644 --- a/DoIt/Models/UserService.swift +++ b/DoIt/Models/UserService.swift @@ -40,7 +40,7 @@ class UserService { func updateUserData(user: UserModel, completion: @escaping(DatabaseCompletion)){ guard let uid = Auth.auth().currentUser?.uid else {return} - let values = ["username": user.username, "summary": user.summary ?? "", "name": user.name ?? ""] + let values: [String: Any] = ["username": user.username, "summary": user.summary ?? "", "name": user.name ?? "", "userPhotoUrl": user.image?.absoluteString ?? ""] REF_USERS.child(uid).updateChildValues(values, withCompletionBlock: completion) } @@ -75,7 +75,8 @@ class UserService { func isUserFollowed(uid: String, completion: @escaping(Bool)->Void){ guard let currentUid = Auth.auth().currentUser?.uid else {return} - REF_USER_FOLLOWING.child(currentUid).child(uid).observeSingleEvent(of: .value) { snapshot in completion(snapshot.exists()) + REF_USER_FOLLOWING.child(currentUid).child(uid).observeSingleEvent(of: .value) { snapshot in + completion(snapshot.exists()) } } diff --git a/DoIt/ViewModels/ProfileEditViewModel.swift b/DoIt/ViewModels/ProfileEditViewModel.swift index a777217..41c0cb8 100644 --- a/DoIt/ViewModels/ProfileEditViewModel.swift +++ b/DoIt/ViewModels/ProfileEditViewModel.swift @@ -12,54 +12,59 @@ final class ProfileEditViewModel { private let userService = UserService.shared var userModel: Observable = Observable() - func updateUserProfile(image: UIImage?, name: String?, username: String, summary: String?, complition: @escaping () -> ()) { + func updateUserProfile(image: UIImage?, name: String?, username: String?, summary: String?, complition: @escaping () -> ()) { DispatchQueue.global().sync { [weak self] in guard let userModel = userModel.value else { + Logger.log("Пользователь не найден") complition() return } + var wasChanged = false - var newImageURL: URL? = nil - if let image = image { - userService.updateUserPhoto(image: image) { url in - newImageURL = url - } - guard newImageURL != nil else { - complition() - return - } - wasChanged = true - } + wasChanged = image != nil var newName = userModel.name - if let name = name, name != newName { + if let name = name?.trimmingCharacters(in: .whitespacesAndNewlines), name != newName { newName = name wasChanged = true } var newSummary = userModel.summary - if let summary = summary, summary != newSummary { + if let summary = summary?.trimmingCharacters(in: .whitespacesAndNewlines), summary != newSummary { newSummary = summary + wasChanged = true } - if username != userModel.username { + var newUsername = userModel.username + if let username = username?.trimmingCharacters(in: .whitespacesAndNewlines), username != newUsername, !username.isEmpty { + newUsername = username wasChanged = true } guard wasChanged else { + Logger.log("Ничего не поменялось") complition() return } - let newUserModel = UserModel(uid: userModel.uid, email: userModel.email, username: username, summary: newSummary, imageURL: newImageURL, name: newName) + var values: [String: String] = ["email": userModel.email, "username": newUsername, "summary": newSummary ?? "", "name": newName ?? ""] - self?.userService.updateUserData(user: newUserModel, completion: { error, _ in - if error != nil { - + if let image = image { + self?.userService.updateUserPhoto(image: image) { [weak self] url in + guard url != nil else { + Logger.log("Ошибка обновления изображения") + complition() + return + } + values["userPhotoUrl"] = url?.absoluteString ?? "" + self?.userModel.value = UserModel(uid: userModel.uid, dictionary: values as [String: AnyObject]) + self?.updateUser(complition: complition) } - complition() - }) + } else { + self?.userModel.value = UserModel(uid: userModel.uid, dictionary: values as [String: AnyObject]) + self?.updateUser(complition: complition) + } } } @@ -76,4 +81,15 @@ final class ProfileEditViewModel { completion(cellImage) } } + + func updateUser(complition: @escaping () -> ()) { + guard let userModel = userModel.value else { return } + userService.updateUserData(user: userModel, completion: { error, _ in + if let error = error { + Logger.log("Ошибка обращения к бд \(error)") + } + Logger.log("Профиль обновлен") + complition() + }) + } } diff --git a/DoIt/ViewModels/ProfileViewModel.swift b/DoIt/ViewModels/ProfileViewModel.swift index 40e737f..cc481ff 100644 --- a/DoIt/ViewModels/ProfileViewModel.swift +++ b/DoIt/ViewModels/ProfileViewModel.swift @@ -6,6 +6,7 @@ // import Foundation +import Firebase import UIKit final class ProfileViewModel { @@ -18,6 +19,17 @@ final class ProfileViewModel { var userTasksModel: Observable = Observable() + func getCurrentUser() { + DispatchQueue.global(qos: .userInitiated).async { [weak self] in + guard let uid = Auth.auth().currentUser?.uid else { + return + } + self?.userService.fetchUser(uid: uid) { [weak self] user in + self?.userModel.value = user + } + } + } + func getUserTasks() { DispatchQueue.global().async { [weak self] in guard let user = self?.userModel.value else { @@ -49,12 +61,12 @@ final class ProfileViewModel { func followUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { DispatchQueue.global().async { [weak self] in self?.userService.followUser(uid: user.uid) { error, _ in - guard error == nil else { - print(error!.localizedDescription) + if let error = error { + print(error.localizedDescription) completion(false) return } - self?.userModel.value?.isFollowed = true + user.isFollowed = true completion(true) } } @@ -63,12 +75,12 @@ final class ProfileViewModel { func unfollowUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { DispatchQueue.global().async { [weak self] in self?.userService.unfollowUser(uid: user.uid) { error, _ in - guard error == nil else { - print(error!.localizedDescription) + if let error = error { + print(error.localizedDescription) completion(false) return } - self?.userModel.value?.isFollowed = true + user.isFollowed = false completion(true) } } diff --git a/DoIt/ViewModels/SearchUsersViewModel.swift b/DoIt/ViewModels/SearchUsersViewModel.swift index d3482be..f35530c 100644 --- a/DoIt/ViewModels/SearchUsersViewModel.swift +++ b/DoIt/ViewModels/SearchUsersViewModel.swift @@ -50,6 +50,8 @@ final class SearchUsersViewModel { func getAllUsers() { DispatchQueue.global(qos: .userInitiated).async { [weak self] in self?.userService.fetchUsers(completion: { [weak self] users in + guard let user = self?.userModel.value else { return } + let users = users.filter({ $0.uid != user.uid }) users.forEach { user in self?.userService.isUserFollowed(uid: user.uid) { user.isFollowed = $0 } } @@ -61,8 +63,8 @@ final class SearchUsersViewModel { func followUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { DispatchQueue.global().async { [weak self] in self?.userService.followUser(uid: user.uid) { error, _ in - guard error == nil else { - print(error!.localizedDescription) + if let error = error { + print(error.localizedDescription) completion(false) return } @@ -75,12 +77,12 @@ final class SearchUsersViewModel { func unfollowUser(_ user: UserModel, completion: @escaping (Bool) -> ()) { DispatchQueue.global().async { [weak self] in self?.userService.unfollowUser(uid: user.uid) { error, _ in - guard error == nil else { - print(error!.localizedDescription) + if let error = error { + print(error.localizedDescription) completion(false) return } - user.isFollowed = true + user.isFollowed = false completion(true) } } diff --git a/DoIt/Views/Custom Views/Auth.swift b/DoIt/Views/Custom Views/Auth.swift index 0770975..afffa82 100644 --- a/DoIt/Views/Custom Views/Auth.swift +++ b/DoIt/Views/Custom Views/Auth.swift @@ -36,7 +36,7 @@ final class InputField: UIView { // MARK: - Initializers - init(labelImage: UIImage? = nil, keyboardType: UIKeyboardType = .default, placeholderText: String) { + init(labelImage: UIImage? = nil, keyboardType: UIKeyboardType = .default, placeholderText: String?) { super.init(frame: .zero) heightAnchor.constraint(equalToConstant: UIConstants.height).isActive = true @@ -71,7 +71,7 @@ final class InputField: UIView { icon.bottomAnchor.constraint(equalTo: bottomAnchor, constant: UIConstants.paddingBottom).isActive = true } - private func addTextfield(placeholderText: String) { + private func addTextfield(placeholderText: String?) { addSubview(textField) textField.autocorrectionType = .no textField.placeholder = placeholderText diff --git a/DoIt/Views/Custom Views/CustomTabBarController.swift b/DoIt/Views/Custom Views/CustomTabBarController.swift index 34c7abe..b573007 100644 --- a/DoIt/Views/Custom Views/CustomTabBarController.swift +++ b/DoIt/Views/Custom Views/CustomTabBarController.swift @@ -36,15 +36,10 @@ class CustomTabBarController: SwipeableTabBarController { //MARK: - Helpers private func configureViewControllers() { - let temp: [String: String] = ["email" : "greagges@vk.com", "username": "myname", "password": "12345678"] - let userModel = UserModel(uid: "fafaf", dictionary: temp as [String: AnyObject]) - let tasks = TasksController() - tasks.userModel = userModel tasks.tabBarItem = UITabBarItem(title: TabBarStrings.tasks.rawValue.localized, image: .TabBarIcons.tasksIcon, selectedImage: nil) let feed = FeedController() - feed.userModel = userModel feed.tabBarItem = UITabBarItem(title: TabBarStrings.feed.rawValue.localized, image: .TabBarIcons.feedIcon, selectedImage: nil) let controllers = [ CustomNavigationController(rootViewController: tasks), CustomNavigationController(rootViewController: feed) ] diff --git a/DoIt/Views/Profile/ProfileEditViewController.swift b/DoIt/Views/Profile/ProfileEditViewController.swift index ad9c9ce..149cc25 100644 --- a/DoIt/Views/Profile/ProfileEditViewController.swift +++ b/DoIt/Views/Profile/ProfileEditViewController.swift @@ -149,6 +149,8 @@ final class ProfileEditViewController: UIViewController { summaryTextView.text = userModel.summary profileImageView.layoutIfNeeded() profileImageView.setImageForName(userModel.name ?? userModel.username, circular: false, textAttributes: nil) + loginInputField.textField.text = userModel.username + nameInputField.textField.text = userModel.name guard let imageURL = userModel.image else { return } @@ -200,11 +202,12 @@ final class ProfileEditViewController: UIViewController { extension ProfileEditViewController { @objc private func doneEditing() { - guard let userModel = viewModel.userModel.value else { return } + guard viewModel.userModel.value != nil else { return } + let summary = summaryTextView.textView.text == ProfileEditString.summeryPlaceholder.rawValue.localized ? nil : summaryTextView.textView.text viewModel.updateUserProfile(image: imageWasChanged ? profileImageView.image : nil, name: nameInputField.textField.text, - username: loginInputField.textField.text ?? userModel.username, - summary: summaryTextView.textView.text.isEmpty ? nil : summaryTextView.textView.text, + username: loginInputField.textField.text, + summary: summary, complition: { DispatchQueue.main.async { [weak self] in self?.navigationController?.popViewController(animated: true) diff --git a/DoIt/Views/Profile/ProfileViewController.swift b/DoIt/Views/Profile/ProfileViewController.swift index 85e7573..83c3cda 100644 --- a/DoIt/Views/Profile/ProfileViewController.swift +++ b/DoIt/Views/Profile/ProfileViewController.swift @@ -313,6 +313,7 @@ class ProfileViewController: UIViewController { private func configureCells() { guard let userModel = viewModel.userModel.value else { return } + configureNavigationController(title: viewModel.userModel.value?.username ?? "", isMyScreen: viewModel.userModel.value?.isCurrentUser ?? false) configureHeader(imageURL: userModel.image, name: userModel.name, login: userModel.username, isFollowed: userModel.isFollowed ?? false, isMyScreen: userModel.isCurrentUser) configureInformation(summary: userModel.summary) configureStatistics() diff --git a/DoIt/Views/Search Users/SearchUsersController.swift b/DoIt/Views/Search Users/SearchUsersController.swift index e4a6237..b0d7859 100644 --- a/DoIt/Views/Search Users/SearchUsersController.swift +++ b/DoIt/Views/Search Users/SearchUsersController.swift @@ -84,6 +84,8 @@ final class SearchUsersController: UIViewController { } } + viewModel.getCurrentUser() + configureUI() } @@ -159,6 +161,7 @@ extension SearchUsersController: UITableViewDataSource { guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchUsersCell.self), for: indexPath) as? SearchUsersCell else { return .init() } + cell.delegate = self cell.indexPathRow = indexPath.row guard viewModel.filteredUsersModel.value == nil else { cell.configureCell(with: viewModel.filteredUsersModel.value![indexPath.row])