diff --git a/mobileClient/ios/Podfile.lock b/mobileClient/ios/Podfile.lock index aa11c6bc1c4445eb23eea7d6118973539c639f91..91e52cc8b10382e0e825c668cc3d4b37443e6a62 100644 --- a/mobileClient/ios/Podfile.lock +++ b/mobileClient/ios/Podfile.lock @@ -1,5 +1,13 @@ PODS: - Flutter (1.0.0) + - flutter_inappwebview_ios (0.0.1): + - Flutter + - flutter_inappwebview_ios/Core (= 0.0.1) + - OrderedSet (~> 6.0.3) + - flutter_inappwebview_ios/Core (0.0.1): + - Flutter + - OrderedSet (~> 6.0.3) + - OrderedSet (6.0.3) - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -9,12 +17,19 @@ PODS: DEPENDENCIES: - Flutter (from `Flutter`) + - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) +SPEC REPOS: + trunk: + - OrderedSet + EXTERNAL SOURCES: Flutter: :path: Flutter + flutter_inappwebview_ios: + :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" webview_flutter_wkwebview: @@ -22,6 +37,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4 diff --git a/mobileClient/ios/Runner.xcodeproj/project.pbxproj b/mobileClient/ios/Runner.xcodeproj/project.pbxproj index 39e9d4f92cfe4b9b25358931c61867ad42292bc8..3152424c2c6a9c2e9274b753cc7d9d1c14ccb4e4 100644 --- a/mobileClient/ios/Runner.xcodeproj/project.pbxproj +++ b/mobileClient/ios/Runner.xcodeproj/project.pbxproj @@ -7,11 +7,11 @@ objects = { /* Begin PBXBuildFile section */ - 056475F6E383C4DB5AFD9884 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA15BACAD1D332D3644FA87F /* Pods_Runner.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 151450DDC3137582FE5482DB /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F1ED599596233C3024B455D7 /* Pods_RunnerTests.framework */; }; + 2558D446A209C4FCCBD450EF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2949718CA4AEBC4D14D9A5F7 /* Pods_Runner.framework */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 66C8405CAC38043C140C18C7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 94338E2F5E217E4F2546A443 /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -42,16 +42,19 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 077000DC94ECB72A595788B3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; - 22A3628A7C527893BDA009B9 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; }; + 2949718CA4AEBC4D14D9A5F7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; + 51BA252E131628B88A41C06A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; + 7781770382AE77512DFCB07C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; - 88B236DB323E4E5A79FF6CA9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; + 94338E2F5E217E4F2546A443 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -59,12 +62,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; - A8AEC17B32157F7343D75C77 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; }; - BA46C00A29A9EF58EEBAD414 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; - DA15BACAD1D332D3644FA87F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E65AFB5AF2B88D532CD22CAB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; - F1ED599596233C3024B455D7 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - FEEE9F4157A31755ADC8AC98 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; }; + AEC8637C7B3D9483AFB40617 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; }; + BC7DE9EDC168EE2A3774994E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; + C7D5B9FD438889D029B3CBB5 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,7 +72,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 151450DDC3137582FE5482DB /* Pods_RunnerTests.framework in Frameworks */, + 66C8405CAC38043C140C18C7 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -80,42 +80,42 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 056475F6E383C4DB5AFD9884 /* Pods_Runner.framework in Frameworks */, + 2558D446A209C4FCCBD450EF /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 2C6782B60E204E8E16F18566 /* Pods */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - BA46C00A29A9EF58EEBAD414 /* Pods-Runner.debug.xcconfig */, - E65AFB5AF2B88D532CD22CAB /* Pods-Runner.release.xcconfig */, - 88B236DB323E4E5A79FF6CA9 /* Pods-Runner.profile.xcconfig */, - A8AEC17B32157F7343D75C77 /* Pods-RunnerTests.debug.xcconfig */, - FEEE9F4157A31755ADC8AC98 /* Pods-RunnerTests.release.xcconfig */, - 22A3628A7C527893BDA009B9 /* Pods-RunnerTests.profile.xcconfig */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); - name = Pods; - path = Pods; + path = RunnerTests; sourceTree = "<group>"; }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { + 589859FD2DEFB98701E152C2 /* Frameworks */ = { isa = PBXGroup; children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, + 2949718CA4AEBC4D14D9A5F7 /* Pods_Runner.framework */, + 94338E2F5E217E4F2546A443 /* Pods_RunnerTests.framework */, ); - path = RunnerTests; + name = Frameworks; sourceTree = "<group>"; }; - 5FCB225371B8947D6A6CF093 /* Frameworks */ = { + 6C383455CCDDBC4EE5DAFF41 /* Pods */ = { isa = PBXGroup; children = ( - DA15BACAD1D332D3644FA87F /* Pods_Runner.framework */, - F1ED599596233C3024B455D7 /* Pods_RunnerTests.framework */, + 51BA252E131628B88A41C06A /* Pods-Runner.debug.xcconfig */, + 7781770382AE77512DFCB07C /* Pods-Runner.release.xcconfig */, + BC7DE9EDC168EE2A3774994E /* Pods-Runner.profile.xcconfig */, + 077000DC94ECB72A595788B3 /* Pods-RunnerTests.debug.xcconfig */, + AEC8637C7B3D9483AFB40617 /* Pods-RunnerTests.release.xcconfig */, + C7D5B9FD438889D029B3CBB5 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Frameworks; + name = Pods; + path = Pods; sourceTree = "<group>"; }; 9740EEB11CF90186004384FC /* Flutter */ = { @@ -136,8 +136,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, - 2C6782B60E204E8E16F18566 /* Pods */, - 5FCB225371B8947D6A6CF093 /* Frameworks */, + 6C383455CCDDBC4EE5DAFF41 /* Pods */, + 589859FD2DEFB98701E152C2 /* Frameworks */, ); sourceTree = "<group>"; }; @@ -172,7 +172,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 88989ACD8BD49B08759AD3AA /* [CP] Check Pods Manifest.lock */, + B6D846A6819375231BFB0E2B /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, 2CF32BD699435AD6979CF9C5 /* Frameworks */, @@ -191,14 +191,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 2C4A8AA2AD3D8EA399B2D867 /* [CP] Check Pods Manifest.lock */, + 6243BCF740DC38ADB8A6ABB1 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 5EA4746333E177D91482F610 /* [CP] Embed Pods Frameworks */, + F462B9DAD043E94968D57633 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -270,7 +270,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 2C4A8AA2AD3D8EA399B2D867 /* [CP] Check Pods Manifest.lock */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 6243BCF740DC38ADB8A6ABB1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -292,40 +308,22 @@ 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; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); - name = "Thin Binary"; + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 5EA4746333E177D91482F610 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - 88989ACD8BD49B08759AD3AA /* [CP] Check Pods Manifest.lock */ = { + B6D846A6819375231BFB0E2B /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -347,20 +345,22 @@ 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; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + F462B9DAD043E94968D57633 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputPaths = ( + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Run Script"; - outputPaths = ( + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -487,7 +487,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A8AEC17B32157F7343D75C77 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = 077000DC94ECB72A595788B3 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -505,7 +505,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FEEE9F4157A31755ADC8AC98 /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = AEC8637C7B3D9483AFB40617 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -521,7 +521,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 22A3628A7C527893BDA009B9 /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = C7D5B9FD438889D029B3CBB5 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/mobileClient/lib/api/api_client.dart b/mobileClient/lib/api/api_client.dart index fbb75ec07ec4be51a06cc3bc54e5bd07b9c486ae..d8f95ee84f4fc1d1aeecd3b88e2233494c2d0b3e 100644 --- a/mobileClient/lib/api/api_client.dart +++ b/mobileClient/lib/api/api_client.dart @@ -32,11 +32,15 @@ class ApiClient { } Future<Map<String, dynamic>> post( - String endpoint, Map<String, dynamic> body) async { + String endpoint, Map<String, dynamic> body, String token) async { final uri = getUri(endpoint); + final response = await http.post( uri, - headers: {"Content-Type": "application/json"}, + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer $token", + }, body: jsonEncode(body), ); @@ -49,4 +53,31 @@ class ApiClient { throw Exception("Error al realizar la petición POST a $endpoint"); } } + + Future<dynamic> delete(String endpoint, {String? token}) async { + try { + final uri = getUri(endpoint); + final headers = { + "Content-Type": "application/json", + if (token != null) "Authorization": "Bearer $token", + }; + + final response = await http.delete(uri, headers: headers); + + if (response.statusCode == 200 || response.statusCode == 204) { + return response.body.isNotEmpty + ? jsonDecode(utf8.decode(response.bodyBytes)) + : {}; + } else { + final errorResponse = utf8.decode(response.bodyBytes); + print( + "Error al realizar la petición DELETE a $endpoint: $errorResponse"); + throw Exception( + "Error inesperado (${response.statusCode}) en $endpoint: $errorResponse"); + } + } catch (e) { + print("Error en la solicitud DELETE a $endpoint: $e"); + rethrow; + } + } } diff --git a/mobileClient/lib/api/interfaces/notification_interface.dart b/mobileClient/lib/api/interfaces/notification_interface.dart new file mode 100644 index 0000000000000000000000000000000000000000..d1aebc854ac02b77a6a1cb0d7a971472b110b96f --- /dev/null +++ b/mobileClient/lib/api/interfaces/notification_interface.dart @@ -0,0 +1,9 @@ +import 'package:verificado_uy/models/notifications_model.dart'; + +abstract class ApiServiceInterface { + Future<List<Notifications>> fetchNotificationsService(String userId); + + Future<bool> deleteNotificationService(String notificationId); + + Future<bool> deleteAllNotificationsService(String userId); +} diff --git a/mobileClient/lib/api/services/fact_service.dart b/mobileClient/lib/api/services/fact_service.dart index 8a90884547186fb72121f5184772525c7966312f..b5f6ba34316d4ca883524ccaef45da6b4e27fdf1 100644 --- a/mobileClient/lib/api/services/fact_service.dart +++ b/mobileClient/lib/api/services/fact_service.dart @@ -25,10 +25,10 @@ class FactService { } } - Future<void> createFact(Fact fact) async { + Future<void> createFact(Fact fact, String token) async { try { final jsonData = fact.toJson(); - await apiClient.post("facts/create", jsonData); + await apiClient.post("facts/create", jsonData, token); } catch (e) { print("Error al crear el hecho: $e"); rethrow; @@ -41,14 +41,14 @@ class FactService { return []; } try { - print(userId); final encodedUserId = Uri.encodeComponent(userId); - final jsonData = await apiClient.get("facts?submittedBy=$encodedUserId"); + final jsonData = await apiClient.get("facts?citizenId=$encodedUserId"); if (jsonData is List) { final List<Fact> facts = jsonData.map((item) { return Fact.fromJson(item); }).toList(); + print(facts); return facts; } else { @@ -62,7 +62,9 @@ class FactService { Future<List<Fact>> fetchFactsByTitle(String title) async { try { - final jsonData = await apiClient.get("facts?title=$title"); + final encodedTitle = Uri.encodeComponent(title); + final jsonData = + await apiClient.get("facts?status=PUBLICADO&title=$encodedTitle"); if (jsonData is List) { return jsonData.map((item) => Fact.fromJson(item)).toList(); diff --git a/mobileClient/lib/api/services/notifications_service.dart b/mobileClient/lib/api/services/notifications_service.dart new file mode 100644 index 0000000000000000000000000000000000000000..5dc726248a9f502fbb6ba17747a1b7e9b7c85a9a --- /dev/null +++ b/mobileClient/lib/api/services/notifications_service.dart @@ -0,0 +1,57 @@ +import 'package:verificado_uy/api/api_client.dart'; +import 'package:verificado_uy/models/notifications_model.dart'; + +class NotificationsService { + final ApiClient apiClient; + + NotificationsService(this.apiClient); + + Future<List<Notifications>> fetchNotificationsService(String userId) async { + try { + final jsonData = await apiClient.get("notifications/$userId"); + + if (jsonData is List) { + final List<Notifications> notifications = jsonData.map((item) { + return Notifications.fromJson(item); + }).toList(); + + return notifications; + } else { + throw Exception("Formato de datos inesperado"); + } + } catch (e) { + print("Error al obtener las notificaciones: $e"); + return []; + } + } + + Future<bool> deleteNotificationService(String notificationId) async { + try { + final response = await apiClient.delete("notifications/$notificationId"); + + if (response['success'] == true) { + return true; + } else { + throw Exception("Error al eliminar la notificación"); + } + } catch (e) { + print("Error: $e"); + return false; + } + } + + Future<void> deleteAllNotificationsService(String userId) async { + try { + final response = await apiClient.delete("notifications/user/$userId"); + + if (response['success'] == true) { + return; + } else { + throw Exception("Error al eliminar todas las notificaciones"); + } + } catch (e) { + print("Error: $e"); + throw Exception("Error en el servicio: ${e.toString()}"); + } + } +} diff --git a/mobileClient/lib/enums/notifications.dart b/mobileClient/lib/enums/notifications.dart deleted file mode 100644 index 246caf96c942721455d2d545787248eda3072051..0000000000000000000000000000000000000000 --- a/mobileClient/lib/enums/notifications.dart +++ /dev/null @@ -1 +0,0 @@ -enum Notificaciones { todas, hechosSolicitados, nuevosVerificados } diff --git a/mobileClient/lib/main.dart b/mobileClient/lib/main.dart index f9c99600924b94d2eae612d9d0a161c51bc2e9bb..35f0e709d7403965c5328f9c96874c61a1aa70d2 100644 --- a/mobileClient/lib/main.dart +++ b/mobileClient/lib/main.dart @@ -2,13 +2,17 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:verificado_uy/api/api_client.dart'; import 'package:verificado_uy/api/services/fact_service.dart'; +import 'package:verificado_uy/api/services/notifications_service.dart'; import 'package:verificado_uy/api/services/user_service.dart'; import 'package:verificado_uy/main_navigation.dart'; import 'package:verificado_uy/notifiers/facts/create_fact_notifier.dart'; import 'package:verificado_uy/notifiers/facts/fetch_fact_notifier.dart'; import 'package:verificado_uy/notifiers/facts/user_fact_notifier.dart'; +import 'package:verificado_uy/notifiers/notifications/delete_notifications_notifier.dart'; +import 'package:verificado_uy/notifiers/notifications/fetch_notifications_notifier.dart'; import 'package:verificado_uy/notifiers/user/user_notifier.dart'; import 'package:verificado_uy/providers/auth_provider.dart'; +import 'package:verificado_uy/providers/fact_category_provider.dart'; import 'package:verificado_uy/providers/fact_status_provider.dart'; import 'package:verificado_uy/theme/app_colors.dart'; import 'package:verificado_uy/ui/screens/auth/login_screen.dart'; @@ -17,18 +21,24 @@ void main() { final apiClient = ApiClient(); final factService = FactService(apiClient); final userService = UserService(apiClient); + final notificstionsService = NotificationsService(apiClient); runApp( MultiProvider( providers: [ ChangeNotifierProvider( - create: (_) => AuthProvider() - ..checkAuthentication()), // Aseguramos que el estado de autenticación se verifique al inicio + create: (_) => AuthProvider()..checkAuthentication()), ChangeNotifierProvider(create: (_) => FactStatusProvider()), + ChangeNotifierProvider(create: (_) => FactCategoryProvider()), ChangeNotifierProvider(create: (_) => FetchFactNotifier(factService)), ChangeNotifierProvider(create: (_) => CreateFactNotifier(factService)), ChangeNotifierProvider(create: (_) => UserFactNotifier(factService)), ChangeNotifierProvider(create: (_) => UserNotifier(userService)), + ChangeNotifierProvider(create: (_) => AuthProvider()), + ChangeNotifierProvider( + create: (_) => FetchNotificationsNotifier(notificstionsService)), + ChangeNotifierProvider( + create: (_) => DeleteNotificationsNotifier(notificstionsService)), ], child: const MyApp(), ), @@ -57,7 +67,6 @@ class MyApp extends StatelessWidget { home: Consumer<AuthProvider>( builder: (context, authProvider, child) { if (authProvider.isLoading) { - // Muestra un indicador de carga mientras se verifica el estado de autenticación return const Center( child: CircularProgressIndicator( color: AppColors.frenchBlue, diff --git a/mobileClient/lib/main_navigation.dart b/mobileClient/lib/main_navigation.dart index ae99e678d8fb6b61247b6081d5630e55a24ba37c..c5575b304e4d4c2f82a09f90968619239bc3ed3f 100644 --- a/mobileClient/lib/main_navigation.dart +++ b/mobileClient/lib/main_navigation.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:verificado_uy/models/fact_model.dart'; +import 'package:verificado_uy/models/notifications_model.dart'; +import 'package:verificado_uy/models/user_model.dart'; import 'package:verificado_uy/notifiers/facts/fetch_fact_notifier.dart'; import 'package:verificado_uy/notifiers/facts/user_fact_notifier.dart'; +import 'package:verificado_uy/notifiers/notifications/fetch_notifications_notifier.dart'; import 'package:verificado_uy/notifiers/user/user_notifier.dart'; import 'package:verificado_uy/ui/screens/main_navigation/facts/add_fact_to_review.dart'; import 'package:verificado_uy/ui/screens/main_navigation/home/home_screen.dart'; @@ -21,6 +26,8 @@ class _MainNavigationState extends State<MainNavigation> { int _selectedIndex = 0; List<Fact> facts = []; List<Fact> userFacts = []; + List<Notifications> notificaciotions = []; + User user = User(id: '', email: '', userName: ''); bool isLoading = true; String? errorMessage; @@ -43,14 +50,27 @@ class _MainNavigationState extends State<MainNavigation> { Future<void> loadData() async { final factNotifier = Provider.of<FetchFactNotifier>(context, listen: false); final userNotifier = Provider.of<UserNotifier>(context, listen: false); + final notificationsNotifier = + Provider.of<FetchNotificationsNotifier>(context, listen: false); final userFactNotifier = Provider.of<UserFactNotifier>(context, listen: false); try { - await userNotifier.getUserInfo(); + final prefs = await SharedPreferences.getInstance(); + String token = prefs.getString('user_token') ?? ''; + if (token.isNotEmpty) { + Map<String, dynamic> decodedToken = JwtDecoder.decode(token); + String userId = decodedToken['id'] ?? ''; + String userName = decodedToken['username'] ?? ''; + String userEmail = decodedToken['email'] ?? ''; + + await userNotifier.updateUserInfo(userId, userName, userEmail); + } await factNotifier.fetchFacts(); + await notificationsNotifier.fetchNotifications(userNotifier.user.id); + await userFactNotifier.userFacts(userNotifier.user.id); setState(() { @@ -79,7 +99,10 @@ class _MainNavigationState extends State<MainNavigation> { HomeScreen( facts: facts, isLoading: isLoading, errorMessage: errorMessage), const AddFactToReview(), - const NotificationsScreen(), + NotificationsScreen( + notifications: notificaciotions, + isLoading: isLoading, + ), ProfileScreen( facts: userFacts, user: user, diff --git a/mobileClient/lib/models/notifications_model.dart b/mobileClient/lib/models/notifications_model.dart index 68264cc45166f8217740c10cfa2519c8a70fb301..2f4db56c50393b9c14bad8adb85a93151b83846a 100644 --- a/mobileClient/lib/models/notifications_model.dart +++ b/mobileClient/lib/models/notifications_model.dart @@ -1,21 +1,46 @@ -import 'package:verificado_uy/enums/notifications.dart'; +import 'package:verificado_uy/enums/fact_category.dart'; class Notifications { Notifications({ - required this.title, - required this.type, + required this.id, + required this.date, + required this.message, + required this.userId, + required this.category, }); - final String title; - final Notificaciones type; + final String id; + final FactCategory category; + final DateTime date; + final String message; + final String userId; Notifications copyWith({ - String? title, - Notificaciones? type, + String? id, + FactCategory? category, + DateTime? date, + String? message, + String? userId, }) { return Notifications( - title: title ?? this.title, - type: type ?? this.type, + id: id ?? this.id, + category: category ?? this.category, + date: date ?? this.date, + message: message ?? this.message, + userId: userId ?? this.userId, + ); + } + + factory Notifications.fromJson(Map<String, dynamic> json) { + return Notifications( + id: json['id'].toString(), + date: json['date'] as DateTime, + message: json['message'] as String, + category: FactCategory.values.firstWhere( + (e) => e.toString().split('.').last == json['category'], + orElse: () => FactCategory.CULTURA, + ), + userId: json['userId'] as String, ); } } diff --git a/mobileClient/lib/models/user_model.dart b/mobileClient/lib/models/user_model.dart index 98ef6aaf086fd1062a63d3a9f986d4e5158affb4..141f3dbe285959751c5306e93fb606d04f83b973 100644 --- a/mobileClient/lib/models/user_model.dart +++ b/mobileClient/lib/models/user_model.dart @@ -2,33 +2,33 @@ class User { User({ required this.id, required this.email, - required this.name, + required this.userName, this.date, }); final String id; final String email; - final String name; + final String userName; final DateTime? date; User copyWith({ String? id, String? email, - String? name, + String? userName, DateTime? date, }) { return User( id: id ?? this.id, email: email ?? this.email, - name: name ?? this.name, + userName: userName ?? this.userName, date: date ?? this.date); } factory User.fromJson(Map<String, dynamic> json) { return User( id: json['id'].toString(), - email: json['name'] as String, - name: json['email'] as String, + email: json['email'] as String, + userName: json['user_name'] as String, date: json['date'] as DateTime, ); } diff --git a/mobileClient/lib/notifiers/facts/create_fact_notifier.dart b/mobileClient/lib/notifiers/facts/create_fact_notifier.dart index 020ba04cc1c816f201abea2730e0bb11c1ba3cd6..289a6bfcfb55c63a533578b953da7b2be073e522 100644 --- a/mobileClient/lib/notifiers/facts/create_fact_notifier.dart +++ b/mobileClient/lib/notifiers/facts/create_fact_notifier.dart @@ -15,12 +15,12 @@ class CreateFactNotifier extends ChangeNotifier { String? _errorMessage; String? get errorMessage => _errorMessage; - Future<bool> createFact(Fact fact) async { + Future<bool> createFact(Fact fact, String token) async { _state = CreateFactState.loading; notifyListeners(); try { - await _factService.createFact(fact); + await _factService.createFact(fact, token); _state = CreateFactState.success; notifyListeners(); return true; diff --git a/mobileClient/lib/notifiers/notifications/delete_notifications_notifier.dart b/mobileClient/lib/notifiers/notifications/delete_notifications_notifier.dart new file mode 100644 index 0000000000000000000000000000000000000000..888a8391bd8327719a7c0c2f9c91e031de0d8e7d --- /dev/null +++ b/mobileClient/lib/notifiers/notifications/delete_notifications_notifier.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:verificado_uy/api/services/notifications_service.dart'; +import 'package:verificado_uy/models/notifications_model.dart'; + +enum DeleteNotificationsState { loading, loaded, error, empty } + +class DeleteNotificationsNotifier extends ChangeNotifier { + final NotificationsService _notificationsService; + + DeleteNotificationsNotifier(this._notificationsService); + + DeleteNotificationsState _state = DeleteNotificationsState.loading; + DeleteNotificationsState get state => _state; + + final List<Notifications> _notifications = []; + List<Notifications> get notifications => _notifications; + + String? _errorMessage; + String? get errorMessage => _errorMessage; + + Future<void> deleteNotification(String notificationId) async { + _state = DeleteNotificationsState.loading; + notifyListeners(); + + try { + await _notificationsService.deleteNotificationService(notificationId); + + _notifications + .removeWhere((notification) => notification.id == notificationId); + + if (_notifications.isEmpty) { + _state = DeleteNotificationsState.empty; + } else { + _state = DeleteNotificationsState.loaded; + } + } catch (e) { + _errorMessage = 'Error al eliminar la notificación: ${e.toString()}'; + _state = DeleteNotificationsState.error; + } + notifyListeners(); + } + + Future<void> deleteAllNotifications(String userId) async { + _state = DeleteNotificationsState.loading; + notifyListeners(); + + try { + await _notificationsService.deleteAllNotificationsService(userId); + + _notifications.clear(); + _state = DeleteNotificationsState.empty; + } catch (e) { + _errorMessage = + 'Error al eliminar todas las notificaciones: ${e.toString()}'; + _state = DeleteNotificationsState.error; + } + notifyListeners(); + } +} diff --git a/mobileClient/lib/notifiers/notifications/fetch_notifications_notifier.dart b/mobileClient/lib/notifiers/notifications/fetch_notifications_notifier.dart new file mode 100644 index 0000000000000000000000000000000000000000..7e30c9bc2c8bbf10f0ed722900d61a6fcefe506d --- /dev/null +++ b/mobileClient/lib/notifiers/notifications/fetch_notifications_notifier.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:verificado_uy/api/services/notifications_service.dart'; +import 'package:verificado_uy/models/notifications_model.dart'; + +enum FetchNotificationsState { loading, loaded, error, empty } + +class FetchNotificationsNotifier extends ChangeNotifier { + final NotificationsService _notificationsService; + + FetchNotificationsNotifier(this._notificationsService); + + FetchNotificationsState _state = FetchNotificationsState.loading; + FetchNotificationsState get state => _state; + + List<Notifications> _notifications = []; + List<Notifications> get notifications => _notifications; + + String? _errorMessage; + String? get errorMessage => _errorMessage; + + Future<void> fetchNotifications(String userId) async { + _state = FetchNotificationsState.loading; + notifyListeners(); + + try { + _notifications = + await _notificationsService.fetchNotificationsService(userId); + if (_notifications.isNotEmpty) { + _state = FetchNotificationsState.loaded; + } else { + _state = FetchNotificationsState.empty; + } + } catch (e) { + _errorMessage = 'Error al cargar las notificaciones: ${e.toString()}'; + _state = FetchNotificationsState.error; + } + notifyListeners(); + } +} diff --git a/mobileClient/lib/notifiers/user/user_notifier.dart b/mobileClient/lib/notifiers/user/user_notifier.dart index 51cc8a04729c9199e988f69de55be107fbf9f133..ae27056dd77f5ec1bed308fe11e4ae34e4a014e6 100644 --- a/mobileClient/lib/notifiers/user/user_notifier.dart +++ b/mobileClient/lib/notifiers/user/user_notifier.dart @@ -12,7 +12,7 @@ class UserNotifier extends ChangeNotifier { UserState _state = UserState.loading; UserState get state => _state; - User _user = User(id: '', email: '', name: ''); + User _user = User(id: '', email: '', userName: ''); User get user => _user; String? _errorMessage; @@ -29,8 +29,15 @@ class UserNotifier extends ChangeNotifier { _errorMessage = 'Error al cargar la información del usuario: ${e.toString()}'; _state = UserState.error; - _user = User(id: '', email: '', name: ''); + _user = User(id: '', email: '', userName: ''); } notifyListeners(); } + + Future<void> updateUserInfo( + String userId, String userName, String userEmail) async { + _user = User(id: userId, userName: userName, email: userEmail); + _state = UserState.loaded; + notifyListeners(); + } } diff --git a/mobileClient/lib/providers/auth_provider.dart b/mobileClient/lib/providers/auth_provider.dart index b03fffdfebebf81bc3f467ae2fd3f92e7fad3ffa..57f513b91115cc20ce7281a391603e4145603f35 100644 --- a/mobileClient/lib/providers/auth_provider.dart +++ b/mobileClient/lib/providers/auth_provider.dart @@ -1,14 +1,22 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:jwt_decoder/jwt_decoder.dart'; class AuthProvider extends ChangeNotifier { bool _isAuthenticated = false; bool _isLoading = false; String? _token; + String? _userId; + String? _userName; + String? _userEmail; + bool get isAuthenticated => _isAuthenticated; bool get isLoading => _isLoading; String? get token => _token; + String? get userId => _userId; + String? get userName => _userName; + String? get userEmail => _userEmail; AuthProvider() { checkAuthentication(); @@ -40,6 +48,7 @@ class AuthProvider extends ChangeNotifier { await prefs.setString('user_token', token); _isAuthenticated = true; _token = token; + _decodeToken(token); } else { _isAuthenticated = false; } @@ -48,12 +57,22 @@ class AuthProvider extends ChangeNotifier { notifyListeners(); } + void _decodeToken(String token) { + Map<String, dynamic> decodedToken = JwtDecoder.decode(token); + _userId = decodedToken['id']; + _userName = decodedToken['username']; + _userEmail = decodedToken['email']; + } + // Cerrar sesión Future<void> logout() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('user_token'); // Remover el token _isAuthenticated = false; _token = null; + _userId = null; + _userName = null; + _userEmail = null; notifyListeners(); } } diff --git a/mobileClient/lib/providers/fact_category_provider.dart b/mobileClient/lib/providers/fact_category_provider.dart new file mode 100644 index 0000000000000000000000000000000000000000..faea49d0ca310d7da5901f74dc758162b75e37bb --- /dev/null +++ b/mobileClient/lib/providers/fact_category_provider.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:verificado_uy/enums/fact_category.dart'; + +class FactCategoryProvider with ChangeNotifier { + final Map<FactCategory, Color> pastelColors = { + FactCategory.POLITICA: Colors.blue[200]!, // Pastel blue + FactCategory.ECONOMIA: Colors.green[200]!, // Pastel green + FactCategory.SOCIEDAD: Colors.pink[200]!, // Pastel pink + FactCategory.CIENCIA: Colors.teal[200]!, // Pastel teal + FactCategory.TECNOLOGIA: Colors.purple[200]!, // Pastel purple + FactCategory.DEPORTE: Colors.orange[200]!, // Pastel orange + FactCategory.CULTURA: Colors.yellow[200]!, // Pastel yellow + FactCategory.OTROS: Colors.grey[400]!, // Pastel grey + FactCategory.SALUD: Colors.red[200]!, // Pastel red + FactCategory.AMBIENTE: Colors.lightGreen[200]!, // Pastel light green + FactCategory.POLICIALES: Colors.indigo[200]!, // Pastel indigo + }; + + final Map<FactCategory, Color> strongColors = { + FactCategory.POLITICA: Colors.blue, // Strong blue + FactCategory.ECONOMIA: Colors.green, // Strong green + FactCategory.SOCIEDAD: Colors.pink, // Strong pink + FactCategory.CIENCIA: Colors.teal, // Strong teal + FactCategory.TECNOLOGIA: Colors.purple, // Strong purple + FactCategory.DEPORTE: Colors.orange, // Strong orange + FactCategory.CULTURA: Colors.yellow, // Strong yellow + FactCategory.OTROS: Colors.grey, // Strong grey + FactCategory.SALUD: Colors.red, // Strong red + FactCategory.AMBIENTE: Colors.lightGreen, // Strong light green + FactCategory.POLICIALES: Colors.indigo, // Strong indigo + }; + + final Map<FactCategory, String> categoryStrings = { + FactCategory.POLITICA: "PolÃtica", + FactCategory.ECONOMIA: "EconomÃa", + FactCategory.SOCIEDAD: "Sociedad", + FactCategory.CIENCIA: "Ciencia", + FactCategory.TECNOLOGIA: "TecnologÃa", + FactCategory.DEPORTE: "Deporte", + FactCategory.CULTURA: "Cultura", + FactCategory.OTROS: "Otros", + FactCategory.SALUD: "Salud", + FactCategory.AMBIENTE: "Ambiente", + FactCategory.POLICIALES: "Policiales", + }; + + Color getPastelColor(FactCategory category) { + return pastelColors[category] ?? Colors.white; + } + + Color getStrongColor(FactCategory category) { + return strongColors[category] ?? Colors.black; + } + + String getString(FactCategory category) { + return categoryStrings[category] ?? ""; + } +} diff --git a/mobileClient/lib/ui/screens/auth/web_view_login.dart b/mobileClient/lib/ui/screens/auth/web_view_login.dart index 2af54813923a8578fda9385ea0cb493adf03f4da..ff660149e4be7ec64a609672e208e6d93a7bb119 100644 --- a/mobileClient/lib/ui/screens/auth/web_view_login.dart +++ b/mobileClient/lib/ui/screens/auth/web_view_login.dart @@ -24,14 +24,12 @@ class _TokenWebViewPageState extends State<TokenWebViewPage> { ..setNavigationDelegate( NavigationDelegate( onNavigationRequest: (NavigationRequest request) { - if (request.url.contains("errorCode=")) { - //CMBIAR POR TOKEN - final token = Uri.parse(request.url) - .queryParameters['errorCode']; //CAMBIAR POR TOKEN - print(token); + if (request.url.contains("token=")) { + final token = Uri.parse(request.url).queryParameters['token']; if (token != null && token.isNotEmpty) { Provider.of<AuthProvider>(context, listen: false) .loginWithToken(token); + _clearCookies(); Navigator.pop(context); } @@ -44,6 +42,10 @@ class _TokenWebViewPageState extends State<TokenWebViewPage> { ..loadRequest(Uri.parse(widget.initialUrl)); } + Future<void> _clearCookies() async { + await _controller.clearCache(); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/mobileClient/lib/ui/screens/main_navigation/notifications/manage_notifications_screen.dart b/mobileClient/lib/ui/screens/main_navigation/notifications/manage_notifications_screen.dart index 6cda4aad781342435f0e62be3a43a24eded49605..f821774d68fdbefd2b56d664bf30fea26261590c 100644 --- a/mobileClient/lib/ui/screens/main_navigation/notifications/manage_notifications_screen.dart +++ b/mobileClient/lib/ui/screens/main_navigation/notifications/manage_notifications_screen.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:verificado_uy/enums/notifications.dart'; +import 'package:verificado_uy/enums/fact_category.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/appbar/app_bar_back_button.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/notifications/notifications_toggle.dart'; @@ -12,16 +12,29 @@ class ManageNotificationsScreen extends StatefulWidget { } class _ManageNotificationsScreenState extends State<ManageNotificationsScreen> { - Notificaciones? _selectedNotification; + final Map<FactCategory, bool> _notificationsStatus = { + for (var category in FactCategory.values) category: false, + }; - void _handleNotificationToggle(Notificaciones type, bool isEnabled) { + bool _allNotificationsEnabled = false; + + void _handleNotificationToggle(FactCategory category, bool isEnabled) { setState(() { - _selectedNotification = isEnabled ? type : null; + _notificationsStatus[category] = isEnabled; + + _allNotificationsEnabled = + _notificationsStatus.values.every((status) => status); }); } - bool _isNotificationEnabled(Notificaciones type) { - return _selectedNotification == type; + void _handleToggleAll(bool isEnabled) { + setState(() { + _allNotificationsEnabled = isEnabled; + + for (var category in _notificationsStatus.keys) { + _notificationsStatus[category] = isEnabled; + } + }); } @override @@ -35,33 +48,24 @@ class _ManageNotificationsScreenState extends State<ManageNotificationsScreen> { child: Column( children: [ NotificationsToggle( - type: "Recibir todas las notificaciones", - isEnabled: _isNotificationEnabled(Notificaciones.todas), - onToggle: (isEnabled) => _handleNotificationToggle( - Notificaciones.todas, - isEnabled, - ), - ), - const SizedBox(height: 30), - NotificationsToggle( - type: "Recibir solo notificaciones de mis hechos", - isEnabled: - _isNotificationEnabled(Notificaciones.hechosSolicitados), - onToggle: (isEnabled) => _handleNotificationToggle( - Notificaciones.hechosSolicitados, - isEnabled, - ), - ), - const SizedBox(height: 30), - NotificationsToggle( - type: "Recibir notificaciones de nuevos hechos verificados", - isEnabled: - _isNotificationEnabled(Notificaciones.nuevosVerificados), - onToggle: (isEnabled) => _handleNotificationToggle( - Notificaciones.nuevosVerificados, - isEnabled, - ), + type: "Todas", + isEnabled: _allNotificationsEnabled, + onToggle: _handleToggleAll, ), + const SizedBox(height: 20), + ...FactCategory.values.map((category) { + return Column( + children: [ + NotificationsToggle( + type: _formatCategory(category), + isEnabled: _notificationsStatus[category] ?? false, + onToggle: (isEnabled) => + _handleNotificationToggle(category, isEnabled), + ), + const SizedBox(height: 20), + ], + ); + }).toList(), ], ), ), @@ -69,4 +73,9 @@ class _ManageNotificationsScreenState extends State<ManageNotificationsScreen> { ), ); } + + String _formatCategory(FactCategory category) { + return category.name[0] + + category.name.substring(1).toLowerCase().replaceAll('_', ' '); + } } diff --git a/mobileClient/lib/ui/screens/main_navigation/notifications/notifications_screen.dart b/mobileClient/lib/ui/screens/main_navigation/notifications/notifications_screen.dart index 89409e8e86cd6423ba06ff2a9807ead2b4d727a9..920e77a6b850849087b2078cf0e022ef19bc39b2 100644 --- a/mobileClient/lib/ui/screens/main_navigation/notifications/notifications_screen.dart +++ b/mobileClient/lib/ui/screens/main_navigation/notifications/notifications_screen.dart @@ -1,73 +1,90 @@ import 'package:flutter/material.dart'; -import 'package:verificado_uy/enums/notifications.dart'; +import 'package:verificado_uy/enums/fact_category.dart'; import 'package:verificado_uy/models/notifications_model.dart'; +import 'package:verificado_uy/theme/app_colors.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/appbar/custom_app_bar.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/notifications/notifications_card.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/pop_ups/notifications_pop_up.dart'; -List<Notifications> exampleNotifications = [ - Notifications( - title: 'Nuevo hecho verificado disponible', - type: Notificaciones.nuevosVerificados), - Notifications( - title: 'Solicitud de verificación de hecho', - type: Notificaciones.hechosSolicitados), - Notifications( - title: 'Todas las notificaciones activadas', type: Notificaciones.todas), - Notifications( - title: 'Nuevo hecho verificado en tu área', - type: Notificaciones.nuevosVerificados), - Notifications( - title: 'Revisión solicitada para un hecho', - type: Notificaciones.hechosSolicitados), - Notifications( - title: 'Resumen semanal de notificaciones', type: Notificaciones.todas), - Notifications( - title: 'Hecho solicitado por la comunidad', - type: Notificaciones.hechosSolicitados), - Notifications( - title: 'Nueva verificación aprobada', - type: Notificaciones.nuevosVerificados), - Notifications( - title: 'Todas las notificaciones actualizadas', - type: Notificaciones.todas), - Notifications( - title: 'Verificación pendiente de revisión', - type: Notificaciones.hechosSolicitados), -]; +class NotificationsScreen extends StatefulWidget { + final List<Notifications> notifications; + final bool isLoading; + final String? errorMessage; -class NotificationsScreen extends StatelessWidget { - const NotificationsScreen({super.key}); + const NotificationsScreen({ + super.key, + required this.notifications, + required this.isLoading, + this.errorMessage, + }); + @override + State<NotificationsScreen> createState() => _NotificationsScreenState(); +} + +class _NotificationsScreenState extends State<NotificationsScreen> { @override Widget build(BuildContext context) { + if (widget.isLoading) { + return const Center( + child: CircularProgressIndicator(color: AppColors.frenchBlue), + ); + } else if (widget.errorMessage != null) { + return Center( + child: Text( + widget.errorMessage!, + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.w500, fontSize: 20), + textAlign: TextAlign.center, + ), + ); + } + + //final List<Notifications> notificationsToDisplay = widget.notifications; + final List<Notifications> notificationsToDisplay = [ + Notifications( + id: "1", + message: 'esto es una notificacion', + category: FactCategory.DEPORTE, + userId: '1', + date: DateTime.now(), + ) + ]; + return Scaffold( appBar: const CustomAppBar( title: "Notificaciones", actions: [NotificationsPopUp()]), body: SafeArea( child: Container( padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20), - child: exampleNotifications.isEmpty + child: notificationsToDisplay.isEmpty ? Center( child: Text( - "No tienes notificaciones", + "No tienes notificaciones.", style: Theme.of(context) .textTheme .titleLarge - ?.copyWith(fontWeight: FontWeight.w500, fontSize: 20), + ?.copyWith(fontWeight: FontWeight.w500, fontSize: 18), + textAlign: TextAlign.center, ), ) : ListView.builder( padding: const EdgeInsets.only(bottom: 80), - itemCount: exampleNotifications.length, + itemCount: notificationsToDisplay.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.only(bottom: 15), child: Container( margin: const EdgeInsets.symmetric(horizontal: 10), child: NotificationsCard( - title: exampleNotifications[index].title, - type: exampleNotifications[index].type), + title: notificationsToDisplay[index].message, + type: notificationsToDisplay[index].category, + date: notificationsToDisplay[index].date, + id: notificationsToDisplay[index].id, + onDismissed: () {}, + ), ), ); }, diff --git a/mobileClient/lib/ui/screens/main_navigation/profile/profile_screen.dart b/mobileClient/lib/ui/screens/main_navigation/profile/profile_screen.dart index 702eedccdedee4183f6087b53227a6e200f5f175..049220decf36ceea143991e7db1dffd64cc12416 100644 --- a/mobileClient/lib/ui/screens/main_navigation/profile/profile_screen.dart +++ b/mobileClient/lib/ui/screens/main_navigation/profile/profile_screen.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:verificado_uy/enums/fact_status.dart'; import 'package:verificado_uy/models/fact_model.dart'; import 'package:verificado_uy/models/user_model.dart'; +import 'package:verificado_uy/notifiers/user/user_notifier.dart'; import 'package:verificado_uy/theme/app_colors.dart'; import 'package:verificado_uy/ui/screens/main_navigation/facts/info_my_fact_request.dart'; import 'package:verificado_uy/ui/widgets/facts/pending_request_card.dart'; @@ -9,13 +11,6 @@ import 'package:verificado_uy/ui/widgets/mainNavigation/appbar/custom_app_bar.da import 'package:verificado_uy/ui/widgets/mainNavigation/pop_ups/profile_pop_up.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/user_image.dart'; -User user = User( - id: '123', - email: 'john.travolta@example.com', - name: 'John Travolta', - date: DateTime(2024, 10, 22), -); - class ProfileScreen extends StatefulWidget { final List<Fact> facts; final bool isLoading; @@ -36,6 +31,7 @@ class ProfileScreen extends StatefulWidget { class _ProfileScreen extends State<ProfileScreen> { @override Widget build(BuildContext context) { + final userNotifier = Provider.of<UserNotifier>(context); List<Fact> pendingRequests = widget.facts; Widget pendingContent; @@ -108,11 +104,10 @@ class _ProfileScreen extends State<ProfileScreen> { padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20), child: Column( children: [ - // Información del usuario, siempre visible const UserImage(), const SizedBox(height: 30), Text( - user.name, + userNotifier.user.userName, style: Theme.of(context) .textTheme .titleLarge @@ -120,14 +115,12 @@ class _ProfileScreen extends State<ProfileScreen> { ), const SizedBox(height: 20), Text( - user.email, + userNotifier.user.email, style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox(height: 20), const Divider(color: Colors.black), const SizedBox(height: 10), - - // Sección de solicitudes pendientes Text( 'Solicitudes pendientes', style: Theme.of(context) @@ -136,8 +129,6 @@ class _ProfileScreen extends State<ProfileScreen> { ?.copyWith(fontSize: 24, fontWeight: FontWeight.w600), ), const SizedBox(height: 15), - - // Renderizado condicional para 'Solicitudes pendientes' pendingContent, ], ), diff --git a/mobileClient/lib/ui/widgets/mainNavigation/facts/add_fact_form.dart b/mobileClient/lib/ui/widgets/mainNavigation/facts/add_fact_form.dart index 988462e918834c2fde592e4d5dcde6a88b4d1ec5..5b4134f000cd69dd76004cf95fded857e51cbf47 100644 --- a/mobileClient/lib/ui/widgets/mainNavigation/facts/add_fact_form.dart +++ b/mobileClient/lib/ui/widgets/mainNavigation/facts/add_fact_form.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:verificado_uy/enums/fact_category.dart'; import 'package:verificado_uy/models/fact_model.dart'; import 'package:verificado_uy/notifiers/facts/create_fact_notifier.dart'; -import 'package:verificado_uy/notifiers/facts/fetch_fact_notifier.dart'; -import 'package:verificado_uy/theme/app_colors.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/facts/success_screen.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/ver_button.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/ver_drop_down.dart'; @@ -32,9 +31,21 @@ class AddFactForm extends StatefulWidget { class _AddFactFormState extends State<AddFactForm> { bool isButtonEnabled = false; + String token = ''; @override void initState() { + WidgetsBinding.instance.addPostFrameCallback( + (timeStamp) async { + await loadData(); + + if (!mounted) { + return; + } else { + setState(() {}); + } + }, + ); super.initState(); widget.titleController.addListener(_updateButtonState); widget.categoryController.addListener(_updateButtonState); @@ -43,6 +54,11 @@ class _AddFactFormState extends State<AddFactForm> { widget.imageUrlController.addListener(_updateButtonState); } + Future<void> loadData() async { + final prefs = await SharedPreferences.getInstance(); + token = prefs.getString('user_token') ?? ''; + } + @override void dispose() { widget.titleController.removeListener(_updateButtonState); @@ -120,7 +136,8 @@ class _AddFactFormState extends State<AddFactForm> { category: selectedCategory, source: widget.sourceController.text, ); - bool isSuccess = await factNotifier.createFact(newFact); + bool isSuccess = + await factNotifier.createFact(newFact, token); if (isSuccess) { Navigator.push( context, diff --git a/mobileClient/lib/ui/widgets/mainNavigation/notifications/notifications_card.dart b/mobileClient/lib/ui/widgets/mainNavigation/notifications/notifications_card.dart index 3a0d878b026f4d2d150e684ee93ebe7def32b99c..758a6333f2d16e30f5b5dee7ec959f1c3af4e2f0 100644 --- a/mobileClient/lib/ui/widgets/mainNavigation/notifications/notifications_card.dart +++ b/mobileClient/lib/ui/widgets/mainNavigation/notifications/notifications_card.dart @@ -1,52 +1,157 @@ import 'package:flutter/material.dart'; -import 'package:verificado_uy/enums/notifications.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:verificado_uy/enums/fact_category.dart'; +import 'package:verificado_uy/notifiers/notifications/delete_notifications_notifier.dart'; +import 'package:verificado_uy/providers/fact_category_provider.dart'; +import 'package:verificado_uy/theme/app_colors.dart'; import 'package:verificado_uy/ui/widgets/mainNavigation/notifications/notifications_image.dart'; class NotificationsCard extends StatelessWidget { - const NotificationsCard({super.key, required this.title, required this.type}); + const NotificationsCard({ + super.key, + required this.id, + required this.title, + required this.type, + required this.date, + required this.onDismissed, + }); + final String id; final String title; - final Notificaciones type; + final FactCategory type; + final DateTime date; + final VoidCallback onDismissed; @override Widget build(BuildContext context) { - return DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: Colors.white, - border: Border.all(color: Colors.black, width: 0.4), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.3), - spreadRadius: 2, - blurRadius: 5, - offset: const Offset(0, 3), - ), - ], + final provider = Provider.of<FactCategoryProvider>(context); + final notificationsNotifier = + Provider.of<DeleteNotificationsNotifier>(context, listen: false); + final pastelColor = provider.getPastelColor(type); + final strongColor = provider.getStrongColor(type); + final categoryString = provider.getString(type); + + return Dismissible( + key: ValueKey(id), + direction: DismissDirection.endToStart, + background: Container( + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(20), + ), + alignment: Alignment.centerRight, + padding: const EdgeInsets.only(right: 20), + child: const Icon( + Icons.delete, + color: Colors.white, + size: 30, + ), ), - child: SizedBox( - width: double.infinity, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), - child: Row( - children: [ - const NotificationsImage(), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w700, + onDismissed: (direction) async { + await notificationsNotifier.deleteNotification(id); + + if (notificationsNotifier.state == DeleteNotificationsState.loaded) { + onDismissed(); + } else if (notificationsNotifier.state == + DeleteNotificationsState.error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppColors.frenchBlue, + content: Center( + child: Text( + notificationsNotifier.errorMessage ?? + 'Error al eliminar la notificación', + style: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: Colors.white), + ), + )), + ); + } else if (notificationsNotifier.state == + DeleteNotificationsState.loading) { + const Center( + child: CircularProgressIndicator(color: AppColors.frenchBlue), + ); + } + }, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.white, + border: Border.all(color: Colors.black, width: 0.4), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 5, + offset: const Offset(0, 3), + ), + ], + ), + child: SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), + child: Row( + children: [ + const NotificationsImage(), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w700, + ), + maxLines: null, + ), + const SizedBox( + height: 5, + ), + Row( + children: [ + Text( + DateFormat('dd/MM/yyyy').format(date), + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + fontWeight: FontWeight.w400, + ), + maxLines: null, ), - maxLines: null, - ), - ], + const Spacer(), + DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + color: pastelColor, + ), + child: SizedBox( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + child: Text(categoryString, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + color: strongColor, + fontWeight: FontWeight.w800, + fontSize: 14)), + ), + ), + ) + ], + ), + ], + ), ), - ), - ], + ], + ), ), ), ), diff --git a/mobileClient/lib/ui/widgets/mainNavigation/pop_ups/notifications_pop_up.dart b/mobileClient/lib/ui/widgets/mainNavigation/pop_ups/notifications_pop_up.dart index 219d61fc160173fb7c9a7ca5b6339482e2f67785..66527d3720dfc9583f42134f39ff7762b19c42a1 100644 --- a/mobileClient/lib/ui/widgets/mainNavigation/pop_ups/notifications_pop_up.dart +++ b/mobileClient/lib/ui/widgets/mainNavigation/pop_ups/notifications_pop_up.dart @@ -1,9 +1,55 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:verificado_uy/notifiers/notifications/delete_notifications_notifier.dart'; +import 'package:verificado_uy/notifiers/user/user_notifier.dart'; +import 'package:verificado_uy/theme/app_colors.dart'; import 'package:verificado_uy/ui/screens/main_navigation/notifications/manage_notifications_screen.dart'; class NotificationsPopUp extends StatelessWidget { const NotificationsPopUp({super.key}); + Future<void> _clearAllNotifications(BuildContext context) async { + final userNotifier = Provider.of<UserNotifier>(context, listen: false); + final notificationsNotifier = + Provider.of<DeleteNotificationsNotifier>(context, listen: false); + + await notificationsNotifier.deleteAllNotifications(userNotifier.user.id); + if (notificationsNotifier.state == DeleteNotificationsState.loaded) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppColors.frenchBlue, + content: Center( + child: Text( + 'Todas las notificaciones han sido borradas.', + style: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: Colors.white), + )), + ), + ); + } else if (notificationsNotifier.state == DeleteNotificationsState.error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppColors.frenchBlue, + content: Center( + child: Text( + 'Error al eliminar las notificaciones', + style: Theme.of(context) + .textTheme + .bodyLarge + ?.copyWith(color: Colors.white), + ), + )), + ); + } else if (notificationsNotifier.state == + DeleteNotificationsState.loading) { + const Center( + child: CircularProgressIndicator(color: AppColors.frenchBlue), + ); + } + } + @override Widget build(BuildContext context) { return Theme( @@ -25,6 +71,8 @@ class NotificationsPopUp extends StatelessWidget { builder: (context) => const ManageNotificationsScreen(), ), ); + } else if (value == 'clear_all') { + _clearAllNotifications(context); } }, itemBuilder: (BuildContext context) { @@ -34,6 +82,11 @@ class NotificationsPopUp extends StatelessWidget { value: 'manage', child: Text('Gestionar notificaciones'), ), + const PopupMenuItem<String>( + padding: EdgeInsets.all(10), + value: 'clear_all', + child: Text('Borrar todas las notificaciones'), + ), ]; }, ), diff --git a/mobileClient/macos/Flutter/GeneratedPluginRegistrant.swift b/mobileClient/macos/Flutter/GeneratedPluginRegistrant.swift index c8f9f01cc163c532013ff2e4502d08911a3ae09b..f03d5fe1c2fe23bbbb06374fa0349954b9c9f5cb 100644 --- a/mobileClient/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/mobileClient/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,12 @@ import FlutterMacOS import Foundation +import flutter_inappwebview_macos import shared_preferences_foundation import webview_flutter_wkwebview func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin")) } diff --git a/mobileClient/macos/Runner/AppDelegate.swift b/mobileClient/macos/Runner/AppDelegate.swift index d53ef6437726b9d1558eda97582804175c0010a2..8e02df288835694650d8c57a5fffefcd8d7ff93f 100644 --- a/mobileClient/macos/Runner/AppDelegate.swift +++ b/mobileClient/macos/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/mobileClient/pubspec.lock b/mobileClient/pubspec.lock index 4f2e344c180062e04bfec475b8b6d9587fde17d4..477a2a228b4eec29949f8f83c844a6de76713dc6 100644 --- a/mobileClient/pubspec.lock +++ b/mobileClient/pubspec.lock @@ -118,6 +118,70 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.dev" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.dev" + source: hosted + version: "0.6.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -184,6 +248,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.9.0" + jwt_decoder: + dependency: "direct main" + description: + name: jwt_decoder + sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f" + url: "https://pub.dev" + source: hosted + version: "2.0.1" leak_tracker: dependency: transitive description: diff --git a/mobileClient/pubspec.yaml b/mobileClient/pubspec.yaml index bc8094faf071079b1a6c236ebff1e9fbb4e09289..1b985a3aaab4026bb02fded8a0972348ab368d46 100644 --- a/mobileClient/pubspec.yaml +++ b/mobileClient/pubspec.yaml @@ -19,6 +19,8 @@ dependencies: json_annotation: ^4.9.0 webview_flutter: ^4.8.0 shared_preferences: ^2.3.3 + jwt_decoder: ^2.0.1 + flutter_inappwebview: ^6.1.5 dev_dependencies: flutter_test: diff --git a/mobileClient/windows/flutter/generated_plugin_registrant.cc b/mobileClient/windows/flutter/generated_plugin_registrant.cc index 8b6d4680af388f28db8742ef7fb8246e2bb1fffb..3b4ee90334d9df2f8c8e149b775ed3a0943f085f 100644 --- a/mobileClient/windows/flutter/generated_plugin_registrant.cc +++ b/mobileClient/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h> void RegisterPlugins(flutter::PluginRegistry* registry) { + FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); } diff --git a/mobileClient/windows/flutter/generated_plugins.cmake b/mobileClient/windows/flutter/generated_plugins.cmake index b93c4c30c16703f640bc38523e56204ade09399e..61c79a21d4d70c1c24b929b96114b2b533babf77 100644 --- a/mobileClient/windows/flutter/generated_plugins.cmake +++ b/mobileClient/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_inappwebview_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST