diff --git a/packages/dart/npt_flutter/assets/advance.svg b/packages/dart/npt_flutter/assets/advance.svg new file mode 100644 index 000000000..df588c3b0 --- /dev/null +++ b/packages/dart/npt_flutter/assets/advance.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart/npt_flutter/assets/list_dashes.svg b/packages/dart/npt_flutter/assets/list_dashes.svg new file mode 100644 index 000000000..c4ddf2fd8 --- /dev/null +++ b/packages/dart/npt_flutter/assets/list_dashes.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/packages/dart/npt_flutter/assets/noports_logo.svg b/packages/dart/npt_flutter/assets/noports_logo.svg new file mode 100644 index 000000000..a966e86c4 --- /dev/null +++ b/packages/dart/npt_flutter/assets/noports_logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart/npt_flutter/assets/radio_button.svg b/packages/dart/npt_flutter/assets/radio_button.svg new file mode 100644 index 000000000..a1256bdca --- /dev/null +++ b/packages/dart/npt_flutter/assets/radio_button.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/dart/npt_flutter/assets/simple.svg b/packages/dart/npt_flutter/assets/simple.svg new file mode 100644 index 000000000..47ef0d5a8 --- /dev/null +++ b/packages/dart/npt_flutter/assets/simple.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/dart/npt_flutter/devtools_options.yaml b/packages/dart/npt_flutter/devtools_options.yaml new file mode 100644 index 000000000..fa0b357c4 --- /dev/null +++ b/packages/dart/npt_flutter/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/packages/dart/npt_flutter/ios/Podfile.lock b/packages/dart/npt_flutter/ios/Podfile.lock new file mode 100644 index 000000000..d347cfea1 --- /dev/null +++ b/packages/dart/npt_flutter/ios/Podfile.lock @@ -0,0 +1,165 @@ +PODS: + - at_backupkey_flutter (0.0.1): + - Flutter + - at_file_saver (0.0.1): + - Flutter + - at_onboarding_flutter (0.0.1): + - Flutter + - biometric_storage (0.0.1): + - Flutter + - device_info_plus (0.0.1): + - Flutter + - DKImagePickerController/Core (4.3.9): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.9) + - DKImagePickerController/PhotoGallery (4.3.9): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.9) + - DKPhotoGallery (0.0.19): + - DKPhotoGallery/Core (= 0.0.19) + - DKPhotoGallery/Model (= 0.0.19) + - DKPhotoGallery/Preview (= 0.0.19) + - DKPhotoGallery/Resource (= 0.0.19) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.19): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.19): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - file_selector_ios (0.0.1): + - Flutter + - Flutter (1.0.0) + - flutter_keychain (0.0.1): + - Flutter + - MTBBarcodeScanner (5.0.11) + - package_info_plus (0.4.5): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - permission_handler_apple (9.3.0): + - Flutter + - qr_code_scanner (0.2.0): + - Flutter + - MTBBarcodeScanner + - SDWebImage (5.19.4): + - SDWebImage/Core (= 5.19.4) + - SDWebImage/Core (5.19.4) + - share_plus (0.0.1): + - Flutter + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - SwiftyGif (5.4.5) + - url_launcher_ios (0.0.1): + - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter + +DEPENDENCIES: + - at_backupkey_flutter (from `.symlinks/plugins/at_backupkey_flutter/ios`) + - at_file_saver (from `.symlinks/plugins/at_file_saver/ios`) + - at_onboarding_flutter (from `.symlinks/plugins/at_onboarding_flutter/ios`) + - biometric_storage (from `.symlinks/plugins/biometric_storage/ios`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - file_selector_ios (from `.symlinks/plugins/file_selector_ios/ios`) + - Flutter (from `Flutter`) + - flutter_keychain (from `.symlinks/plugins/flutter_keychain/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) + +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - MTBBarcodeScanner + - SDWebImage + - SwiftyGif + +EXTERNAL SOURCES: + at_backupkey_flutter: + :path: ".symlinks/plugins/at_backupkey_flutter/ios" + at_file_saver: + :path: ".symlinks/plugins/at_file_saver/ios" + at_onboarding_flutter: + :path: ".symlinks/plugins/at_onboarding_flutter/ios" + biometric_storage: + :path: ".symlinks/plugins/biometric_storage/ios" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + file_selector_ios: + :path: ".symlinks/plugins/file_selector_ios/ios" + Flutter: + :path: Flutter + flutter_keychain: + :path: ".symlinks/plugins/flutter_keychain/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + permission_handler_apple: + :path: ".symlinks/plugins/permission_handler_apple/ios" + qr_code_scanner: + :path: ".symlinks/plugins/qr_code_scanner/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" + +SPEC CHECKSUMS: + at_backupkey_flutter: 2fc3d01138175e41bce8b574387a47544c53e01b + at_file_saver: c0e052c72d8c0296318bd70f2ae7f510887014ce + at_onboarding_flutter: e8219b6d0bfb236d3837ec3528871aebdcc56e8d + biometric_storage: 1400f1382af3a4cc2bf05340e13c3d8de873ceb9 + device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + file_selector_ios: f0670c1064a8c8450e38145d8043160105d0b97c + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_keychain: 01aabf894ffe8b01adfda1d9df21c210c1b4b452 + MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb + package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 + qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e + SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d + share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe + webview_flutter_wkwebview: 2a23822e9039b7b1bc52e5add778e5d89ad488d1 + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.14.3 diff --git a/packages/dart/npt_flutter/ios/Runner.xcodeproj/project.pbxproj b/packages/dart/npt_flutter/ios/Runner.xcodeproj/project.pbxproj index b530ac725..d91aa6e47 100644 --- a/packages/dart/npt_flutter/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/dart/npt_flutter/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + ABE4398EDCB374DB3C744673 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0542A615ED37F8C89E756574 /* Pods_RunnerTests.framework */; }; + FF90A8197CAEDF056A31D4BC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 533AF0BA188888B33F52F215 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,11 +42,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0542A615ED37F8C89E756574 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1A2A58DCFC85BDDEEC352839 /* 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 = ""; }; + 23F105CD2887A1BA835D3BEF /* 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 = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 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 = ""; }; + 47A9CCBF73EFA85D3A135C32 /* 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 = ""; }; + 533AF0BA188888B33F52F215 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -55,6 +62,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B51C1C3B5EDD481D35B1F82E /* 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 = ""; }; + BBF33EB0ED02DACC5C0FCBCC /* 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 = ""; }; + F4E98D1042220D05EB47E718 /* 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,6 +72,15 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + FF90A8197CAEDF056A31D4BC /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BBDA3723460887ED196722D8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ABE4398EDCB374DB3C744673 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -76,6 +95,15 @@ path = RunnerTests; sourceTree = ""; }; + 452321B41B775E8B94E1C4DC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 533AF0BA188888B33F52F215 /* Pods_Runner.framework */, + 0542A615ED37F8C89E756574 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -94,6 +122,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + B369985015352CE4455B46A3 /* Pods */, + 452321B41B775E8B94E1C4DC /* Frameworks */, ); sourceTree = ""; }; @@ -121,6 +151,20 @@ path = Runner; sourceTree = ""; }; + B369985015352CE4455B46A3 /* Pods */ = { + isa = PBXGroup; + children = ( + F4E98D1042220D05EB47E718 /* Pods-Runner.debug.xcconfig */, + 23F105CD2887A1BA835D3BEF /* Pods-Runner.release.xcconfig */, + B51C1C3B5EDD481D35B1F82E /* Pods-Runner.profile.xcconfig */, + 47A9CCBF73EFA85D3A135C32 /* Pods-RunnerTests.debug.xcconfig */, + BBF33EB0ED02DACC5C0FCBCC /* Pods-RunnerTests.release.xcconfig */, + 1A2A58DCFC85BDDEEC352839 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,8 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + B5F9916D88B9E984D2CD7E37 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + BBDA3723460887ED196722D8 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +191,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 86AE4F50BCFE929F9FB3B5D3 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 5ED76DEB71D5788F7D4C4845 /* [CP] Embed Pods Frameworks */, + 8C0F3CD693F51E1153307A85 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -238,6 +287,62 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 5ED76DEB71D5788F7D4C4845 /* [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; + }; + 86AE4F50BCFE929F9FB3B5D3 /* [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-Runner-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; + }; + 8C0F3CD693F51E1153307A85 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -253,6 +358,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + B5F9916D88B9E984D2CD7E37 /* [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-RunnerTests-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; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +506,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 47A9CCBF73EFA85D3A135C32 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +524,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BBF33EB0ED02DACC5C0FCBCC /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +540,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 1A2A58DCFC85BDDEEC352839 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/packages/dart/npt_flutter/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/dart/npt_flutter/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16e..21a3cc14c 100644 --- a/packages/dart/npt_flutter/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/dart/npt_flutter/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/packages/dart/npt_flutter/l10n.yaml b/packages/dart/npt_flutter/l10n.yaml new file mode 100644 index 000000000..a5b643abb --- /dev/null +++ b/packages/dart/npt_flutter/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/localization +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart \ No newline at end of file diff --git a/packages/dart/npt_flutter/lib/app.dart b/packages/dart/npt_flutter/lib/app.dart index 3a16b5241..b23881584 100644 --- a/packages/dart/npt_flutter/lib/app.dart +++ b/packages/dart/npt_flutter/lib/app.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/features.dart'; import 'package:npt_flutter/routes.dart'; +import 'package:npt_flutter/styles/app_theme.dart'; export 'package:npt_flutter/features/logging/logging.dart'; @@ -29,72 +31,86 @@ class App extends StatelessWidget { ), ], child: MultiBlocProvider( - providers: [ - BlocProvider( - create: (_) => EnableLoggingCubit(), - ), + providers: [ + BlocProvider( + create: (_) => EnableLoggingCubit(), + ), - /// Logging provider must come before ALL [LoggingBloc] & [LoggingCubit] providers - /// There MUST be a [LogsCubit] provider as an ancestor widget - BlocProvider( - create: (_) => LogsCubit(), - ), + /// Logging provider must come before ALL [LoggingBloc] & [LoggingCubit] providers + /// There MUST be a [LogsCubit] provider as an ancestor widget + BlocProvider( + create: (_) => LogsCubit(), + ), - /// A cubit which manages the onboarding status - BlocProvider( - create: (_) => OnboardingCubit(), - ), + /// A cubit which manages the onboarding status + BlocProvider( + create: (_) => OnboardingCubit(), + ), - /// Settings provider, not much else to say - /// - If settings are not found, we automatically load some defaults - /// so it is possible that someone's settings get wiped if there is - /// an issue loading them - BlocProvider( - create: (ctx) => SettingsBloc(ctx.read()), - ), + /// Settings provider, not much else to say + /// - If settings are not found, we automatically load some defaults + /// so it is possible that someone's settings get wiped if there is + /// an issue loading them + BlocProvider( + create: (ctx) => SettingsBloc(ctx.read()), + ), - /// - A list of all the uuids for profiles which have been found in persistence - /// - This list is ALL of the profiles which are loaded in the app for the onboarded atSign - /// Note that multiple client atSigns have not been considered as part of the current implementation - BlocProvider( - create: (ctx) => ProfileListBloc(ctx.read()), - ), + /// - A list of all the uuids for profiles which have been found in persistence + /// - This list is ALL of the profiles which are loaded in the app for the onboarded atSign + /// Note that multiple client atSigns have not been considered as part of the current implementation + BlocProvider( + create: (ctx) => ProfileListBloc(ctx.read()), + ), - /// A cubit which caches [ProfileBloc] by uuid so they can be shared - /// between the dashboard and the system tray - BlocProvider( - create: (ctx) => ProfileCacheCubit(ctx.read()), - ), + /// A cubit which caches [ProfileBloc] by uuid so they can be shared + /// between the dashboard and the system tray + BlocProvider( + create: (ctx) => ProfileCacheCubit(ctx.read()), + ), - /// [ProfilesSelectedCubit] reads from [ProfileListBloc], and must be under it - /// - A list of the uuids for profiles which have been check selected in the UI - BlocProvider( - create: (_) => ProfilesSelectedCubit(), - ), + /// [ProfilesSelectedCubit] reads from [ProfileListBloc], and must be under it + /// - A list of the uuids for profiles which have been check selected in the UI + BlocProvider( + create: (_) => ProfilesSelectedCubit(), + ), - /// - A map of uuid: SocketConnector for running profiles (a cache of running connections) - BlocProvider( - create: (_) => ProfilesRunningCubit(), - ), + /// - A map of uuid: SocketConnector for running profiles (a cache of running connections) + BlocProvider( + create: (_) => ProfilesRunningCubit(), + ), /// A cubit which manages the system tray entries BlocProvider( create: (_) => TrayCubit(), ), - /// A bloc which manages favorites - BlocProvider( - create: (ctx) => FavoriteBloc(ctx.read()), - ), - ], - child: TrayManager( - child: MaterialApp( - navigatorKey: navState, - initialRoute: Routes.onboarding, - routes: Routes.routes, - ), - ), - ), + /// A bloc which manages favorites + BlocProvider( + create: (ctx) => FavoriteBloc(ctx.read()), + ), + ], + child: BlocSelector(selector: (state) { + if (state is SettingsLoadedState) { + return state.settings.language; + } + + return Language.english; + }, builder: (context, language) { + return TrayManager( + child: MaterialApp( + theme: AppTheme.light(), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + locale: language.locale, + localeResolutionCallback: (locale, supportedLocales) { + return language.locale; + }, + navigatorKey: navState, + initialRoute: Routes.onboarding, + routes: Routes.routes, + ), + ); + })), ); } } diff --git a/packages/dart/npt_flutter/lib/constants.dart b/packages/dart/npt_flutter/lib/constants.dart index e12ec1250..843267e9e 100644 --- a/packages/dart/npt_flutter/lib/constants.dart +++ b/packages/dart/npt_flutter/lib/constants.dart @@ -13,10 +13,5 @@ class Constants { "@rv_ap": "Singapore", }; - // Languages (TODO) - // English - // Spanish - // Br portuguese - // Mandarin - // Cantonese + static const languages = ['English', 'Spanish', 'Br portuguese', 'Mandarin', 'Cantonese']; } diff --git a/packages/dart/npt_flutter/lib/features/logging/widgets/export_logs_button.dart b/packages/dart/npt_flutter/lib/features/logging/widgets/export_logs_button.dart index cfdf4e6a8..ed3fd91ca 100644 --- a/packages/dart/npt_flutter/lib/features/logging/widgets/export_logs_button.dart +++ b/packages/dart/npt_flutter/lib/features/logging/widgets/export_logs_button.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/logging/logging.dart'; class ExportLogsButton extends StatelessWidget { @@ -10,13 +11,14 @@ class ExportLogsButton extends StatelessWidget { @override Widget build(BuildContext context) { - return ElevatedButton( + final strings = AppLocalizations.of(context)!; + return TextButton.icon( onPressed: () async { var list = context.read().logs; final timestamp = DateTime.now().millisecondsSinceEpoch; String? outputFile = await FilePicker.platform.saveFile( - dialogTitle: 'Please select a file to export to:', - fileName: 'NoPorts-Logs-$timestamp.txt', + dialogTitle: strings.selectExportFile, + fileName: 'NoPorts-${strings.logs}-$timestamp.txt', ); if (outputFile == null) return; @@ -25,7 +27,8 @@ class ExportLogsButton extends StatelessWidget { await f.create(recursive: true); await f.writeAsString(list.join("\n")); }, - child: const Text("Export Logs"), + label: Text(strings.exportLogs), + icon: const Icon(Icons.download), ); } } diff --git a/packages/dart/npt_flutter/lib/features/onboarding/widgets/onboarding_button.dart b/packages/dart/npt_flutter/lib/features/onboarding/widgets/onboarding_button.dart index 011563724..53d269738 100644 --- a/packages/dart/npt_flutter/lib/features/onboarding/widgets/onboarding_button.dart +++ b/packages/dart/npt_flutter/lib/features/onboarding/widgets/onboarding_button.dart @@ -1,3 +1,4 @@ +import 'package:at_contacts_flutter/at_contacts_flutter.dart'; import 'package:at_onboarding_flutter/at_onboarding_flutter.dart'; import 'package:flutter/material.dart'; import 'package:npt_flutter/constants.dart'; @@ -55,6 +56,7 @@ class _OnboardingButtonState extends State { if (mounted) { switch (onboardingResult.status) { case AtOnboardingResultStatus.success: + await initializeContactsService(rootDomain: Constants.rootDomain); postOnboard(onboardingResult.atsign!); Navigator.of(context).pushReplacementNamed(widget.nextRoute); break; diff --git a/packages/dart/npt_flutter/lib/features/settings/models/settings.dart b/packages/dart/npt_flutter/lib/features/settings/models/settings.dart index af6035399..4a86142ed 100644 --- a/packages/dart/npt_flutter/lib/features/settings/models/settings.dart +++ b/packages/dart/npt_flutter/lib/features/settings/models/settings.dart @@ -1,5 +1,6 @@ -import 'package:npt_flutter/app.dart'; +import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; +import 'package:npt_flutter/app.dart'; part 'settings.g.dart'; @@ -18,6 +19,10 @@ enum PreferredViewLayout { enum Language { @JsonValue("en") english, + @JsonValue("es") + spanish, + @JsonValue("pt-br") + portuguese, } @JsonSerializable() @@ -59,8 +64,7 @@ class Settings extends Loggable { static const String customRelayKey = 'custom'; Map toJson() => _$SettingsToJson(this); - factory Settings.fromJson(Map json) => - _$SettingsFromJson(json); + factory Settings.fromJson(Map json) => _$SettingsFromJson(json); @override List get props => [ @@ -78,3 +82,29 @@ class Settings extends Loggable { 'darkMode: $darkMode, lang: ${_$LanguageEnumMap[language]}'; } } + +extension LanguageExtension on Language { + Locale get locale { + switch (this) { + case Language.english: + return const Locale('en'); + case Language.spanish: + return const Locale('es'); + case Language.portuguese: + return const Locale('pt', 'BR'); + } + } + + String get displayName { + switch (this) { + case Language.english: + return 'English'; + case Language.spanish: + return 'Español'; + case Language.portuguese: + return 'Português'; + } + } +} + +// ['English', 'Spanish', 'Br portuguese', 'Mandarin', 'Cantonese'] \ No newline at end of file diff --git a/packages/dart/npt_flutter/lib/features/settings/models/settings.g.dart b/packages/dart/npt_flutter/lib/features/settings/models/settings.g.dart index 90a3c3db6..2ccc6be9c 100644 --- a/packages/dart/npt_flutter/lib/features/settings/models/settings.g.dart +++ b/packages/dart/npt_flutter/lib/features/settings/models/settings.g.dart @@ -30,4 +30,6 @@ const _$PreferredViewLayoutEnumMap = { const _$LanguageEnumMap = { Language.english: 'en', + Language.spanish: 'es', + Language.portuguese: 'pt-br', }; diff --git a/packages/dart/npt_flutter/lib/features/settings/repository/contact_repository.dart b/packages/dart/npt_flutter/lib/features/settings/repository/contact_repository.dart new file mode 100644 index 000000000..2d5ca1066 --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/repository/contact_repository.dart @@ -0,0 +1,88 @@ +// 🎯 Dart imports: +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:at_client_mobile/at_client_mobile.dart'; +import 'package:at_contact/at_contact.dart'; +import 'package:at_contacts_flutter/services/contact_service.dart'; +import 'package:at_utils/at_utils.dart'; + +import '../../../constants.dart'; + +/// A singleton that makes all the network calls to the @platform. +class ContactsService { + static final ContactsService _singleton = ContactsService._internal(); + ContactsService._internal(); + + factory ContactsService.getInstance() { + return _singleton; + } + final AtSignLogger _logger = AtSignLogger(Constants.namespace!); + + AtClient? atClient; + AtClientService? atClientService; + var atClientManager = AtClientManager.getInstance(); + static var atContactService = ContactService(); + + /// Fetch the current atsign contacts. + Future?> getContactList() { + return atContactService.fetchContacts(); + } + + /// Fetch the current atsign profile image + Future getCurrentAtsignProfileImage() async { + return atContactService.getContactDetails(atClientManager.atClient.getCurrentAtSign(), null).then((value) { + return value['image']; + }); + } + + /// Fetch details for the current atsign + Future> getCurrentAtsignContactDetails() { + return atContactService.getContactDetails(atClientManager.atClient.getCurrentAtSign(), null); + } + + /// Delete contact from contact list. + Future addContact(String atSign, String? nickname) async { + try { + bool isAdded = await atContactService.addAtSign(atSign: atSign, nickName: nickname); + + return isAdded; + } on AtClientException catch (atClientExcep) { + _logger.severe('❌ AtClientException : ${atClientExcep.message}'); + return false; + } catch (e) { + _logger.severe('❌ Exception : ${e.toString()}'); + return false; + } + } + + /// Delete contact from contact list. + Future deleteContact(String atSign) async { + try { + bool isDeleted = await atContactService.deleteAtSign(atSign: atSign); + + return isDeleted; + } on AtClientException catch (atClientExcep) { + _logger.severe('❌ AtClientException : ${atClientExcep.message}'); + return false; + } catch (e) { + _logger.severe('❌ Exception : ${e.toString()}'); + return false; + } + } + + /// Add/remove contact as favorite. + Future markUnmarkFavoriteContact(AtContact contact) async { + try { + bool isMarked = await atContactService.markFavContact(contact); + + return isMarked; + } on AtClientException catch (atClientExcep) { + _logger.severe('❌ AtClientException : ${atClientExcep.message}'); + return false; + } catch (e) { + _logger.severe('❌ Exception : ${e.toString()}'); + return false; + } + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/view/settings_view.dart b/packages/dart/npt_flutter/lib/features/settings/view/settings_view.dart index e14efbeaa..38d7f6fd1 100644 --- a/packages/dart/npt_flutter/lib/features/settings/view/settings_view.dart +++ b/packages/dart/npt_flutter/lib/features/settings/view/settings_view.dart @@ -1,14 +1,24 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:npt_flutter/features/logging/logging.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/settings/settings.dart'; +import 'package:npt_flutter/features/settings/widgets/advance_section.dart'; +import 'package:npt_flutter/features/settings/widgets/contact_list_tile.dart'; +import 'package:npt_flutter/features/settings/widgets/default_relay_section.dart'; +import 'package:npt_flutter/features/settings/widgets/language_section.dart'; +import 'package:npt_flutter/widgets/custom_card.dart'; +import 'package:npt_flutter/widgets/custom_text_button.dart'; import 'package:npt_flutter/widgets/spinner.dart'; +import '../../../styles/sizes.dart'; +import '../widgets/dashboard_section.dart'; + class SettingsView extends StatelessWidget { const SettingsView({super.key}); @override Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; return BlocBuilder( builder: (context, state) { if (state is SettingsInitial) { @@ -19,22 +29,62 @@ class SettingsView extends StatelessWidget { case SettingsLoading(): return const Spinner(); case SettingsLoadedState(): - return const Column(children: [ - SettingsErrorHint(), - Text("Default Relay"), - SettingsRelayAtSignTextField(), - SettingsRelayQuickButtons(), - SettingsOverrideRelaySwitch(), - SizedBox(height: 100), - Text("View Mode"), - SettingsViewLayoutSelector(), - Text("Advanced"), - Row(children: [ - Text("Enable Logging"), - EnableLogsBox(), - ExportLogsButton(), - ]), - ]); + return Padding( + padding: const EdgeInsets.only(top: 18, bottom: 92, left: 120, right: 77), + child: Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + left: Sizes.p192, + child: CustomCard.settingsContent( + child: Padding( + padding: const EdgeInsets.only( + left: Sizes.p43, + right: Sizes.p33, + top: Sizes.p28, + ), + child: ListView(children: const [ + SettingsErrorHint(), + DefaultRelaySection(), + gapH25, + DashboardSection(), + gapH25, + AdvanceSection(), + gapH25, + LanguageSection(), + ]), + ), + ), + ), + const Positioned( + left: 0, + child: CustomCard.settingsRail( + child: Padding( + padding: EdgeInsets.all(0.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + gapH30, + CustomTextButton.discord(), + CustomTextButton.email(), + CustomTextButton.faq(), + CustomTextButton.privacyPolicy(), + CustomTextButton.feedback(), + CustomTextButton.backUpYourKey(), + CustomTextButton.resetAtsign(), + ContactListTile(), + ], + ), + ), + ), + ), + Positioned( + top: Sizes.p470, + child: Text(strings.allRightsReserved), + ), + ], + ), + ); } }, ); diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/advance_section.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/advance_section.dart new file mode 100644 index 000000000..6b8dbef78 --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/advance_section.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import '../../../styles/sizes.dart'; +import '../../../widgets/custom_container.dart'; +import '../../logging/widgets/enable_logs_box.dart'; +import '../../logging/widgets/export_logs_button.dart'; + +class AdvanceSection extends StatelessWidget { + const AdvanceSection({super.key}); + + @override + Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; + return Column( + children: [ + Row( + children: [ + const Icon(Icons.apps), + gapW4, + Text(strings.advanced), + ], + ), + gapH16, + CustomContainer.background( + child: Column( + children: [ + Row(children: [ + Text(strings.enableLogging), + const EnableLogsBox(), + gapW20, + const ExportLogsButton(), + ]), + ], + ), + ), + ], + ); + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/contact_list_tile.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/contact_list_tile.dart new file mode 100644 index 000000000..336eba6b2 --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/contact_list_tile.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; + +import '../../../styles/app_color.dart'; +import '../../../styles/sizes.dart'; +import '../repository/contact_repository.dart'; + +class ContactListTile extends StatelessWidget { + const ContactListTile({super.key}); + + @override + Widget build(BuildContext context) { + SizeConfig().init(context); + final contactRepo = ContactsService.getInstance(); + + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; + return FutureBuilder( + future: contactRepo.getCurrentAtsignContactDetails(), + builder: ((context, snapshot) { + if (snapshot.hasData) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 13.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(Sizes.p10), + color: AppColor.cardColorDark, + ), + child: ListTile( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(Sizes.p8.toFont), + ), + leading: CircleAvatar( + radius: Sizes.p18.toFont, + backgroundColor: AppColor.primaryColor, + backgroundImage: snapshot.data!['image'] != null ? MemoryImage(snapshot.data!['image']) : null, + ), + title: Text( + snapshot.data?['name'] ?? '', + style: bodyMedium.copyWith(fontSize: 8.toFont), + ), + subtitle: Text( + contactRepo.atClientManager.atClient.getCurrentAtSign() ?? '', + style: bodySmall.copyWith(fontSize: 8.toFont), + )), + ), + ); + } else { + return const ListTile( + leading: CircleAvatar( + child: Icon(Icons.person), + ), + title: Text('No Name'), + subtitle: Text('No Atsign'), + ); + } + })); + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/dashboard_section.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/dashboard_section.dart new file mode 100644 index 000000000..77613476a --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/dashboard_section.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../styles/sizes.dart'; +import '../../../widgets/custom_container.dart'; +import '../settings.dart'; + +class DashboardSection extends StatelessWidget { + const DashboardSection({super.key}); + + @override + Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; + return Column( + children: [ + Row( + children: [ + SvgPicture.asset('assets/list_dashes.svg'), + gapW4, + Text(strings.dashboardView), + ], + ), + gapH16, + const CustomContainer.background( + child: SettingsDashboardLayoutSelector(), + ), + ], + ); + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/default_relay_section.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/default_relay_section.dart new file mode 100644 index 000000000..ceb9b9fb4 --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/default_relay_section.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../../styles/sizes.dart'; +import '../../../widgets/custom_container.dart'; +import 'settings_override_relay_switch.dart'; +import 'settings_relay_quick_buttons.dart'; + +class DefaultRelaySection extends StatelessWidget { + const DefaultRelaySection({super.key}); + + @override + Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; + return Column( + children: [ + Row( + children: [ + SvgPicture.asset('assets/radio_button.svg'), + gapW4, + Text(strings.defaultRelaySelection), + ], + ), + gapH16, + const CustomContainer.background( + child: SettingsRelayQuickButtons(), + ), + gapH13, + const CustomContainer.background( + child: SettingsOverrideRelaySwitch(), + ) + ], + ); + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/language_section.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/language_section.dart new file mode 100644 index 000000000..eff42c1e3 --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/language_section.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:npt_flutter/features/settings/widgets/settings_language_selector.dart'; + +import '../../../styles/sizes.dart'; +import '../../../widgets/custom_container.dart'; + +class LanguageSection extends StatelessWidget { + const LanguageSection({super.key}); + + @override + Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; + return Column( + children: [ + Row( + children: [ + const Icon(Icons.public_outlined), + gapW4, + Text(strings.language), + ], + ), + gapH16, + const CustomContainer.background( + child: SettingsLanguageSelector(), + ), + ], + ); + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_action_button.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_action_button.dart new file mode 100644 index 000000000..93119b923 --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_action_button.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:npt_flutter/styles/app_color.dart'; + +import '../../../styles/sizes.dart'; + +class SettingsActionButton extends StatelessWidget { + const SettingsActionButton({ + required this.icon, + required this.title, + required this.onTap, + super.key, + }); + + final IconData icon; + final String title; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + return Container( + width: 300, + height: 60, + decoration: BoxDecoration(color: AppColor.primaryColor, borderRadius: BorderRadius.circular(10)), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: Sizes.p12), + child: ListTile( + leading: Icon( + icon, + color: Colors.white, + ), + title: Text( + title, + style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 18, color: Colors.white), + ), + onTap: onTap, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + ), + ), + ); + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_dashboard_layout_selector.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_dashboard_layout_selector.dart new file mode 100644 index 000000000..37fc46f7d --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_dashboard_layout_selector.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:npt_flutter/features/settings/settings.dart'; +import 'package:npt_flutter/styles/sizes.dart'; +import 'package:npt_flutter/widgets/spinner.dart'; + +import '../../../widgets/custom_card.dart'; + +class SettingsDashboardLayoutSelector extends StatelessWidget { + const SettingsDashboardLayoutSelector({ + super.key, + }); + + @override + Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; + return BlocSelector(selector: (state) { + if (state is SettingsLoadedState) { + return state.settings.viewLayout; + } + return null; + }, builder: (context, viewLayout) { + if (viewLayout == null) return const Spinner(); + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(getPreferredViewLayoutText(context, PreferredViewLayout.minimal)), + gapW20, + Switch( + value: viewLayout == PreferredViewLayout.minimal ? false : true, + onChanged: (value) { + var bloc = context.read(); + bloc.add(SettingsEditEvent( + settings: (bloc.state as SettingsLoadedState).settings.copyWith( + viewLayout: value == false ? PreferredViewLayout.minimal : PreferredViewLayout.sshStyle), + save: true, + )); + }, + ), + gapW20, + Text(getPreferredViewLayoutText(context, PreferredViewLayout.sshStyle)), + ], + ), + gapH18, + CustomCard.settingsPreview( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + gapH13, + Padding( + padding: const EdgeInsets.only(left: Sizes.p20), + child: Align( + alignment: Alignment.centerLeft, + child: Text(strings.preview), + ), + ), + gapH10, + viewLayout == PreferredViewLayout.minimal + ? SvgPicture.asset('assets/simple.svg') + : SvgPicture.asset('assets/advance.svg'), + gapH16, + ], + )) + ], + ); + }); + } +} + +String getPreferredViewLayoutText(BuildContext context, PreferredViewLayout preferredViewLayout) { + final strings = AppLocalizations.of(context)!; + switch (preferredViewLayout) { + case PreferredViewLayout.minimal: + return strings.minimal; + case PreferredViewLayout.sshStyle: + return strings.sshStyle; + } +} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_language_selector.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_language_selector.dart new file mode 100644 index 000000000..f383e491b --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_language_selector.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:npt_flutter/features/settings/settings.dart'; +import 'package:npt_flutter/widgets/spinner.dart'; + +class SettingsLanguageSelector extends StatelessWidget { + const SettingsLanguageSelector({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BlocSelector(selector: (state) { + if (state is SettingsLoadedState) { + return state.settings.language; + } + return null; + }, builder: (context, language) { + if (language == null) return const Spinner(); + return Column( + children: [ + Row( + children: [ + // Text(PreferredViewLayout.minimal.displayName), + // gapW20, + DropdownMenu( + initialSelection: language, + dropdownMenuEntries: Language.values + .map>( + (Language l) => DropdownMenuEntry( + value: l, + label: l.displayName, + ), + ) + .toList(), + onSelected: (value) { + if (value == null) return; + var bloc = context.read(); + bloc.add(SettingsEditEvent( + settings: (bloc.state as SettingsLoadedState).settings.copyWith(language: value), + save: true, + )); + }, + ), + ], + ), + ], + ); + }); + } +} + +var a = [1, 2, 3, 4, 5].map((e) => e * 2).toList(); diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_override_relay_switch.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_override_relay_switch.dart index b6ff09503..899119a42 100644 --- a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_override_relay_switch.dart +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_override_relay_switch.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/settings/settings.dart'; import 'package:npt_flutter/widgets/spinner.dart'; @@ -10,6 +11,7 @@ class SettingsOverrideRelaySwitch extends StatelessWidget { @override Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; return BlocSelector(selector: (state) { if (state is SettingsLoadedState) { return state.settings.overrideRelay; @@ -17,18 +19,22 @@ class SettingsOverrideRelaySwitch extends StatelessWidget { return null; }, builder: (context, overrideRelay) { if (overrideRelay == null) return const Spinner(); - return SwitchListTile( - title: const Text("Global Relay Override"), - value: overrideRelay, - onChanged: (value) { - var bloc = context.read(); - bloc.add(SettingsEditEvent( - settings: (bloc.state as SettingsLoadedState) - .settings - .copyWith(overrideRelay: value), - save: true, - )); - }, + return Row( + children: [ + Checkbox( + value: overrideRelay, + onChanged: (value) { + var bloc = context.read(); + bloc.add(SettingsEditEvent( + settings: (bloc.state as SettingsLoadedState).settings.copyWith(overrideRelay: value), + save: true, + )); + }, + ), + Text( + strings.overrideAllProfile, + ), + ], ); }); } diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_at_sign_text_field.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_at_sign_text_field.dart index a29941cae..6630a3867 100644 --- a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_at_sign_text_field.dart +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_at_sign_text_field.dart @@ -1,51 +1,47 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/settings/settings.dart'; class SettingsRelayAtSignTextField extends StatefulWidget { const SettingsRelayAtSignTextField({super.key}); @override - State createState() => - _SettingsRelayAtSignTextFieldState(); + State createState() => _SettingsRelayAtSignTextFieldState(); } -class _SettingsRelayAtSignTextFieldState - extends State { +class _SettingsRelayAtSignTextFieldState extends State { final TextEditingController controller = TextEditingController(); @override Widget build(BuildContext context) { - return Row( - children: [ - const SizedBox(width: 200, child: Text("Relay atSign")), - Expanded( - child: BlocSelector( - selector: (SettingsState state) { - if (state is SettingsLoadedState) { - return state.settings.relayAtsign; + final strings = AppLocalizations.of(context)!; + return BlocSelector( + selector: (SettingsState state) { + if (state is SettingsLoadedState) { + return state.settings.relayAtsign; + } + return null; + }, + builder: (BuildContext context, String? relayAtsign) { + if (relayAtsign == null) return const SizedBox(); + controller.text = relayAtsign; + return TextFormField( + controller: controller, + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: (value) { + if (value == null || value.isEmpty || !value.startsWith('@')) { + return strings.invalidRelayAtsignMsg; } return null; }, - builder: (BuildContext context, String? relayAtsign) { - if (relayAtsign == null) return const SizedBox(); - controller.text = relayAtsign; - return Column(children: [ - TextFormField( - controller: controller, - onChanged: (value) { - var bloc = context.read(); - bloc.add(SettingsEditEvent( - settings: (bloc.state as SettingsLoadedState) - .settings - .copyWith(relayAtsign: value), - save: true, - )); - }), - ]); - }, - ), - ), - ], + onChanged: (value) { + var bloc = context.read(); + bloc.add(SettingsEditEvent( + settings: (bloc.state as SettingsLoadedState).settings.copyWith(relayAtsign: value), + save: true, + )); + }); + }, ); } } diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_quick_buttons.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_quick_buttons.dart index b7622d083..9bcfbb0d1 100644 --- a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_quick_buttons.dart +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_relay_quick_buttons.dart @@ -2,45 +2,60 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:npt_flutter/constants.dart'; import 'package:npt_flutter/features/settings/settings.dart'; +import 'package:npt_flutter/widgets/custom_container.dart'; + +import '../../../styles/sizes.dart'; class SettingsRelayQuickButtons extends StatelessWidget { const SettingsRelayQuickButtons({super.key}); @override Widget build(BuildContext context) { - return BlocSelector( - selector: (SettingsState state) { + final ScrollController controller = ScrollController(); + return BlocSelector(selector: (SettingsState state) { if (state is SettingsLoadedState) { return state.settings.relayAtsign; } return null; }, builder: (BuildContext context, String? relayAtsign) { if (relayAtsign == null) return const SizedBox(); - return Row( - children: [ - const SizedBox(width: 200), - const Text('Populate Relay atSign with a preset:'), - ...Constants.defaultRelayOptions.entries.map( - (e) => SizedBox( - key: Key(e.key), - width: 200, - child: RadioListTile( - title: Text(e.value), - value: e.key, - groupValue: relayAtsign, - onChanged: (value) { - var bloc = context.read(); - bloc.add(SettingsEditEvent( - settings: (bloc.state as SettingsLoadedState) - .settings - .copyWith(relayAtsign: value), - save: true, - )); - }, + return Scrollbar( + controller: controller, + thumbVisibility: true, + child: Container( + padding: const EdgeInsets.only(bottom: Sizes.p20), + height: Sizes.p70, + child: ListView( + controller: controller, + scrollDirection: Axis.horizontal, + children: [ + ...Constants.defaultRelayOptions.entries.map( + (e) => Padding( + padding: const EdgeInsets.only(right: Sizes.p10), + child: CustomContainer.foreground( + key: Key(e.key), + child: SizedBox( + width: Sizes.p180, + child: RadioListTile( + title: Text(e.value), + value: e.key, + groupValue: relayAtsign, + onChanged: (value) { + var bloc = context.read(); + bloc.add(SettingsEditEvent( + settings: (bloc.state as SettingsLoadedState).settings.copyWith(relayAtsign: value), + save: true, + )); + }, + ), + ), + ), + ), ), - ), + const SettingsRelayAtSignTextField(), + ], ), - ], + ), ); }); } diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_switch_atsign_action.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_switch_atsign_action.dart new file mode 100644 index 000000000..f4ad0ee7e --- /dev/null +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_switch_atsign_action.dart @@ -0,0 +1,152 @@ +// import 'package:at_common_flutter/services/size_config.dart'; +// import 'package:at_contact/at_contact.dart'; +// import 'package:at_contacts_flutter/widgets/circular_contacts.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +// import 'package:flutter_riverpod/flutter_riverpod.dart'; +// import 'package:npt_flutter/app.dart'; +// import 'package:sshnp_flutter/src/controllers/authentication_controller.dart'; +// import 'package:sshnp_flutter/src/presentation/widgets/settings_screen_widgets/settings_actions/settings_action_button.dart'; +// import 'package:sshnp_flutter/src/presentation/widgets/utility/custom_snack_bar.dart'; +// import 'package:sshnp_flutter/src/repository/authentication_repository.dart'; +// import 'package:sshnp_flutter/src/repository/navigation_repository.dart'; +// import 'package:sshnp_flutter/src/utility/constants.dart'; + +// class SettingsSwitchAtsignAction extends StatelessWidget { +// const SettingsSwitchAtsignAction({super.key}); + +// @override +// Widget build(BuildContext context) { +// final strings = AppLocalizations.of(context)!; +// return SettingsActionButton( +// icon: Icons.logout_rounded, +// title: strings.switchAtsign, +// onTap: () async { +// await showModalBottomSheet( +// context: App.navState .currentContext!, +// builder: (context) => const SwitchAtSignBottomSheet()); +// }, +// ); +// } +// } + +// class SwitchAtSignBottomSheet extends ConsumerStatefulWidget { +// const SwitchAtSignBottomSheet({super.key}); + +// @override +// ConsumerState createState() => _AtSignBottomSheetState(); +// } + +// class _AtSignBottomSheetState extends ConsumerState { +// bool isLoading = false; + +// @override +// void initState() { +// ref.read(authenticationController.notifier).getAtSignList(); + +// super.initState(); +// } + +// @override +// Widget build(BuildContext context) { +// final state = ref.watch(authenticationController); +// final strings = AppLocalizations.of(context)!; +// SizeConfig().init(context); +// return Stack( +// children: [ +// Positioned( +// child: BottomSheet( +// onClosing: () {}, +// backgroundColor: Colors.transparent, +// builder: (context) => ClipRRect( +// borderRadius: const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)), +// child: Container( +// height: 155.toHeight < 155 ? 155 : 150.toHeight, +// width: SizeConfig().screenWidth, +// color: kBackGroundColorDark, +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Padding( +// padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), +// child: Text( +// strings.switchAtsign, +// ), +// ), +// Container( +// height: 100.toHeight < 105 ? 110 : 100.toHeight, +// width: MediaQuery.of(context).size.width, +// color: kBackGroundColorDark, +// child: state.isLoading +// ? const CircularProgressIndicator() +// : Row( +// children: [ +// Expanded( +// child: ListView.builder( +// scrollDirection: Axis.horizontal, +// itemCount: ref.watch(authenticationController).value!.length, +// itemBuilder: (context, index) { +// return FutureBuilder( +// future: ref +// .watch(authenticationController.notifier) +// .getAtContact(state.value![index]) +// .then((value) => value), +// builder: ((context, snapshot) { +// if (snapshot.hasData) { +// return GestureDetector( +// onTap: isLoading +// ? () {} +// : () async { +// Navigator.pop(context); +// ref +// .watch(authenticationRepositoryProvider) +// .handleSwitchAtsign(state.value![index]); +// }, +// child: FittedBox( +// child: CircularContacts(contact: snapshot.data as AtContact), +// ), +// ); +// } else if (!snapshot.hasData) { +// return const CircularProgressIndicator(); +// } else { +// CustomSnackBar.error(content: strings.error); +// return const SizedBox(); +// } +// })); +// }, +// )), +// const SizedBox( +// width: 20, +// ), +// GestureDetector( +// onTap: () async { +// setState(() { +// isLoading = true; +// Navigator.pop(context); +// }); +// ref.watch(authenticationRepositoryProvider).handleSwitchAtsign(null); + +// setState(() { +// isLoading = false; +// }); +// }, +// child: Container( +// margin: const EdgeInsets.only(right: 10), +// height: 40, +// width: 40, +// child: Icon(Icons.add_circle_outline_outlined, size: 25.toFont), +// ), +// ) +// ], +// ), +// ), +// ], +// ), +// ), +// ), +// ), +// ), +// ], +// ); +// } +// } diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_view_layout_selector.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/settings_view_layout_selector.dart deleted file mode 100644 index 6fd495873..000000000 --- a/packages/dart/npt_flutter/lib/features/settings/widgets/settings_view_layout_selector.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:npt_flutter/features/settings/settings.dart'; -import 'package:npt_flutter/widgets/spinner.dart'; - -class SettingsViewLayoutSelector extends StatelessWidget { - const SettingsViewLayoutSelector({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return BlocSelector( - selector: (state) { - if (state is SettingsLoadedState) { - return state.settings.viewLayout; - } - return null; - }, builder: (context, viewLayout) { - if (viewLayout == null) return const Spinner(); - return Column( - children: PreferredViewLayout.values - .map((e) => RadioListTile( - title: Text(e.displayName), - value: e, - groupValue: viewLayout, - onChanged: (value) { - var bloc = context.read(); - bloc.add(SettingsEditEvent( - settings: (bloc.state as SettingsLoadedState) - .settings - .copyWith(viewLayout: value), - save: true, - )); - }, - )) - .toList(), - ); - }); - } -} diff --git a/packages/dart/npt_flutter/lib/features/settings/widgets/widgets.dart b/packages/dart/npt_flutter/lib/features/settings/widgets/widgets.dart index 8f43a8ee7..550921816 100644 --- a/packages/dart/npt_flutter/lib/features/settings/widgets/widgets.dart +++ b/packages/dart/npt_flutter/lib/features/settings/widgets/widgets.dart @@ -1,5 +1,5 @@ +export 'settings_dashboard_layout_selector.dart'; export 'settings_error_hint.dart'; export 'settings_override_relay_switch.dart'; export 'settings_relay_at_sign_text_field.dart'; export 'settings_relay_quick_buttons.dart'; -export 'settings_view_layout_selector.dart'; diff --git a/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.dart b/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.dart index 238f63fc5..ceebbeaa3 100644 --- a/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.dart +++ b/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.dart @@ -12,11 +12,10 @@ import 'package:npt_flutter/routes.dart'; import 'package:tray_manager/tray_manager.dart'; import 'package:window_manager/window_manager.dart'; -part 'tray_state.dart'; part 'tray_cubit.g.dart'; +part 'tray_state.dart'; -(String, void Function(MenuItem)) getAction(TrayAction action) => - switch (action) { +(String, void Function(MenuItem)) getAction(TrayAction action) => switch (action) { TrayAction.showDashboard => ('Show Window', (_) => windowManager.focus()), TrayAction.showSettings => ( 'Settings', @@ -51,13 +50,13 @@ enum TrayAction { quitApp; static bool isTrayAction(String key) { - return _$TrayActionsEnumMap.values.contains(key); + return _$TrayActionEnumMap.values.contains(key); } MenuItem get menuItem { final (label, callback) = getAction(this); return MenuItem( - key: _$TrayActionsEnumMap[this], + key: _$TrayActionEnumMap[this], label: label, onClick: callback, ); diff --git a/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.g.dart b/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.g.dart index 2e530784a..f793de004 100644 --- a/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.g.dart +++ b/packages/dart/npt_flutter/lib/features/tray_manager/cubit/tray_cubit.g.dart @@ -6,7 +6,7 @@ part of 'tray_cubit.dart'; // JsonSerializableGenerator // ************************************************************************** -const _$TrayActionsEnumMap = { +const _$TrayActionEnumMap = { TrayAction.showDashboard: 'showDashboard', TrayAction.showSettings: 'showSettings', TrayAction.quitApp: 'quitApp', diff --git a/packages/dart/npt_flutter/lib/localization/app_en.arb b/packages/dart/npt_flutter/lib/localization/app_en.arb new file mode 100644 index 000000000..a799c6b98 --- /dev/null +++ b/packages/dart/npt_flutter/lib/localization/app_en.arb @@ -0,0 +1,29 @@ +{ + "advanced": "Advanced", + "allRightsReserved":"@ 2024 Atsign, All Rights Reserved", + "americas" : "Americas", + "asiaPacific" : "Asia-Pacific", + "backupYourKey" : "Backup Your Key", + "back" : "Back", + "dashboardView" : "Dashboard View", + "defaultRelaySelection" : "Default Relay Selection", + "discord" : "Discord", + "email" : "Email", + "enableLogging" : "Enable Logging", + "europe" : "Europe", + "exportLogs" : "Export Logs", + "faq" : "faq", + "feedback" : "Feedback", + "invalidRelayAtsignMsg" : "Please enter a valid atsign", + "language" : "Language", + "logs" : "Logs", + "minimal" : "Simple", + "noPorts" : "NoPorts", + "overrideAllProfile":"Override all profiles with default relay selection", + "preview" : "Preview", + "privacyPolicy" : "Privacy Policy", + "resetAtsign" : "Reset Atsign", + "selectExportFile": "Please select a file to export to:", + "settings" : "Settings", + "sshStyle" : "Advanced" +} \ No newline at end of file diff --git a/packages/dart/npt_flutter/lib/localization/app_es.arb b/packages/dart/npt_flutter/lib/localization/app_es.arb new file mode 100644 index 000000000..759d0dbd2 --- /dev/null +++ b/packages/dart/npt_flutter/lib/localization/app_es.arb @@ -0,0 +1,29 @@ +{ + "advanced": "Avanzado", + "allRightsReserved":"@ 2024 Atsign, Todos los derechos reservados", + "americas" : "Américas", + "asiaPacific" : "Asia-Pacífico", + "backupYourKey" : "Respaldar tu clave", + "back" : "Atrás", + "dashboardView" : "Vista del panel de control", + "defaultRelaySelection" : "Selección de relé predeterminada", + "discord" : "Discord", + "email" : "Correo electrónico", + "enableLogging" : "Habilitar registro", + "europe" : "Europa", + "exportLogs" : "Exportar registros", + "faq" : "Preguntas frecuentes", + "feedback" : "Comentarios", + "invalidRelayAtsignMsg" : "Por favor, ingresa un atsign válido", + "language" : "Idioma", + "logs" : "Registros", + "minimal" : "Simple", + "noPorts" : "Sin puertos", + "overrideAllProfile":"Anular todos los perfiles con la selección de relé predeterminada", + "preview" : "Vista previa", + "privacyPolicy" : "Política de privacidad", + "resetAtsign" : "Restablecer Atsign", + "selectExportFile": "Por favor, selecciona un archivo para exportar:", + "settings" : "Configuración", + "sshStyle" : "Avanzado" +} \ No newline at end of file diff --git a/packages/dart/npt_flutter/lib/localization/app_pt.arb b/packages/dart/npt_flutter/lib/localization/app_pt.arb new file mode 100644 index 000000000..8c4c012e4 --- /dev/null +++ b/packages/dart/npt_flutter/lib/localization/app_pt.arb @@ -0,0 +1,29 @@ +{ + "advanced": "Avançado", + "allRightsReserved":"@ 2024 Atsign, Todos os direitos reservados", + "americas" : "Américas", + "asiaPacific" : "Ásia-Pacífico", + "backupYourKey" : "Faça backup da sua chave", + "back" : "Voltar", + "dashboardView" : "Visualização do painel", + "defaultRelaySelection" : "Seleção de relé padrão", + "discord" : "Discord", + "email" : "Email", + "enableLogging" : "Ativar registro", + "europe" : "Europa", + "exportLogs" : "Exportar registros", + "faq" : "Perguntas frequentes", + "feedback" : "Feedback", + "invalidRelayAtsignMsg" : "Digite um atsign válido", + "language" : "Idioma", + "logs" : "Registros", + "minimal" : "Simples", + "noPorts" : "Sem portas", + "overrideAllProfile":"Substituir todos os perfis pela seleção de relé padrão", + "preview" : "Visualizar", + "privacyPolicy" : "Política de Privacidade", + "resetAtsign" : "Redefinir Atsign", + "selectExportFile": "Por favor, selecione um arquivo para exportar:", + "settings" : "Configurações", + "sshStyle" : "Avançado" +} \ No newline at end of file diff --git a/packages/dart/npt_flutter/lib/pages/settings_page.dart b/packages/dart/npt_flutter/lib/pages/settings_page.dart index 6d667b459..d6e4d138c 100644 --- a/packages/dart/npt_flutter/lib/pages/settings_page.dart +++ b/packages/dart/npt_flutter/lib/pages/settings_page.dart @@ -1,14 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/settings/settings.dart'; +import 'package:npt_flutter/styles/app_color.dart'; +import 'package:npt_flutter/widgets/npt_app_bar.dart'; class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; return Scaffold( - appBar: AppBar( - title: const Text("Settings"), + appBar: NptAppBar( + title: strings.settings, + settingsSelectedColor: AppColor.primaryColor, ), body: const SettingsView(), ); diff --git a/packages/dart/npt_flutter/lib/styles/app_color.dart b/packages/dart/npt_flutter/lib/styles/app_color.dart new file mode 100644 index 000000000..051979f4f --- /dev/null +++ b/packages/dart/npt_flutter/lib/styles/app_color.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class AppColor { + static const primaryColor = Color(0xFFF05E3E); + static const surfaceColor = Color(0xFFF2F2F2); + static const dividerColor = Color(0xFFC4C4C4); + static const onSurfaceColor = Color(0xFF747474); + static const cardColorDark = Color(0xFFEAEAEA); + static const textFieldBorderColor = Color(0xFFD9D9D9); +} diff --git a/packages/dart/npt_flutter/lib/styles/app_theme.dart b/packages/dart/npt_flutter/lib/styles/app_theme.dart new file mode 100644 index 000000000..3e543bcf1 --- /dev/null +++ b/packages/dart/npt_flutter/lib/styles/app_theme.dart @@ -0,0 +1,291 @@ +import 'package:flutter/material.dart'; +import 'package:npt_flutter/styles/app_color.dart'; +import 'package:npt_flutter/styles/sizes.dart'; + +class AppTheme { + static TextTheme lightTextTheme = const TextTheme( + titleMedium: TextStyle( + fontSize: Sizes.p18, + fontWeight: FontWeight.w600, + ), + bodyLarge: TextStyle( + fontSize: Sizes.p15, + fontWeight: FontWeight.w500, + ), + bodyMedium: TextStyle( + fontSize: Sizes.p15, + fontWeight: FontWeight.w500, + ), + bodySmall: TextStyle( + fontSize: Sizes.p11, + fontWeight: FontWeight.w400, + ), + // labelLarge: TextStyle( + // fontSize: 11, + // fontWeight: FontWeight.w500, + // ), + // labelMedium: TextStyle( + // fontSize: 11, + // fontWeight: FontWeight.w500, + // ), + // labelSmall: TextStyle( + // fontSize: 10, + // fontWeight: FontWeight.w400, + // ), + ); + + static TextTheme darkTextTheme = const TextTheme( + titleMedium: TextStyle( + fontSize: 32, + fontWeight: FontWeight.w600, + ), + titleSmall: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + headlineLarge: TextStyle( + fontSize: 22, + fontWeight: FontWeight.w600, + ), + bodyLarge: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + ), + bodyMedium: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + bodySmall: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w400, + ), + labelLarge: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + labelSmall: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w400, + ), + ); + + static ThemeData light() { + return ThemeData( + fontFamily: 'Poppins', + useMaterial3: true, + brightness: Brightness.light, + textTheme: lightTextTheme, + colorScheme: const ColorScheme.light().copyWith( + primary: AppColor.primaryColor, + surface: AppColor.surfaceColor, + onSurface: AppColor.onSurfaceColor, + surfaceTint: Colors.transparent), + appBarTheme: const AppBarTheme( + color: AppColor.surfaceColor, + foregroundColor: Colors.black, + surfaceTintColor: Colors.transparent, + ), + textButtonTheme: TextButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStateProperty.all( + AppColor.onSurfaceColor, + ), + textStyle: WidgetStateProperty.all( + const TextStyle( + // fontSize: Sizes.p12, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + iconButtonTheme: IconButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStateProperty.all( + AppColor.onSurfaceColor, + ), + ), + ), + iconTheme: const IconThemeData.fallback().copyWith( + color: AppColor.onSurfaceColor, + ), + checkboxTheme: CheckboxThemeData( + fillColor: WidgetStateProperty.resolveWith((states) => Colors.white), + checkColor: WidgetStateProperty.resolveWith( + (states) => AppColor.primaryColor, + ), + side: WidgetStateBorderSide.resolveWith( + (states) => const BorderSide( + color: AppColor.primaryColor, + width: Sizes.p2, + ), + ), + ), + inputDecorationTheme: const InputDecorationTheme().copyWith( + fillColor: const Color(0xFFF4F4F4), + filled: true, + constraints: const BoxConstraints(maxWidth: 179, maxHeight: 59.21), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + ), + ), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + disabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + errorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + focusedErrorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + ), + radioTheme: RadioThemeData( + fillColor: WidgetStateColor.resolveWith( + (states) { + return AppColor.primaryColor; + }, + ), + ), + dropdownMenuTheme: DropdownMenuThemeData( + inputDecorationTheme: const InputDecorationTheme().copyWith( + fillColor: const Color(0xE5FAFAFA), + filled: true, + constraints: const BoxConstraints(maxWidth: 179, maxHeight: 59.21), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + ), + ), + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + disabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + errorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + focusedErrorBorder: const OutlineInputBorder( + borderSide: BorderSide(color: AppColor.textFieldBorderColor, width: Sizes.p2), + borderRadius: BorderRadius.all( + Radius.circular(Sizes.p10), + )), + ), + )); + + // checkboxTheme: CheckboxThemeData( + // fillColor: WidgetStateColor.resolveWith( + // (states) { + // return Colors.black; + // }, + // ), + // ), + // floatingActionButtonTheme: const FloatingActionButtonThemeData( + // foregroundColor: Color(0xFFF8C630), + // backgroundColor: Colors.black, + // ), + // elevatedButtonTheme: ElevatedButtonThemeData( + // style: ButtonStyle( + // shape: WidgetStateProperty.all( + // RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(18.0), + // ), + // ), + // backgroundColor: WidgetStateProperty.all(const Color(0xFF12DE26)), + // foregroundColor: WidgetStateProperty.all(const Color(0xFFFFFFFF)), + // ), + // ), + // dialogTheme: const DialogTheme( + // surfaceTintColor: AppColor.primaryColor, + // ), + // cardTheme: CardTheme( + // elevation: 0, + // surfaceTintColor: AppColor.primaryColor, + // color: const Color(0xFFF4F4F4), + // shape: OutlineInputBorder( + // borderRadius: BorderRadius.circular(5), + // borderSide: BorderSide.none, + // ), + // ), + // navigationRailTheme: const NavigationRailThemeData( + // useIndicator: false, + // backgroundColor: AppColor.primaryColor, + // ), + // filledButtonTheme: FilledButtonThemeData( + // style: FilledButton.styleFrom( + // // foregroundColor: Colors.white, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(Sizes.p5), + // ), + // padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + // fixedSize: const Size(48, 43), + // ), + // ) + } + +// static ThemeData dark() { +// return ThemeData( +// visualDensity: VisualDensity.adaptivePlatformDensity, +// useMaterial3: true, +// checkboxTheme: CheckboxThemeData( +// fillColor: WidgetStateColor.resolveWith( +// (states) { +// return Colors.black; +// }, +// ), +// ), +// floatingActionButtonTheme: +// const FloatingActionButtonThemeData(foregroundColor: Colors.white, backgroundColor: AppColor.primaryColor), +// textTheme: darkTextTheme, +// elevatedButtonTheme: ElevatedButtonThemeData( +// style: ButtonStyle( +// shape: WidgetStateProperty.all( +// RoundedRectangleBorder( +// side: const BorderSide( +// width: 1, +// color: Color(0xFF707070), +// ), +// borderRadius: BorderRadius.circular(Sizes.p3), +// ), +// ), +// backgroundColor: WidgetStateProperty.all(const Color(0xFF2F2F2F)), +// foregroundColor: WidgetStateProperty.all(const Color(0xFF707070)), +// ), +// ), +// cardTheme: CardTheme( +// elevation: 0, +// surfaceTintColor: AppColor.primaryColor, +// color: const Color(0xFFF4F4F4), +// shape: OutlineInputBorder( +// borderRadius: BorderRadius.circular(5), +// borderSide: BorderSide.none, +// ), +// ), +// navigationRailTheme: const NavigationRailThemeData( +// useIndicator: false, +// backgroundColor: AppColor.primaryColor, +// ), +// appBarTheme: +// const AppBarTheme(backgroundColor: AppColor.primaryColor, systemOverlayStyle: SystemUiOverlayStyle.light), +// ); +// } +} diff --git a/packages/dart/npt_flutter/lib/styles/sizes.dart b/packages/dart/npt_flutter/lib/styles/sizes.dart new file mode 100644 index 000000000..5242657d8 --- /dev/null +++ b/packages/dart/npt_flutter/lib/styles/sizes.dart @@ -0,0 +1,215 @@ +import 'package:flutter/material.dart'; + +/// Constant sizes to be used in the app (paddings, gaps, rounded corners etc.) +class Sizes { + static const p2 = 2.0; + // static const p3 = 3.0; + static const p4 = 4.0; + // static const p5 = 5.0; + static const p8 = 8.0; + static const p10 = 10.0; + static const p11 = 11.0; + static const p12 = 12.0; + static const p13 = 13.0; + // static const p14 = 14.0; + static const p15 = 15.0; + static const p16 = 16.0; + static const p18 = 18.0; + static const p20 = 20.0; + // static const p21 = 21.0; + // static const p28 = 28.0; + // static const p24 = 24.0; + static const p25 = 25.0; + static const p27 = 27.0; + static const p28 = 28.0; + static const p30 = 30.0; + // static const p32 = 32.0; + static const p33 = 33.0; + // static const p34 = 34.0; + // static const p36 = 36.0; + static const p38 = 38.0; + static const p40 = 40.0; + // static const p46 = 46.0; + // static const p48 = 48.0; + static const p43 = 43.0; + static const p54 = 54.0; + static const p70 = 70.0; + // static const p99 = 99.0; + static const p100 = 100.0; + static const p108 = 108.0; + static const p150 = 150.0; + static const p175 = 175.0; + static const p177 = 177.0; + // static const p185 = 185.0; + static const p192 = 192.0; + static const p202 = 202.0; + static const p180 = 180.0; + // static const p244 = 244.0; + // static const p247 = 247.0; + // static const p286 = 286.0; + // static const p320 = 320.0; + static const p436 = 436.0; + static const p470 = 470.0; + static const p654 = 654.0; + static const p664 = 664.0; +} + +const gap0 = SizedBox(); + +/// Constant gap widths +const gapW4 = SizedBox(width: Sizes.p4); +// const gapW8 = SizedBox(width: Sizes.p8); +// const gapW12 = SizedBox(width: Sizes.p12); +// const gapW16 = SizedBox(width: Sizes.p16); +const gapW20 = SizedBox(width: Sizes.p20); +// const gapW24 = SizedBox(width: Sizes.p24); +const gapW27 = SizedBox(width: Sizes.p27); +// const gapW34 = SizedBox(width: Sizes.p34); +const gapW38 = SizedBox(width: Sizes.p38); +// const gapW48 = SizedBox(width: Sizes.p48); +// const gapW64 = SizedBox(width: Sizes.p64); + +// /// Constant gap heights +// const gapH4 = SizedBox(height: Sizes.p4); +// const gapH8 = SizedBox(height: Sizes.p8); +const gapH10 = SizedBox(height: Sizes.p10); +// const gapH12 = SizedBox(height: Sizes.p12); +const gapH13 = SizedBox(height: Sizes.p13); +// const gapH14 = SizedBox(height: Sizes.p14); +const gapH16 = SizedBox(height: Sizes.p16); +const gapH18 = SizedBox(height: Sizes.p18); +const gapH20 = SizedBox(height: Sizes.p20); +const gapH25 = SizedBox(height: Sizes.p25); +const gapH30 = SizedBox(height: Sizes.p30); +// const gapH32 = SizedBox(height: Sizes.p32); +// const gapH36 = SizedBox(height: Sizes.p36); +const gapH40 = SizedBox(height: Sizes.p40); +// const gapH46 = SizedBox(height: Sizes.p46); +// const gapH60 = SizedBox(height: Sizes.p60); +const gapH108 = SizedBox(height: Sizes.p108); + +const kWindowsMinWindowSize = Size(684, 541); + +/// A class defined to get dimensions for the screen size displayed, +/// using the proportion of the designed screen size. +class SizeConfig { + SizeConfig._(); + + static final SizeConfig _instance = SizeConfig._(); + + factory SizeConfig() => _instance; + late MediaQueryData _mediaQueryData; + late double screenWidth; + late double screenHeight; + late double blockSizeHorizontal; + late double blockSizeVertical; + late double deviceTextFactor; + + late double _safeAreaHorizontal; + late double _safeAreaVertical; + late double safeBlockHorizontal; + late double safeBlockVertical; + + double? profileDrawerWidth; + late double refHeight; + late double refWidth; + + double textFactor = 1.0; + + bool isMobile(BuildContext context) => MediaQuery.of(context).size.width < 700; + + bool isTablet(BuildContext context) => + MediaQuery.of(context).size.width >= 700 && MediaQuery.of(context).size.width < 1200; + bool isDesktop(BuildContext context) => MediaQuery.of(context).size.width >= 1200; + + void init(BuildContext context) { + _mediaQueryData = MediaQuery.of(context); + screenWidth = _mediaQueryData.size.width; + screenHeight = _mediaQueryData.size.height; + refHeight = 505; + refWidth = 671; + + deviceTextFactor = _mediaQueryData.textScaler.scale(20) / 20; + + // print("height is::: $screenHeight"); + + if (screenHeight < 1200) { + blockSizeHorizontal = screenWidth / 100; + blockSizeVertical = screenHeight / 100; + + _safeAreaHorizontal = _mediaQueryData.padding.left + _mediaQueryData.padding.right; + _safeAreaVertical = _mediaQueryData.padding.top + _mediaQueryData.padding.bottom; + safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100; + safeBlockVertical = (screenHeight - _safeAreaVertical) / 100; + } else { + blockSizeHorizontal = screenWidth / 120; + blockSizeVertical = screenHeight / 120; + + _safeAreaHorizontal = _mediaQueryData.padding.left + _mediaQueryData.padding.right; + _safeAreaVertical = _mediaQueryData.padding.top + _mediaQueryData.padding.bottom; + safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 120; + safeBlockVertical = (screenHeight - _safeAreaVertical) / 120; + } + if (screenWidth > 700) { + textFactor = 0.8; + } + } + + double getWidthRatio(double val) { + // if (screenWidth >= 1200 || (Platform.isLinux || Platform.isMacOS || Platform.isWindows)) { + // return val; + // } + double res = (val / refWidth) * 100; + double temp = res * blockSizeHorizontal; + // print("width$temp"); + + return temp; + } + + double getHeightRatio(double val) { + // if (screenWidth >= 1200 || (Platform.isLinux || Platform.isMacOS || Platform.isWindows)) { + // return val; + // } + double res = (val / refHeight) * 100; + double temp = res * blockSizeVertical; + return temp; + } + + double getFontRatio(double val) { + // if (screenWidth >= 1200 || (Platform.isLinux || Platform.isMacOS || Platform.isWindows)) { + // return val; + // } + double res = (val / refWidth) * 100; + double temp = 0.0; + if (screenWidth > screenHeight) { + temp = res * safeBlockHorizontal + (val * 0.150521609538003) * textFactor; + } else { + temp = res * safeBlockVertical + (val * 0.2473919523099851) * textFactor; + } + // print('$val,$temp,$refHeight,$refWidth'); + final maxSize = val + Sizes.p4; + if (temp > maxSize) { + return maxSize; + } else { + return temp; + } + + // var heightScale = (_mediaQueryData.size.height / refHeight); + // var widthScale = (_mediaQueryData.size.width / refWidth); + + // if (_mediaQueryData.size.height > refHeight || _mediaQueryData.size.width > refWidth) { + // heightScale = heightScale * 0.9; + // widthScale = widthScale * 0.9; + // } + // return val * heightScale * widthScale; + } +} + +/// A shorthand usage of the functions defined in [SizeConfig]. +extension SizeUtils on num { + double get toWidth => SizeConfig().getWidthRatio(toDouble()); + + double get toHeight => SizeConfig().getHeightRatio(toDouble()); + + double get toFont => SizeConfig().getFontRatio(toDouble()); +} diff --git a/packages/dart/npt_flutter/lib/styles/style_constants.dart b/packages/dart/npt_flutter/lib/styles/style_constants.dart new file mode 100644 index 000000000..fdbbbd2b9 --- /dev/null +++ b/packages/dart/npt_flutter/lib/styles/style_constants.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:npt_flutter/styles/sizes.dart'; + +import 'app_color.dart'; + +class StyleConstants { + static ButtonStyle backButtonStyle = TextButton.styleFrom( + foregroundColor: AppColor.primaryColor, + textStyle: const TextStyle(fontSize: Sizes.p18), + ); +} diff --git a/packages/dart/npt_flutter/lib/util/form_validator.dart b/packages/dart/npt_flutter/lib/util/form_validator.dart new file mode 100644 index 000000000..5847cf61f --- /dev/null +++ b/packages/dart/npt_flutter/lib/util/form_validator.dart @@ -0,0 +1,70 @@ +import 'dart:developer'; + +class FormValidator { + static const kEmptyFieldValidationError = 'Field cannot be left blank'; + static const kAtsignFieldValidationError = 'Field must start with @'; + static const kProfileNameFieldValidationError = 'Field must only use lower case alphanumeric characters and spaces'; + static const kPrivateKeyFieldValidationError = 'Field must only use lower case alphanumeric characters'; + static const kIntFieldValidationError = 'Field must only use numbers'; + static const kPortFieldValidationError = 'Field must use a valid port number'; + static const kPrivateKeyDropDownOption = 'Create a new private key'; + static String? validateRequiredField(String? value) { + if (value?.isEmpty ?? true) { + return kEmptyFieldValidationError; + } + return null; + } + + static String? validateRequiredPortField(String? value) { + String valid = r'^[0-9]+$'; + if (value?.isEmpty ?? true) { + return kEmptyFieldValidationError; + } else if (!RegExp(valid).hasMatch(value!)) { + return kPortFieldValidationError; + } else if (!(int.parse(value) >= 0 && int.parse(value) <= 65535)) { + return kPortFieldValidationError; + } + return null; + } + + static String? validateAtsignField(String? value) { + if (value?.isEmpty ?? true) { + return kEmptyFieldValidationError; + } else if (!value!.startsWith('@')) { + return kAtsignFieldValidationError; + } + validateRequiredField(value); + return null; + } + + static String? validateProfileNameField(String? value) { + String invalid = '[^a-z0-9 ]'; + if (value?.isEmpty ?? true) { + return kEmptyFieldValidationError; + } else if (value!.contains(RegExp(invalid))) { + return kProfileNameFieldValidationError; + } + return null; + } + + static String? validatePrivateKeyField(String? value) { + String invalid = '[^a-z0-9_]'; + if (value?.isEmpty ?? true) { + return kEmptyFieldValidationError; + } else if (value! == kPrivateKeyDropDownOption) { + return kPrivateKeyFieldValidationError; + } else if (value.contains(RegExp(invalid))) { + return kPrivateKeyFieldValidationError; + } + return null; + } + + static String? validateMultiSelectStringField(List? value) { + if (value == null || value.isEmpty) { + log('value is empty'); + return kEmptyFieldValidationError; + } + + return null; + } +} diff --git a/packages/dart/npt_flutter/lib/widgets/custom_card.dart b/packages/dart/npt_flutter/lib/widgets/custom_card.dart new file mode 100644 index 000000000..bd22a66dc --- /dev/null +++ b/packages/dart/npt_flutter/lib/widgets/custom_card.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; + +import '../styles/app_color.dart'; +import '../styles/sizes.dart'; + +class CustomCard extends StatelessWidget { + const CustomCard({ + required this.child, + required this.height, + required this.width, + required this.color, + required this.radiusTopLeft, + required this.radiusTopRight, + required this.radiusBottomLeft, + required this.radiusBottomRight, + required this.leftPadding, + super.key, + }); + + const CustomCard.settingsRail({ + required this.child, + super.key, + }) : height = Sizes.p436, + width = Sizes.p202, + color = Colors.white, + radiusTopLeft = const Radius.circular(Sizes.p10), + radiusTopRight = const Radius.circular(Sizes.p10), + radiusBottomLeft = const Radius.circular(Sizes.p10), + radiusBottomRight = const Radius.circular(Sizes.p10), + leftPadding = 0; + + const CustomCard.settingsContent({ + required this.child, + super.key, + }) : height = Sizes.p436, + width = Sizes.p664, + color = AppColor.cardColorDark, + radiusTopLeft = Radius.zero, + radiusTopRight = const Radius.circular(Sizes.p20), + radiusBottomLeft = Radius.zero, + radiusBottomRight = const Radius.circular(Sizes.p20), + leftPadding = Sizes.p10; + + const CustomCard.settingsPreview({ + required this.child, + super.key, + }) : height = null, + width = null, + color = Colors.white, + radiusTopLeft = const Radius.circular(Sizes.p20), + radiusTopRight = const Radius.circular(Sizes.p20), + radiusBottomLeft = const Radius.circular(Sizes.p20), + radiusBottomRight = const Radius.circular(Sizes.p20), + leftPadding = Sizes.p10; + + final Widget child; + final double? height; + final double? width; + final Color color; + final Radius radiusTopLeft; + final Radius radiusTopRight; + final Radius radiusBottomLeft; + final Radius radiusBottomRight; + final double leftPadding; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.only( + topLeft: radiusTopLeft, + topRight: radiusTopRight, + bottomLeft: radiusBottomLeft, + bottomRight: radiusBottomRight, + ), + ), + height: height, + width: width, + child: Padding( + padding: EdgeInsets.only(left: leftPadding), + child: child, + ), + ); + } +} diff --git a/packages/dart/npt_flutter/lib/widgets/custom_container.dart b/packages/dart/npt_flutter/lib/widgets/custom_container.dart new file mode 100644 index 000000000..2e25c7c3e --- /dev/null +++ b/packages/dart/npt_flutter/lib/widgets/custom_container.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:npt_flutter/styles/app_color.dart'; + +import '../styles/sizes.dart'; + +class CustomContainer extends StatelessWidget { + const CustomContainer({ + required this.child, + required this.color, + required this.padding, + super.key, + }); + + const CustomContainer.background({required this.child, super.key}) + : color = AppColor.surfaceColor, + padding = Sizes.p16; + + const CustomContainer.foreground({required this.child, super.key}) + : color = Colors.white, + padding = 0; + + final Widget child; + final Color color; + final double padding; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(padding), + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(Sizes.p10), + ), + child: child, + ); + } +} diff --git a/packages/dart/npt_flutter/lib/widgets/custom_snack_bar.dart b/packages/dart/npt_flutter/lib/widgets/custom_snack_bar.dart new file mode 100644 index 000000000..98b97660a --- /dev/null +++ b/packages/dart/npt_flutter/lib/widgets/custom_snack_bar.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:npt_flutter/app.dart'; + +class CustomSnackBar { + static void error({ + required String content, + Duration duration = const Duration(seconds: 2), + }) { + final context = App.navState.currentContext!; + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + content, + textAlign: TextAlign.center, + ), + backgroundColor: Theme.of(context).colorScheme.error, + duration: duration, + )); + } + + static void success({ + required String content, + Duration duration = const Duration(seconds: 2), + }) { + final context = App.navState.currentContext!; + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + content, + textAlign: TextAlign.center, + ), + backgroundColor: const Color(0xffC4FF79), + duration: duration, + )); + } + + static void notification({ + required String content, + SnackBarAction? action, + Duration duration = const Duration(seconds: 2), + }) { + final context = App.navState.currentContext!; + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + content, + textAlign: TextAlign.center, + ), + action: action, + duration: duration, + // backgroundColor: kDataStorageColor, + )); + } +} diff --git a/packages/dart/npt_flutter/lib/widgets/custom_text_button.dart b/packages/dart/npt_flutter/lib/widgets/custom_text_button.dart new file mode 100644 index 000000000..454f4bfb7 --- /dev/null +++ b/packages/dart/npt_flutter/lib/widgets/custom_text_button.dart @@ -0,0 +1,196 @@ +import 'package:at_contacts_flutter/services/contact_service.dart'; +import 'package:at_onboarding_flutter/at_onboarding_flutter.dart'; +import 'package:at_onboarding_flutter/services/onboarding_service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:npt_flutter/constants.dart'; +import 'package:npt_flutter/routes.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../features/onboarding/onboarding.dart'; +import '../styles/sizes.dart'; +import 'custom_snack_bar.dart'; + +class CustomTextButton extends StatelessWidget { + const CustomTextButton({ + super.key, + required this.iconData, + required this.title, + required this.type, + }); + + const CustomTextButton.email({ + super.key, + }) : iconData = Icons.email_outlined, + title = 'Email', + type = CustomListTileType.email; + + const CustomTextButton.discord({ + super.key, + }) : iconData = Icons.discord, + title = 'Discord', + type = CustomListTileType.discord; + + const CustomTextButton.faq({ + super.key, + }) : iconData = Icons.help_center_outlined, + title = 'FAQ', + type = CustomListTileType.faq; + + const CustomTextButton.privacyPolicy({ + super.key, + }) : iconData = Icons.account_balance_wallet_outlined, + title = 'Privacy Policy', + type = CustomListTileType.privacyPolicy; + + // const CustomListTile.switchAtsign( + // {this.iconData = Icons.switch_account_outlined, + // this.title = 'Switch atsign', + // this.type = CustomListTileType.switchAtsign, + // super.key}); + + const CustomTextButton.backUpYourKey( + {this.iconData = Icons.bookmark_outline, + this.title = 'Back Up Your Keys', + this.type = CustomListTileType.backupYourKey, + super.key}); + + const CustomTextButton.resetAtsign( + {this.iconData = Icons.rotate_right, + this.title = 'Reset App', + this.type = CustomListTileType.resetAtsign, + super.key}); + + const CustomTextButton.feedback( + {this.iconData = Icons.feedback_outlined, + this.title = 'Feedback', + this.type = CustomListTileType.feedback, + super.key}); + + final IconData iconData; + final String title; + final CustomListTileType type; + + @override + Widget build(BuildContext context) { + // SizeConfig().init(context); + // final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + // final bodySmall = Theme.of(context).textTheme.bodySmall!; + final strings = AppLocalizations.of(context)!; + Future onTap() async { + switch (type) { + case CustomListTileType.email: + Uri emailUri = Uri( + scheme: 'mailto', + path: 'info@noports.com', + ); + if (!await launchUrl(emailUri)) { + CustomSnackBar.notification(content: 'No email client available'); + } + break; + case CustomListTileType.discord: + final Uri url = Uri.parse('https://discord.gg/atsign-778383211214536722'); + if (!await launchUrl(url)) { + throw Exception('Could not launch $url'); + } + break; + case CustomListTileType.faq: + final Uri url = Uri.parse('https://docs.noports.com/ssh-no-ports/faq'); + if (!await launchUrl(url)) { + throw Exception('Could not launch $url'); + } + break; + case CustomListTileType.privacyPolicy: + final Uri url = Uri.parse('https://atsign.com/privacy-policy/'); + if (!await launchUrl(url)) { + throw Exception('Could not launch $url'); + } + break; + // case CustomListTileType.switchAtsign: + // if (context.mounted) { + // await showModalBottomSheet(context: context, builder: (context) => const SwitchAtSignBottomSheet()); + // } + // break; + case CustomListTileType.backupYourKey: + if (context.mounted) { + BackupKeyWidget(atsign: ContactService().currentAtsign).showBackupDialog(context); + } + break; + case CustomListTileType.resetAtsign: + final futurePreference = await loadAtClientPreference(); + if (context.mounted) { + final result = await AtOnboarding.reset( + context: context, + config: AtOnboardingConfig( + atClientPreference: futurePreference, + rootEnvironment: RootEnvironment.Testing, + domain: Constants.rootDomain, + appAPIKey: Constants.appAPIKey, + ), + ); + final OnboardingService onboardingService = OnboardingService.getInstance(); + + if (context.mounted && result == AtOnboardingResetResult.success) { + onboardingService.setAtsign = null; + Navigator.of(context).pushNamed(Routes.onboarding); + } + } + break; + + case CustomListTileType.feedback: + final emailUri = Uri( + scheme: 'mailto', + path: 'info@noports.com', + query: 'subject=SSH No Ports Desktop Feedback', + ); + + if (!await launchUrl(emailUri)) { + CustomSnackBar.notification(content: 'No email client available'); + } + } + } + + String getTitle(AppLocalizations strings) { + switch (type) { + case CustomListTileType.email: + return strings.email; + case CustomListTileType.discord: + return strings.discord; + case CustomListTileType.faq: + return strings.faq; + case CustomListTileType.privacyPolicy: + return strings.privacyPolicy; + // case CustomListTileType.switchAtsign: + // return strings.switchAtsign; + case CustomListTileType.backupYourKey: + return strings.backupYourKey; + case CustomListTileType.resetAtsign: + return strings.resetAtsign; + case CustomListTileType.feedback: + return strings.feedback; + } + } + + return Padding( + padding: const EdgeInsets.only(left: Sizes.p30, right: Sizes.p30, bottom: Sizes.p10), + child: TextButton.icon( + label: Text(getTitle(strings)), + onPressed: onTap, + icon: Icon( + iconData, + ), + ), + ); + } +} + +enum CustomListTileType { + email, + discord, + faq, + privacyPolicy, + // switchAtsign, + backupYourKey, + resetAtsign, + feedback, +} diff --git a/packages/dart/npt_flutter/lib/widgets/npt_app_bar.dart b/packages/dart/npt_flutter/lib/widgets/npt_app_bar.dart new file mode 100644 index 000000000..158fe05ef --- /dev/null +++ b/packages/dart/npt_flutter/lib/widgets/npt_app_bar.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:npt_flutter/styles/app_color.dart'; +import 'package:npt_flutter/styles/style_constants.dart'; + +import '../styles/sizes.dart'; + +class NptAppBar extends StatelessWidget implements PreferredSizeWidget { + final String title; + final Color? settingsSelectedColor; + final bool isNavigateBack; + + const NptAppBar({super.key, required this.title, this.settingsSelectedColor, this.isNavigateBack = true}); + + @override + Size get preferredSize => Size.fromHeight(isNavigateBack ? Sizes.p150 : Sizes.p100); + + @override + Widget build(BuildContext context) { + final strings = AppLocalizations.of(context)!; + return AppBar( + titleSpacing: 0, + leading: gap0, + toolbarHeight: isNavigateBack ? Sizes.p150 : Sizes.p100, + title: Row( + children: [ + Column( + children: [ + gapH40, + SvgPicture.asset( + 'assets/noports_logo.svg', + height: Sizes.p54, + width: Sizes.p175, + ), + gapH25, + TextButton.icon( + onPressed: () { + Navigator.pop(context); + }, + label: Text( + strings.back, + ), + icon: const Icon( + Icons.arrow_back_ios, + ), + style: StyleConstants.backButtonStyle, + ), + ], + ), + gapW27, + Column( + children: [ + Container( + color: AppColor.dividerColor, + height: Sizes.p38, + width: Sizes.p2, + ), + gapH25 + ], + ), + gapW20, + Column( + children: [ + Text( + title, + ), + gapH25, + ], + ), + ], + ), + actions: [ + IconButton( + color: settingsSelectedColor, + icon: const Icon(Icons.settings_outlined), + onPressed: () { + Navigator.pushNamed(context, '/settings'); + }, + ), + ], + centerTitle: true, + ); + } +} diff --git a/packages/dart/npt_flutter/macos/Podfile.lock b/packages/dart/npt_flutter/macos/Podfile.lock index baec81b66..e47331eb8 100644 --- a/packages/dart/npt_flutter/macos/Podfile.lock +++ b/packages/dart/npt_flutter/macos/Podfile.lock @@ -87,4 +87,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.3 diff --git a/packages/dart/npt_flutter/macos/Runner.xcodeproj/project.pbxproj b/packages/dart/npt_flutter/macos/Runner.xcodeproj/project.pbxproj index b952adba9..5e69fcf9d 100644 --- a/packages/dart/npt_flutter/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/dart/npt_flutter/macos/Runner.xcodeproj/project.pbxproj @@ -195,7 +195,6 @@ 9611F019DC92910A8E1C7E57 /* Pods-RunnerTests.release.xcconfig */, E03BBBA6673398DB5AAF96F8 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -575,6 +574,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "SSH NPT"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -707,6 +707,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "SSH NPT"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -727,6 +728,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "SSH NPT"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", diff --git a/packages/dart/npt_flutter/macos/Runner/Base.lproj/MainMenu.xib b/packages/dart/npt_flutter/macos/Runner/Base.lproj/MainMenu.xib index 80e867a4e..202b19c1e 100644 --- a/packages/dart/npt_flutter/macos/Runner/Base.lproj/MainMenu.xib +++ b/packages/dart/npt_flutter/macos/Runner/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -13,7 +13,7 @@ - + @@ -330,14 +330,16 @@ - + - + + + diff --git a/packages/dart/npt_flutter/pubspec.lock b/packages/dart/npt_flutter/pubspec.lock index ad05964d2..47aa2f304 100644 --- a/packages/dart/npt_flutter/pubspec.lock +++ b/packages/dart/npt_flutter/pubspec.lock @@ -119,6 +119,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.11" + at_contact: + dependency: "direct main" + description: + name: at_contact + sha256: e1b8904116e6e0fcbc5627409bffe3b620417c62b76bbedc84b1f66acc28adfe + url: "https://pub.dev" + source: hosted + version: "3.0.8" + at_contacts_flutter: + dependency: "direct main" + description: + name: at_contacts_flutter + sha256: "530a5112e303fdf8ae26bfbe477112b14c16c8b35f7005ea4919f05584fa8dec" + url: "https://pub.dev" + source: hosted + version: "4.0.15" at_demo_data: dependency: transitive description: @@ -146,10 +162,10 @@ packages: at_onboarding_flutter: dependency: "direct main" description: - path: "/Users/chant/src/af/at_widgets/xc-npt-desktop-pin/packages/at_onboarding_flutter" + path: "/Users/curtlycritchlow/Documents/CCWC/clients/atsign/at_widgets/packages/at_onboarding_flutter" relative: false source: path - version: "6.1.7" + version: "6.1.8" at_persistence_secondary_server: dependency: transitive description: @@ -191,7 +207,7 @@ packages: source: hosted version: "1.0.0" at_utils: - dependency: transitive + dependency: "direct main" description: name: at_utils sha256: ec28600e4eec321ee5e22be051109fa7b2e94590dc51d9f957730c2540beb681 @@ -499,10 +515,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4" + sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "8.1.2" file_selector: dependency: transitive description: @@ -604,6 +620,11 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -612,6 +633,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.21" + flutter_slidable: + dependency: transitive + description: + name: flutter_slidable + sha256: "2c5611c0b44e20d180e4342318e1bbc28b0a44ad2c442f5df16962606fd3e8e3" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter @@ -638,14 +675,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: ddc16d34b0d74cb313986918c0f0885a7ba2fc24d8fb8419de75f0015144ccfe - url: "https://pub.dev" - source: hosted - version: "14.2.3" graphs: dependency: transitive description: @@ -703,7 +732,7 @@ packages: source: hosted version: "1.0.0+1" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf @@ -901,6 +930,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" path_provider: dependency: "direct main" description: @@ -1339,7 +1376,7 @@ packages: source: hosted version: "1.3.2" url_launcher: - dependency: transitive + dependency: "direct main" description: name: url_launcher sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" @@ -1410,6 +1447,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.7" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" vector_math: dependency: transitive description: diff --git a/packages/dart/npt_flutter/pubspec.yaml b/packages/dart/npt_flutter/pubspec.yaml index 9c6286775..bd88d8c09 100644 --- a/packages/dart/npt_flutter/pubspec.yaml +++ b/packages/dart/npt_flutter/pubspec.yaml @@ -28,40 +28,40 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 at_client_mobile: ^3.2.18 + at_contact: ^3.0.8 + at_contacts_flutter: ^4.0.15 at_onboarding_flutter: - path: "/Users/chant/src/af/at_widgets/xc-npt-desktop-pin/packages/at_onboarding_flutter" - # git: - # url: https://github.com/atsign-foundation/at_widgets.git - # ref: enrollment_screens - # path: packages/at_onboarding_flutter - path_provider: ^2.1.4 - tray_manager: ^0.2.3 - noports_core: - path: "../noports_core" + path: /Users/curtlycritchlow/Documents/CCWC/clients/atsign/at_widgets/packages/at_onboarding_flutter + at_utils: ^3.0.16 + cupertino_icons: ^1.0.8 equatable: ^2.0.5 + file_picker: ^8.1.2 + flutter: + sdk: flutter flutter_bloc: ^8.1.6 - socket_connector: ^2.2.0 - json_serializable: ^6.8.0 + flutter_svg: ^2.0.10+1 + flutter_localizations: + sdk: flutter + intl: any json_annotation: ^4.9.0 - uuid: ^3.0.7 + json_serializable: ^6.8.0 meta: ^1.15.0 - go_router: ^14.2.3 - file_picker: ^6.2.1 + noports_core: + path: ../noports_core + path_provider: ^2.1.4 + socket_connector: ^2.2.0 toml: ^0.16.0 + tray_manager: ^0.2.3 + url_launcher: ^6.3.0 + uuid: ^3.0.7 + window_manager: ^0.4.2 yaml: ^3.1.2 yaml_writer: ^2.0.0 - window_manager: ^0.4.2 dev_dependencies: + build_runner: ^2.4.12 flutter_test: sdk: flutter - build_runner: ^2.4.12 dependency_overrides: dartssh2: @@ -82,9 +82,9 @@ dependency_overrides: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - # The following section is specific to Flutter packages. flutter: + generate: true # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. @@ -92,20 +92,11 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - - assets/noports-icon32.png - - assets/noports-icon64.png - - assets/noports-icon256.png - - assets/noports-icon512.png - - assets/noports-icon32.ico - - assets/noports-icon64.ico - - assets/noports-icon256.ico - - assets/noports-icon512.ico + - assets/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images - # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package - # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a