diff --git a/.gitignore b/.gitignore index 29a3a50..1aad01c 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +.vscode/launch.json diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c47c8f9..06df719 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:icon="@mipmap/launcher_icon"> - - - - - + + + diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..7dbde7a Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 304732f..f88598c 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -1,12 +1,6 @@ - - - - - + + + diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000..6997da9 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000..db1c063 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000..4d65d1a Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000..6a8c6e7 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000..73ab19c Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/values-night-v31/styles.xml b/android/app/src/main/res/values-night-v31/styles.xml new file mode 100644 index 0000000..a3653cb --- /dev/null +++ b/android/app/src/main/res/values-night-v31/styles.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 06952be..dbc9ea9 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index cb1ef88..0d1fa8f 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges + + + \ No newline at end of file diff --git a/assets/svgs/stars.svg b/assets/svgs/stars.svg new file mode 100644 index 0000000..44f1cd6 --- /dev/null +++ b/assets/svgs/stars.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..520c391 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,36 @@ +PODS: + - Flutter (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - rive_common (0.0.1): + - Flutter + - sqflite (0.0.3): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - rive_common (from `.symlinks/plugins/rive_common/ios`) + - sqflite (from `.symlinks/plugins/sqflite/darwin`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + rive_common: + :path: ".symlinks/plugins/rive_common/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/darwin" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c + rive_common: 3a4c254c6e4db7e4b9e05daeb3d1f47ae4f7bf76 + sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 3f92503..4ee3136 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -10,10 +10,12 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 5C2EE584B9A724E8435C193E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E12F6E6515568AC3A9CAB8 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 99385EB80FFB8F83951CD960 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C57B89EFED82A46B010844DD /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,6 +44,11 @@ /* Begin PBXFileReference section */ 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 = ""; }; + 17C5EDB175A413C0FDC1D69F /* 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 = ""; }; + 1E4AACCDFC2761725567CDFF /* 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 = ""; }; + 21E12F6E6515568AC3A9CAB8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2B328B2B86BEE78E6D3CD43E /* 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 = ""; }; + 31852A14FF620EFA350E0F17 /* 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 = ""; }; 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 = ""; }; @@ -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 = ""; }; + C57B89EFED82A46B010844DD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E2BF8FC0A2C9D9FD027A5BA0 /* 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 = ""; }; + F35A4192C3412B7D3B1B7566 /* 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,12 +72,44 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5C2EE584B9A724E8435C193E /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CAC1575E11BFFDB7C6D581E4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 99385EB80FFB8F83951CD960 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 037A44915099CBA388781AA5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 21E12F6E6515568AC3A9CAB8 /* Pods_Runner.framework */, + C57B89EFED82A46B010844DD /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 2133A9A084A87C470A01FCF1 /* Pods */ = { + isa = PBXGroup; + children = ( + E2BF8FC0A2C9D9FD027A5BA0 /* Pods-Runner.debug.xcconfig */, + 1E4AACCDFC2761725567CDFF /* Pods-Runner.release.xcconfig */, + 2B328B2B86BEE78E6D3CD43E /* Pods-Runner.profile.xcconfig */, + 17C5EDB175A413C0FDC1D69F /* Pods-RunnerTests.debug.xcconfig */, + 31852A14FF620EFA350E0F17 /* Pods-RunnerTests.release.xcconfig */, + F35A4192C3412B7D3B1B7566 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -94,6 +136,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 2133A9A084A87C470A01FCF1 /* Pods */, + 037A44915099CBA388781AA5 /* Frameworks */, ); sourceTree = ""; }; @@ -128,8 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 24F5FBDAFA0B32CF47588BBD /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + CAC1575E11BFFDB7C6D581E4 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +191,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 46C04F9164EDBCCC9290D2CD /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + A213180F28D6A4977EA93C26 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -222,6 +270,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 24F5FBDAFA0B32CF47588BBD /* [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; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -238,6 +308,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 46C04F9164EDBCCC9290D2CD /* [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; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -253,6 +345,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A213180F28D6A4977EA93C26 /* [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; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +488,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 17C5EDB175A413C0FDC1D69F /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +506,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 31852A14FF620EFA350E0F17 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +522,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F35A4192C3412B7D3B1B7566 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -428,7 +540,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -485,7 +597,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index dc9ada4..0ac0b82 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 7353c41..6b30350 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 797d452..1b11166 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 6ed2d93..f99a83b 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cd7b00..7ac6ecd 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index fe73094..409e5df 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 321773c..aa368f9 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 797d452..1b11166 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 502f463..d679aeb 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 0ec3034..96bdfed 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..0e33bec Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..d7266c7 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..aafa3c6 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..0f310d3 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 0ec3034..96bdfed 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index e9f5fea..5cddf16 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..6997da9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..6a8c6e7 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 84ac32a..1bdfddb 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 8953cba..5a9996b 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 0467bf1..9c53767 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json new file mode 100644 index 0000000..9f447e1 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "background.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png new file mode 100644 index 0000000..7dbde7a Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json index 0bedcf2..00cabce 100644 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { - "idiom" : "universal", "filename" : "LaunchImage.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "LaunchImage@2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "LaunchImage@3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } } diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png index 9da19ea..71e9c81 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png index 9da19ea..71e9c81 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png index 9da19ea..71e9c81 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard index f2e259c..02c3208 100644 --- a/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -16,13 +16,19 @@ - - + + - - + + + + + + + + @@ -33,5 +39,6 @@ + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 16f4ede..8182baa 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -1,49 +1,51 @@ - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - News Assistant - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - news_assistant - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + News Assistant + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + news_assistant + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + UIStatusBarHidden + + diff --git a/lib/components/custom_buttons.dart b/lib/components/custom_buttons.dart deleted file mode 100644 index cc2d5ee..0000000 --- a/lib/components/custom_buttons.dart +++ /dev/null @@ -1,171 +0,0 @@ -import 'package:flutter/material.dart'; - -class PrimaryButton extends StatelessWidget { - const PrimaryButton({ - super.key, - this.onPressed, - this.color, - required this.label, - this.disabled = false, - this.textColor, - this.showLoading = false, - }); - - final VoidCallback? onPressed; - final Color? color; - final String label; - final bool disabled; - final Color? textColor; - final bool showLoading; - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: disabled ? null : onPressed, - borderRadius: BorderRadius.circular(13), - child: Container( - height: 50, - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - color: disabled - ? const Color(0xFFB1B1B1) - : color ?? Theme.of(context).colorScheme.primary, - ), - child: Center( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - if (showLoading) ...{ - SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: textColor ?? Colors.white, - )), - const SizedBox( - width: 10, - ) - }, - Text( - label, - style: Theme.of(context).textTheme.labelLarge!.copyWith( - color: disabled - ? const Color(0xFFF5F5F5) - : textColor ?? Colors.white, - fontSize: 15, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ), - ); - } -} - -class SecondaryButton extends StatelessWidget { - const SecondaryButton({ - super.key, - this.onPressed, - this.color, - required this.label, - this.disabled = false, - this.textColor, - this.showLoading = false, - }); - - final VoidCallback? onPressed; - final Color? color; - final String label; - final bool disabled; - final Color? textColor; - final bool showLoading; - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: disabled ? null : onPressed, - borderRadius: BorderRadius.circular(13), - child: Container( - height: 50, - width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - color: disabled ? const Color(0xFFF5F5F5) : color ?? Colors.grey, - ), - child: Center( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - if (showLoading) ...{ - SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: textColor ?? Colors.white, - )), - const SizedBox( - width: 10, - ) - }, - Text( - label, - style: Theme.of(context).textTheme.labelLarge!.copyWith( - color: disabled - ? const Color(0xFFC8C8C8) - : textColor ?? Colors.black, - fontSize: 15, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ), - ); - } -} - -class EateryOutlinedButton extends StatelessWidget { - const EateryOutlinedButton( - {super.key, - this.onPressed, - this.color, - required this.child, - this.disabled = false, - this.size = 40, - this.showOutline = true}); - final VoidCallback? onPressed; - final Color? color; - final Widget child; - final bool disabled; - final int size; - final bool showOutline; - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onPressed, - child: Center( - child: Container( - width: size.toDouble(), - height: size.toDouble(), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - border: Border.all( - color: showOutline - ? const Color(0xFFF5F5F5) - : Theme.of(context).scaffoldBackgroundColor)), - child: Center(child: child), - ), - ), - ); - } -} diff --git a/lib/components/custom_textfield.dart b/lib/components/custom_textfield.dart deleted file mode 100644 index bbf170a..0000000 --- a/lib/components/custom_textfield.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -class EateryTextField extends StatelessWidget { - const EateryTextField({ - super.key, - this.textController, - this.validator, - this.label, - required this.placeholderText, - this.keyboardType = TextInputType.text, - this.textCapitalization = TextCapitalization.none, - this.textInputAction = TextInputAction.done, - this.enabled = true, - this.suffixIcons, - this.prefixIcons, - this.initialText, - this.onChanged, - this.maxLines, - this.labelFontWeight, - this.onSubmitted, - this.inputFormatters, - this.isPassword = false, - }); - - final TextEditingController? textController; - final String? Function(String? value)? validator; - final void Function(String? value)? onChanged; - final void Function(String? value)? onSubmitted; - final String? label; - final String placeholderText; - final TextInputType keyboardType; - final TextCapitalization textCapitalization; - final TextInputAction? textInputAction; - final bool enabled; - final Widget? suffixIcons; - final Widget? prefixIcons; - final String? initialText; - final FontWeight? labelFontWeight; - final int? maxLines; - final List? inputFormatters; - final bool isPassword; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - if (label != null) ...{ - Text( - label!, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - fontSize: 15, fontWeight: labelFontWeight ?? FontWeight.w400), - ), - const SizedBox( - height: 8, - ), - }, - TextFormField( - obscureText: isPassword, - controller: textController, - keyboardType: keyboardType, - initialValue: initialText, - textCapitalization: textCapitalization, - textInputAction: textInputAction, - enabled: enabled, - maxLines: maxLines, - inputFormatters: inputFormatters, - decoration: InputDecoration( - label: Text(placeholderText, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Colors.grey, - fontSize: 15, - fontWeight: FontWeight.w400, - )), - alignLabelWithHint: true, - hintStyle: Theme.of(context).inputDecorationTheme.hintStyle, - contentPadding: const EdgeInsets.all(15.0), - floatingLabelBehavior: FloatingLabelBehavior.never, - focusedBorder: - Theme.of(context).inputDecorationTheme.focusedBorder, - enabledBorder: - Theme.of(context).inputDecorationTheme.enabledBorder, - disabledBorder: - Theme.of(context).inputDecorationTheme.disabledBorder, - errorBorder: Theme.of(context).inputDecorationTheme.errorBorder, - focusedErrorBorder: - Theme.of(context).inputDecorationTheme.focusedErrorBorder, - fillColor: Theme.of(context).inputDecorationTheme.fillColor, - filled: true, - errorStyle: Theme.of(context).inputDecorationTheme.errorStyle, - suffixIcon: suffixIcons, - prefixIcon: prefixIcons), - cursorColor: Theme.of(context).colorScheme.secondary, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - fontSize: 15, - fontWeight: FontWeight.w400, - ), - validator: validator, - onChanged: onChanged, - onFieldSubmitted: onSubmitted, - ), - ], - ); - } -} - -class UpperCaseTextFormatter extends TextInputFormatter { - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, TextEditingValue newValue) { - return TextEditingValue( - text: capitalize(newValue.text), - selection: newValue.selection, - ); - } -} - -String capitalize(String value) { - if (value.trim().isEmpty) return ""; - return "${value[0].toUpperCase()}${value.substring(1).toLowerCase()}"; -} diff --git a/lib/components/news_agency_header.dart b/lib/components/news_agency_header.dart index d2d0d5a..8171aaf 100644 --- a/lib/components/news_agency_header.dart +++ b/lib/components/news_agency_header.dart @@ -1,14 +1,18 @@ import 'package:flutter/material.dart'; +import 'package:news_assistant/models/news.dart'; +import 'package:news_assistant/utils/util.dart'; class NewsAgencyHeader extends StatelessWidget { const NewsAgencyHeader({ super.key, required this.imageSize, - this.textColor, + this.textColor, required this.articles, }); final double imageSize; final Color? textColor; + final Articles articles; + @override Widget build(BuildContext context) { @@ -21,6 +25,12 @@ class NewsAgencyHeader extends StatelessWidget { children: [ CircleAvatar( radius: imageSize, + child: Text( + articles.source!.name![0], + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.w700), + ), ), const SizedBox( width: 10, @@ -29,14 +39,14 @@ class NewsAgencyHeader extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'CNN Philippines', + articles.source?.name ?? '', style: Theme.of(context) .textTheme .bodyMedium! .copyWith(color: textColor, fontWeight: FontWeight.w900,fontSize: 20), ), Text( - '10 minutes ago', + getTimeAgo(DateTime.parse(articles.publishedAt!)), style: Theme.of(context).textTheme.bodyMedium!.copyWith( color: textColor, fontWeight: FontWeight.normal), ) diff --git a/lib/main.dart b/lib/main.dart index f1c89e1..de1dbcf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:news_assistant/app.dart'; +import 'package:news_assistant/services/services.dart'; void main() { - runApp(const App()); + setupInjector(); + runApp(const ProviderScope(child: App())); } diff --git a/lib/managers/news_manager.dart b/lib/managers/news_manager.dart new file mode 100644 index 0000000..1ae7d3e --- /dev/null +++ b/lib/managers/news_manager.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:google_generative_ai/google_generative_ai.dart'; +import 'package:news_assistant/models/news.dart'; +import 'package:news_assistant/services/news_service.dart'; + +class NewsManager extends ChangeNotifier { + final NewsServices newsServices; + + NewsManager(this.newsServices); + + Future getHeadlines({String country = 'us'}) async { + return await newsServices.headlines(country: country); + } + + Future getOtherNews({String country = 'us'}) async { + return await newsServices.otherNews(country: country); + } + + Future summarize({required String article}) async { + return await newsServices.summarize(articleuRL: article); + } + + Future translate( + {required String text, required String language}) async { + return await newsServices.translate(text: text, language: language); + } +} diff --git a/lib/models/news.dart b/lib/models/news.dart new file mode 100644 index 0000000..c7e1ac0 --- /dev/null +++ b/lib/models/news.dart @@ -0,0 +1,94 @@ +class News { + String? status; + int? totalResults; + List? articles; + + News({this.status, this.totalResults, this.articles}); + + News.fromJson(Map json) { + status = json['status']; + totalResults = json['totalResults']; + if (json['articles'] != null) { + articles = []; + json['articles'].forEach((v) { + articles!.add(Articles.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['status'] = status; + data['totalResults'] = totalResults; + if (articles != null) { + data['articles'] = articles!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Articles { + Source? source; + String? author; + String? title; + String? description; + String? url; + String? urlToImage; + String? publishedAt; + String? content; + + Articles( + {this.source, + this.author, + this.title, + this.description, + this.url, + this.urlToImage, + this.publishedAt, + this.content}); + + Articles.fromJson(Map json) { + source = json['source'] != null ? Source.fromJson(json['source']) : null; + author = json['author']; + title = json['title']; + description = json['description']; + url = json['url']; + urlToImage = json['urlToImage']; + publishedAt = json['publishedAt']; + content = json['content']; + } + + Map toJson() { + final Map data = {}; + if (source != null) { + data['source'] = source!.toJson(); + } + data['author'] = author; + data['title'] = title; + data['description'] = description; + data['url'] = url; + data['urlToImage'] = urlToImage; + data['publishedAt'] = publishedAt; + data['content'] = content; + return data; + } +} + +class Source { + String? id; + String? name; + + Source({this.id, this.name}); + + Source.fromJson(Map json) { + id = json['id']; + name = json['name']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + return data; + } +} diff --git a/lib/resources/images.dart b/lib/resources/images.dart index e529b1c..a6ffe39 100644 --- a/lib/resources/images.dart +++ b/lib/resources/images.dart @@ -3,5 +3,6 @@ part of 'resources.dart'; class Images { Images._(); + static const String logo = 'assets/images/logo.jpg'; static const String placeholder = 'assets/images/placeholder.png'; } diff --git a/lib/resources/resources.dart b/lib/resources/resources.dart index 3902daa..ccfd4f3 100644 --- a/lib/resources/resources.dart +++ b/lib/resources/resources.dart @@ -1,3 +1,5 @@ part 'images.dart'; part 'svgs.dart'; + +part 'rive_assets.dart'; diff --git a/lib/resources/rive.dart b/lib/resources/rive.dart new file mode 100644 index 0000000..c2fea98 --- /dev/null +++ b/lib/resources/rive.dart @@ -0,0 +1,7 @@ +part of 'resources.dart'; + +class Rive { + Rive._(); + + static const String aiTalk = 'assets/rive/ai_talk.riv'; +} diff --git a/lib/resources/rive_assets.dart b/lib/resources/rive_assets.dart new file mode 100644 index 0000000..603ccf6 --- /dev/null +++ b/lib/resources/rive_assets.dart @@ -0,0 +1,7 @@ +part of 'resources.dart'; + +class RiveAssets { + RiveAssets._(); + + static const String aiTalk = 'assets/rive/ai_talk.riv'; +} diff --git a/lib/resources/svgs.dart b/lib/resources/svgs.dart index 77d2638..6723f8e 100644 --- a/lib/resources/svgs.dart +++ b/lib/resources/svgs.dart @@ -5,7 +5,9 @@ class Svgs { static const String back = 'assets/svgs/back.svg'; static const String bookmark = 'assets/svgs/bookmark.svg'; + static const String close = 'assets/svgs/close.svg'; static const String logo = 'assets/svgs/logo.svg'; static const String search = 'assets/svgs/search.svg'; static const String share = 'assets/svgs/share.svg'; + static const String stars = 'assets/svgs/stars.svg'; } diff --git a/lib/router.dart b/lib/router.dart index 47afcb1..a00d8bb 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -2,6 +2,8 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:news_assistant/models/news.dart'; +import 'package:news_assistant/views/ai_summarize_view.dart'; import 'package:news_assistant/views/home_view.dart'; import 'package:news_assistant/views/news_detail_view.dart'; import 'package:news_assistant/views/splash_view.dart'; @@ -10,7 +12,9 @@ class Routes { static ({String name, String path}) initialRoute = (name: '/', path: '/'); static ({String name, String path}) home = (name: 'home', path: '/home'); static ({String name, String path}) details = - (name: 'details', path: 'details/:id'); + (name: 'details', path: 'details'); + static ({String name, String path}) summarize = (name: 'summarize', path: 'summarize'); + } final GoRouter router = GoRouter( @@ -58,10 +62,12 @@ final GoRouter router = GoRouter( path: Routes.details.path, name: Routes.details.name, pageBuilder: (BuildContext context, GoRouterState state) { + final args = state.extra as (Articles, String); return CustomTransitionPage( key: state.pageKey, child: NewsDetailView( - id: state.pathParameters['id']!, + articles: args.$1, + heroTag: args.$2, ), transitionsBuilder: (context, animation, secondaryAnimation, child) { @@ -73,6 +79,28 @@ final GoRouter router = GoRouter( }, ); }, + routes: [ + GoRoute( + path: Routes.summarize.path, + name: Routes.summarize.name, + pageBuilder: (BuildContext context, GoRouterState state) { + return CustomTransitionPage( + key: state.pageKey, + child: AiSummarizeView( + article: state.extra as Articles, + ), + transitionsBuilder: + (context, animation, secondaryAnimation, child) { + return FadeTransition( + opacity: CurveTween(curve: Curves.easeInOutCirc) + .animate(animation), + child: child, + ); + }, + ); + }, + ), + ] ), ]), ]); diff --git a/lib/services/news_service.dart b/lib/services/news_service.dart new file mode 100644 index 0000000..118efb9 --- /dev/null +++ b/lib/services/news_service.dart @@ -0,0 +1,102 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:async/async.dart'; +import 'package:google_generative_ai/google_generative_ai.dart'; +import 'package:http/http.dart'; +import 'package:news_assistant/models/news.dart'; +import 'package:news_assistant/utils/util.dart'; + +abstract class NewsServices { + Future headlines({String country = 'gh'}); + Future otherNews({String country = 'gh'}); + Future summarize({required String articleuRL}); + Future translate( + {required String text, required String language}); +} + +class NewsServicesImpl extends NewsServices { + final baseUrl = "https://newsapi.org/v2/"; + final apiKey = const String.fromEnvironment('NEWS-API-KEY'); + final memoizer = AsyncMemoizer(); + final model = GenerativeModel( + model: 'gemini-pro', + apiKey: const String.fromEnvironment('GEMINI-API-KEY'), + safetySettings: [ + SafetySetting(HarmCategory.sexuallyExplicit, HarmBlockThreshold.none) + ], + ); + + Future fetchDataFromApi(Uri url) async { + final response = await get(url); + final body = jsonDecode(response.body); + if (response.statusCode == 200) { + return response.body; + } else { + throw Exception('${body['message'] ?? response.statusCode}'); + } + } + + @override + Future headlines({String country = 'us'}) async { + try { + final url = + Uri.parse('$baseUrl/top-headlines?country=$country&apiKey=$apiKey'); + final response = + await memoizer.runOnce(() async => fetchDataFromApi(url)); + final body = jsonDecode(response); + + return News.fromJson(body); + } catch (e) { + rethrow; + } + } + + @override + Future otherNews({String country = 'us'}) async { + try { + final url = Uri.parse( + '$baseUrl/everything?q=$country&sortBy=popularity&apiKey=$apiKey'); + final response = + await memoizer.runOnce(() async => fetchDataFromApi(url)); + final body = jsonDecode(response); + + return News.fromJson(body); + } catch (e) { + rethrow; + } + } + + @override + Future summarize( + {required String articleuRL}) async { + try { + final webContent = await getMainArticleContent(articleuRL); + final String prompt = + 'Given the following article content, please generate a concise summary' + ' highlighting the main points and key details. ' + 'Ignore any non-relevant elements such as menus, promotions, and ' + 'other unrelated information to the main article narrative: $webContent'; + final content = [Content.text(prompt)]; + + final response = await model.generateContent(content); + return response; + } catch (e) { + log('$e'); + throw Exception(e); + } + } + + @override + Future translate( + {required String text, required String language}) async { + try { + final prompt = 'Translate the following text to $language: $text'; + final content = [Content.text(prompt)]; + final response = await model.generateContent(content); + return response; + } catch (e) { + rethrow; + } + } +} diff --git a/lib/services/services.dart b/lib/services/services.dart new file mode 100644 index 0000000..82aa79d --- /dev/null +++ b/lib/services/services.dart @@ -0,0 +1,10 @@ +import 'package:get_it/get_it.dart'; +import 'package:news_assistant/managers/news_manager.dart'; +import 'package:news_assistant/services/news_service.dart'; + +final getIt = GetIt.instance; + +void setupInjector() async { + getIt.registerLazySingleton(() => NewsServicesImpl()); + getIt.registerSingleton(NewsManager(getIt.get())); +} diff --git a/lib/theme.dart b/lib/theme.dart index 65c03f2..fd4e6f3 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:news_assistant/components/color_schemes.dart'; ThemeData get customLightTheme { - return ThemeData.light().copyWith(colorScheme: lightColorScheme); + return ThemeData(colorScheme: lightColorScheme, fontFamily: 'Satoshi'); } ThemeData get customDarkTheme { - return ThemeData.dark().copyWith(colorScheme: darkColorScheme); + return ThemeData(colorScheme: darkColorScheme, fontFamily: 'Satoshi'); } diff --git a/lib/utils/util.dart b/lib/utils/util.dart new file mode 100644 index 0000000..cce6678 --- /dev/null +++ b/lib/utils/util.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:html/parser.dart' as parser; +import 'package:http/http.dart' as http; + +String getTimeAgo(DateTime referenceTime) { + final now = DateTime.now(); + final difference = now.difference(referenceTime); + final inSeconds = difference.inSeconds.abs(); + + if (inSeconds < 60) { + return "just now"; + } else if (inSeconds < 3600) { + final minutes = (inSeconds / 60).floor(); + final plural = minutes > 1 ? "minutes" : "minute"; + return "$minutes $plural ago"; + } else if (inSeconds < 86400) { + final hours = (inSeconds / 3600).floor(); + final plural = hours > 1 ? "hours" : "hour"; + return "$hours $plural ago"; + } else if (inSeconds < 604800) { + // Less than a week + final days = (inSeconds / 86400).floor(); + final plural = days > 1 ? "days" : "day"; + return "$days $plural ago"; + } else if (inSeconds < 2592000) { + // Less than a month (approx 4 weeks) + final weeks = (inSeconds / 604800).floor(); + final plural = weeks > 1 ? "weeks" : "week"; + return "$weeks $plural ago"; + } else if (referenceTime.year == now.year) { + final months = now.month - referenceTime.month; + if (months == 1) { + return "last month"; + } else { + return "$months months ago"; + } + } else { + final years = now.year - referenceTime.year; + final plural = years > 1 ? "years" : "year"; + return "$years $plural ago"; + } +} + +List parseMarkdown(String text) { + List spans = []; + RegExp exp = RegExp(r'\*\*(.*?)\*\*'); + String tempText = text; + + while (exp.hasMatch(tempText)) { + final match = exp.firstMatch(tempText); + if (match != null) { + final beforeText = tempText.substring(0, match.start); + final boldText = match.group(1); + + if (beforeText.isNotEmpty) { + spans.add(TextSpan(text: beforeText)); + spans.add(const TextSpan(text: '\n\n')); + } + if (boldText != null) { + spans.add( + TextSpan( + text: boldText, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ); + } + + tempText = tempText.substring(match.end); + } + } + + if (tempText.isNotEmpty) { + spans.add(TextSpan(text: tempText)); + } + + return spans; +} + +Future getMainArticleContent(String url) async { + try { + // Send a GET request to the URL + var response = await http.get(Uri.parse(url)); + + // Check if the request was successful (status code 200) + if (response.statusCode == 200) { + // Parse the HTML content of the page + var document = parser.parse(response.body); + + // Define CSS selectors for common elements to ignore + var selectorsToIgnore = [ + 'header', 'footer', 'nav', 'aside', 'script', 'style', 'iframe', + '.menu', '.popup', '.promotion', '.advertisement', '.related' + // Add more selectors if needed + ]; + + // Remove elements matching the specified selectors + for (var selector in selectorsToIgnore) { + document.querySelectorAll(selector).forEach((element) { + element.remove(); // Remove the element from the document + }); + } + + // Extract and return the text content of the remaining elements + return document.body?.text; + } else { + print('Failed to fetch the webpage. Status code: ${response.statusCode}'); + } + } catch (e) { + print('Error: $e'); + } + + return null; +} diff --git a/lib/views/ai_summarize_view.dart b/lib/views/ai_summarize_view.dart new file mode 100644 index 0000000..438efe9 --- /dev/null +++ b/lib/views/ai_summarize_view.dart @@ -0,0 +1,247 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_generative_ai/google_generative_ai.dart'; +import 'package:news_assistant/managers/news_manager.dart'; +import 'package:news_assistant/models/news.dart'; +import 'package:news_assistant/resources/resources.dart'; +import 'package:news_assistant/services/news_service.dart'; +import 'package:news_assistant/services/services.dart'; +import 'package:news_assistant/utils/util.dart'; +import 'package:rive/rive.dart'; + +final _newsService = getIt.get(); +final _newsManager = + ChangeNotifierProvider((ref) => NewsManager(_newsService)); + +class AiSummarizeView extends ConsumerStatefulWidget { + const AiSummarizeView({super.key, required this.article}); + + final Articles article; + + @override + ConsumerState createState() => _AiSummarizeViewState(); +} + +class _AiSummarizeViewState extends ConsumerState { + GenerateContentResponse? response; + bool loading = false; + final languages = [ + 'English', + 'French', + 'German', + 'Hindi', + 'Italian', + 'Japanese', + 'Korean', + 'Portuguese', + 'Russian', + 'Spanish', + 'Turkish', + 'Vietnamese', + 'Indonesian', + 'Chinese', + 'Thai', + 'Arabic', + 'Bengali', + 'Bulgarian', + 'Catalan', + 'Czech', + 'Danish', + 'Dutch', + 'Filipino', + 'Finnish', + 'Galician', + 'Greek', + 'Hebrew', + 'Hindi', + 'Hungarian', + 'Irish', + 'Icelandic', + 'Kannada', + ]; + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + setState(() { + loading = true; + }); + final newsManager = ref.read(_newsManager); + + response = await newsManager.summarize(article: widget.article.url ?? ''); + setState(() { + loading = false; + }); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: FutureBuilder( + future: Future.value(response), + builder: (context, snapshot) { + if (loading) { + return const LoadingWidget(); + } + + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () => context.pop(), + icon: SvgPicture.asset( + Svgs.close, + width: 35, + )), + actions: [ + if (snapshot.data != null) ...{ + IconButton( + onPressed: () async { + if (snapshot.data?.text == null) return; + await Clipboard.setData(ClipboardData( + text: snapshot.data?.text ?? '')) + .then((value) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(10))), + content: Text('Copied to clipboard!'))); + }); + }, + icon: const Icon(Icons.copy_rounded)) + } + ], + ), + floatingActionButton: snapshot.data == null + ? null + : FloatingActionButton( + onPressed: () async => showTranslationList(), + child: const Icon(Icons.translate), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: response == null || snapshot.data == null + ? Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.sentiment_dissatisfied), + Text( + '${snapshot.error ?? 'Couldn\t summarize article'}', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + )) + : SelectableText.rich( + TextSpan( + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith(fontSize: 18), // Default text style + children: parseMarkdown( + snapshot.data?.text ?? '', + ), + ), + ), + ), + ); + }), + ); + } + + showTranslationList() async { + final language = await showModalBottomSheet( + context: context, + showDragHandle: true, + enableDrag: true, + isScrollControlled: true, + isDismissible: true, + anchorPoint: Offset.fromDirection(0.5), + builder: (context) { + return Container( + height: MediaQuery.sizeOf(context).height * .8, + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ...languages.map((e) => ListTile( + title: Text( + e, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(fontSize: 18), + ), + onTap: () { + Navigator.pop(context, e); + }, + )), + ], + ), + ), + ); + }); + + if (language == null) return; + if (response?.text == null) return; + setState(() { + loading = true; + }); + final translate = await ref + .read(_newsManager) + .translate(text: response?.text ?? '', language: language); + log('translate: ${translate.text}'); + + setState(() { + response = translate; + loading = false; + }); + } +} + +class LoadingWidget extends StatelessWidget { + const LoadingWidget({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const Spacer(), + const Center( + child: SizedBox( + width: 300, + height: 300, + child: RiveAnimation.asset( + RiveAssets.aiTalk, + )), + ), + const SizedBox(height: 25), + Text( + 'Get ready for some magic!', + style: Theme.of(context).textTheme.bodyLarge!.copyWith(fontSize: 20), + ), + const SizedBox(height: 10), + Text( + 'Crafting an article summary...', + style: Theme.of(context).textTheme.bodyMedium!.copyWith(fontSize: 15), + ), + const SizedBox(height: 25), + const SizedBox( + width: 40, height: 40, child: CircularProgressIndicator()), + const Spacer(), + const Spacer(), + ], + ); + } +} diff --git a/lib/views/home_view.dart b/lib/views/home_view.dart index b4a657d..c5b9d84 100644 --- a/lib/views/home_view.dart +++ b/lib/views/home_view.dart @@ -1,112 +1,201 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:news_assistant/components/category_chip.dart'; import 'package:news_assistant/components/my_app_bar.dart'; +import 'package:news_assistant/managers/news_manager.dart'; +import 'package:news_assistant/models/news.dart'; import 'package:news_assistant/resources/resources.dart'; import 'package:news_assistant/router.dart'; +import 'package:news_assistant/services/news_service.dart'; +import 'package:news_assistant/services/services.dart'; +import 'package:news_assistant/utils/util.dart'; -class HomeView extends StatefulWidget { +final _newsService = getIt.get(); +final _newsManager = + ChangeNotifierProvider((ref) => NewsManager(_newsService)); + +class HomeView extends ConsumerStatefulWidget { const HomeView({super.key}); @override - State createState() => _HomeViewState(); + ConsumerState createState() => _HomeViewState(); } -class _HomeViewState extends State { +class _HomeViewState extends ConsumerState { final scrollController = ScrollController(); - String categotySelected = 'General'; - final categories = [ - 'General', - 'Sports', - 'Business', - 'Entertainment', - 'Health', - 'Science', - 'Technology', - ]; + ValueNotifier categotySelectedListenable = ValueNotifier('All'); @override Widget build(BuildContext context) { + final newsManager = ref.read(_newsManager); + return Scaffold( appBar: const MyAppBar(), - body: ListView( - controller: scrollController, - padding: const EdgeInsets.all(16), - children: [ - SizedBox( - height: 37, - child: ListView( - scrollDirection: Axis.horizontal, - children: List.generate( - categories.length, - (index) => Padding( - padding: const EdgeInsets.only(right: 10), - child: CategoryChip( - isSelected: categotySelected == categories[index], - label: categories[index], - onTap: () { - setState(() { - categotySelected = categories[index]; - }); - }, + body: ValueListenableBuilder( + valueListenable: categotySelectedListenable, + builder: (context, categotySelected, _) { + return ListView( + controller: scrollController, + padding: const EdgeInsets.all(16), + children: [ + FutureBuilder( + future: newsManager.getHeadlines(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting || + !snapshot.hasData) { + return const LinearProgressIndicator(); + } + + final articles = snapshot.data?.articles ?? []; + + if (articles.isEmpty) { + return const Center( + child: Text('No articles found'), + ); + } + + final categories = + articles.map((e) => e.source!.name).toSet().toList(); + categories.insert(0, 'All'); + final displayArticles = articles.where((element) { + if (categotySelected == 'All') { + return true; + } + return element.source!.name == categotySelected; + }).toList(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 38, + child: ListView( + scrollDirection: Axis.horizontal, + children: List.generate( + categories.length, + (index) => Padding( + padding: + const EdgeInsets.only(right: 10), + child: CategoryChip( + isSelected: categotySelected == + categories[index], + label: categories[index]!, + onTap: () { + categotySelectedListenable.value = + categories[index]!; + }, + ), + ))), ), - ))), - ), - const SizedBox( - height: 18, - ), - Text( - 'Inbound Now!', - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - fontSize: 35, - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary), - ), - const SizedBox(height: 18), - SizedBox( - height: 265, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemBuilder: (context,index){ - return SizedBox( - width: MediaQuery.sizeOf(context).width/1.2, - child: NewsCard( - onTap: () {}, + const SizedBox( + height: 18, ), - ); - }, separatorBuilder: (__,_)=> const SizedBox(width: 10,), itemCount: 10), - ), - const SizedBox( - height: 18, - ), - Text( - 'Other News:', - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary), - ), - const SizedBox(height: 12), - ListView.separated( - controller: scrollController, - shrinkWrap: true, - itemBuilder: (context, index) { - return NewsCard( - onTap: () { - context.pushNamed( - Routes.details.name, - pathParameters: { - 'id': index.toString(), + Text( + 'Inbound Now!', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontSize: 35, + fontWeight: FontWeight.bold, + color: + Theme.of(context).colorScheme.primary), + ), + const SizedBox(height: 18), + if (categotySelected == 'All') ...{ + SizedBox( + height: 265, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + final heroTag = + '${articles[index].title!.replaceAll(' ', '')}${'${articles[index].publishedAt}'.replaceAll(' ', '')}inbound'; + + return SizedBox( + width: MediaQuery.sizeOf(context).width / + 1.2, + child: NewsCard( + heroTag: heroTag, + article: displayArticles[index], + onTap: () => context.pushNamed( + Routes.details.name, + extra: ( + displayArticles[index], + heroTag + )), + ), + ); + }, + separatorBuilder: (__, _) => const SizedBox( + width: 10, + ), + itemCount: displayArticles.length), + ), + }, + ], + ); + }), + if (categotySelected == 'All') ...{ + const SizedBox( + height: 18, + ), + Text( + 'Other News:', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary), + ), + const SizedBox(height: 12), + }, + FutureBuilder( + future: newsManager.getOtherNews(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting || + !snapshot.hasData) { + return const Center( + child: CircularProgressIndicator(), + ); } - ); - }, - ); - }, - separatorBuilder: (context, index) { - return const SizedBox(width: 10); - }, - itemCount: 10) - ], - ), + + final articles = snapshot.data?.articles ?? []; + + if (articles.isEmpty) { + return const Center( + child: Text('No articles found'), + ); + } + + final displayArticles = articles.where((element) { + if (categotySelected == 'All') { + return true; + } + return element.source!.name == categotySelected; + }).toList(); + displayArticles.shuffle(); + + return ListView.separated( + controller: scrollController, + shrinkWrap: true, + itemBuilder: (context, index) { + final heroTag = + '${articles[index].title!.replaceAll(' ', '')}${'${articles[index].publishedAt}'.replaceAll(' ', '')}other'; + return NewsCard( + heroTag: heroTag, + article: displayArticles[index], + onTap: () => context.pushNamed( + Routes.details.name, + extra: (displayArticles[index], heroTag)), + ); + }, + separatorBuilder: (context, index) { + return const SizedBox(width: 10); + }, + itemCount: displayArticles.length); + }) + ], + ); + }), ); } } @@ -115,9 +204,13 @@ class NewsCard extends StatelessWidget { const NewsCard({ super.key, required this.onTap, + required this.article, + required this.heroTag, }); final VoidCallback onTap; + final Articles article; + final String heroTag; @override Widget build(BuildContext context) { @@ -133,31 +226,55 @@ class NewsCard extends StatelessWidget { padding: const EdgeInsets.all(14.0), child: Column( children: [ - ClipRRect( - borderRadius: BorderRadius.circular(13.75), - child: SizedBox( - height: 167, - child: Stack( - children: [ - Image.asset( - Images.placeholder, - fit: BoxFit.fill, - height: 167, - width: MediaQuery.sizeOf(context).width, - ), - Container( - height: 167, - width: MediaQuery.sizeOf(context).width, - color: Colors.red.withOpacity(.2), - ), - NewsAgencyHeader() - ], + Hero( + tag: heroTag, + child: ClipRRect( + borderRadius: BorderRadius.circular(13.75), + child: SizedBox( + height: 167, + child: Stack( + children: [ + article.urlToImage == null + ? Image.asset( + Images.placeholder, + fit: BoxFit.fill, + height: 167, + width: MediaQuery.sizeOf(context).width, + ) + : CachedNetworkImage( + imageUrl: article.urlToImage!, + fit: BoxFit.fill, + height: 167, + width: MediaQuery.sizeOf(context).width, + progressIndicatorBuilder: + (context, url, downloadProgress) => Center( + child: CircularProgressIndicator( + value: downloadProgress.progress), + ), + errorWidget: (context, url, error) => + Image.asset( + Images.placeholder, + fit: BoxFit.fill, + height: 167, + width: MediaQuery.sizeOf(context).width, + ), + ), + Container( + height: 167, + width: MediaQuery.sizeOf(context).width, + color: Colors.black.withOpacity(.2), + ), + NewsAgencyHeader( + article: article, + ) + ], + ), ), ), ), const SizedBox(height: 14), Text( - 'Traffic in Philippines\' Capital City of Manila Worsens Despite Measures to Ease Congestion', + '''${article.title}''', maxLines: 2, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodyLarge!.copyWith( @@ -177,8 +294,11 @@ class NewsCard extends StatelessWidget { class NewsAgencyHeader extends StatelessWidget { const NewsAgencyHeader({ super.key, + required this.article, }); + final Articles article; + @override Widget build(BuildContext context) { return Padding( @@ -190,32 +310,34 @@ class NewsAgencyHeader extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ - const CircleAvatar( + CircleAvatar( radius: 29 / 2, + child: Text( + article.source!.name![0], + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.w700), + ), ), const SizedBox( width: 10, ), Text( - 'CNN Philippines', + article.source?.name ?? '', style: Theme.of(context) .textTheme .bodyMedium! - .copyWith( - color: Colors.white, - fontWeight: FontWeight.bold), + .copyWith(color: Colors.white, fontWeight: FontWeight.bold), ) ], ), const Spacer(), Text( - '10 minutes ago', + getTimeAgo(DateTime.parse(article.publishedAt!)), style: Theme.of(context) .textTheme .bodyMedium! - .copyWith( - color: Colors.white, - fontWeight: FontWeight.w600), + .copyWith(color: Colors.white, fontWeight: FontWeight.w600), ) ], ), diff --git a/lib/views/news_detail_view.dart b/lib/views/news_detail_view.dart index 9d91805..ed02dd3 100644 --- a/lib/views/news_detail_view.dart +++ b/lib/views/news_detail_view.dart @@ -1,46 +1,103 @@ import 'dart:io'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:news_assistant/components/news_agency_header.dart'; +import 'package:news_assistant/models/news.dart'; import 'package:news_assistant/resources/resources.dart'; +import 'package:news_assistant/router.dart'; +import 'package:share_plus/share_plus.dart'; class NewsDetailView extends StatelessWidget { - const NewsDetailView({super.key, required this.id}); + const NewsDetailView( + {super.key, required this.articles, required this.heroTag}); - final String id; + final Articles articles; + final String heroTag; @override Widget build(BuildContext context) { return Scaffold( - appBar: const AppBar(), + appBar: AppBar( + onBookmark: () {}, + onShare: () => + Share.share('Hey! Check out this article: ${articles.url}'), + ), body: ListView( padding: const EdgeInsets.all(16), children: [ + Align( + alignment: Alignment.centerRight, + child: TextButton( + style: TextButton.styleFrom( + backgroundColor: + Theme.of(context).colorScheme.primary.withOpacity(.2), + shape: const StadiumBorder()), + onPressed: () => + context.pushNamed(Routes.summarize.name, extra: articles), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset(Svgs.stars, + color: Theme.of(context).colorScheme.primary), + const SizedBox(width: 6), + Text( + 'AI Summarize', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Theme.of(context).colorScheme.primary), + ) + ], + )), + ), SizedBox( height: 310, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const NewsAgencyHeader(imageSize: 25), - ClipRRect( - borderRadius: BorderRadius.circular(13.75), - child: SizedBox( - height: 216, - child: Stack( - children: [ - Image.asset( - Images.placeholder, - fit: BoxFit.cover, - height: 216, - width: MediaQuery.sizeOf(context).width, - ), - Container( - height: 216, - width: MediaQuery.sizeOf(context).width, - color: Colors.red.withOpacity(.2), - ), - ], + NewsAgencyHeader(imageSize: 25, articles: articles), + Hero( + tag: heroTag, + child: ClipRRect( + borderRadius: BorderRadius.circular(13.75), + child: SizedBox( + height: 216, + child: Stack( + children: [ + articles.urlToImage == null + ? Image.asset( + Images.placeholder, + fit: BoxFit.fill, + height: 216, + width: MediaQuery.sizeOf(context).width, + ) + : CachedNetworkImage( + imageUrl: articles.urlToImage!, + fit: BoxFit.fill, + height: 216, + width: MediaQuery.sizeOf(context).width, + progressIndicatorBuilder: + (context, url, downloadProgress) => + Center( + child: CircularProgressIndicator( + value: downloadProgress.progress), + ), + errorWidget: (context, url, error) => + Image.asset( + Images.placeholder, + fit: BoxFit.fill, + height: 167, + width: MediaQuery.sizeOf(context).width, + ), + ), + Container( + height: 216, + width: MediaQuery.sizeOf(context).width, + color: Colors.black.withOpacity(.2), + ), + ], + ), ), ), ), @@ -48,23 +105,20 @@ class NewsDetailView extends StatelessWidget { ), ), const SizedBox(height: 10), - Text('GENERAL NEWS', + Text('NEWS HEADLINE', style: Theme.of(context).textTheme.bodyLarge!.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary)), const SizedBox(height: 10), - Text( - 'Traffic in Philippines\' Capital City of Manila Worsens Despite Measures to Ease Congestion', - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith(fontWeight: FontWeight.w900, fontSize: 24)), + Text(articles.title!, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + fontWeight: FontWeight.w900, + fontSize: 24, + letterSpacing: 0, + height: 1.1)), const SizedBox(height: 10), Text( - '''MANILA, Philippines - Despite efforts to ease traffic congestion in the capital city of Manila, residents are reporting that traffic has only gotten worse. The government has implemented a number of measures in recent years, including the construction of new roadways and the implementation of a color-coded coding scheme for vehicles, but these efforts have done little to alleviate the problem. -According to a recent survey, the average commuter in Manila spends an average of three hours a day stuck in traffic. This has not only caused frustration and inconvenience for residents, but it is also taking a toll on the city's economy. Businesses are struggling to keep up with the high costs of transportation and delivery, and many residents are finding it difficult to make it to work on time. -The government has acknowledged the problem and is looking for new solutions to ease the traffic congestion. Some officials have suggested the implementation of a more comprehensive public transportation system, while others have proposed the construction of new flyovers and underpasses. -As the population and urbanization of Manila is growing rapidly, traffic congestion is becoming a major problem for the city. The government is doing efforts to ease the traffic but seems not enough to solve the problem. Hopefully, new solutions will be implemented soon to improve the quality of life for the residents of Manila.''', + '''${articles.content ?? articles.description}''', style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox( @@ -77,7 +131,10 @@ As the population and urbanization of Manila is growing rapidly, traffic congest } class AppBar extends StatelessWidget implements PreferredSizeWidget { - const AppBar({super.key}); + const AppBar({super.key, required this.onShare, required this.onBookmark}); + + final VoidCallback onShare; + final VoidCallback onBookmark; @override Widget build(BuildContext context) { diff --git a/lib/views/splash_view.dart b/lib/views/splash_view.dart index bb09f9f..b41437e 100644 --- a/lib/views/splash_view.dart +++ b/lib/views/splash_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:news_assistant/resources/resources.dart'; import 'package:news_assistant/router.dart'; class SplashView extends StatefulWidget { @@ -9,27 +10,77 @@ class SplashView extends StatefulWidget { State createState() => _SplashViewState(); } -class _SplashViewState extends State { +class _SplashViewState extends State with TickerProviderStateMixin { + late AnimationController contentCtrl; + Animation? animation; @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - Future.delayed(const Duration(seconds: 2), () { + + contentCtrl = + AnimationController(vsync: this, duration: const Duration(seconds: 2)) + ..forward(); + + contentCtrl.addStatusListener((status) { + if (status == AnimationStatus.completed) { context.goNamed(Routes.home.name); - }); + } }); } + @override + void dispose() { + contentCtrl.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return const Scaffold( + return Scaffold( + backgroundColor: Theme.of(context).colorScheme.primary, body: Column( children: [ - Expanded( - child: Center( - child: CircularProgressIndicator(), + const Spacer(), + FadeTransition( + opacity: Tween(begin: 0, end: 1).animate( + CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut), + ), + child: SlideTransition( + position: Tween( + begin: const Offset(0, 0.125), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: contentCtrl, + curve: Curves.easeInOut, + ), + ), + child: Column( + children: [ + Image.asset( + Images.logo, + width: MediaQuery.sizeOf(context).width / 2, + ), + Text( + 'News Assistant', + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Colors.white, + fontSize: 27, + fontWeight: FontWeight.w800), + ), + ], + ), + ), + ), + const Spacer(), + const Center( + child: CircularProgressIndicator( + backgroundColor: Colors.white, ), ), + const SizedBox( + height: 50, + ) ], ), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..f6f23bf 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..f16b4c3 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..7798fc3 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,14 @@ import FlutterMacOS import Foundation +import path_provider_foundation +import rive_common +import share_plus +import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index a2ec33f..96d3fee 100644 --- a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,68 +1,68 @@ { - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" + "info": { + "version": 1, + "author": "xcode" }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} + "images": [ + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_16.png", + "scale": "1x" + }, + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "2x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "1x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_64.png", + "scale": "2x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_128.png", + "scale": "1x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "2x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "1x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "2x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "1x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_1024.png", + "scale": "2x" + } + ] +} \ No newline at end of file diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png index 82b6f9d..0ac0b82 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png index 13b35eb..d3c5c7e 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png index 0a3f5fa..2022511 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png index bdb5722..7653335 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png index f083318..1820f29 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png index 326c0e7..ff6701e 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png index 2f1632c..857a53c 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/pubspec.lock b/pubspec.lock index df34fa7..f2eaf59 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,46 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + url: "https://pub.dev" + source: hosted + version: "0.11.3" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "8bf17a8ff6ea17499e40a2d2542c2f481cd7615760c6d34065cb22bfd22e6880" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + archive: + dependency: transitive + description: + name: archive + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + url: "https://pub.dev" + source: hosted + version: "3.4.10" args: dependency: transitive description: @@ -10,7 +50,7 @@ packages: source: hosted version: "2.4.2" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" @@ -33,6 +73,46 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.3" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" + url: "https://pub.dev" + source: hosted + version: "1.1.1" characters: dependency: transitive description: @@ -41,6 +121,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" clock: dependency: transitive description: @@ -57,6 +161,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + url: "https://pub.dev" + source: hosted + version: "0.3.4+1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + custom_lint: + dependency: transitive + description: + name: custom_lint + sha256: "445242371d91d2e24bd7b82e3583a2c05610094ba2d0575262484ad889c8f981" + url: "https://pub.dev" + source: hosted + version: "0.6.2" + custom_lint_builder: + dependency: transitive + description: + name: custom_lint_builder + sha256: "4c0aed2a3491096e91cf1281923ba1b6814993f16dde0fd60f697925225bbbd6" + url: "https://pub.dev" + source: hosted + version: "0.6.2" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: ce5d6215f4e143f7780ce53f73dfa6fc503f39d2d30bef76c48be9ac1a09d9a6 + url: "https://pub.dev" + source: hosted + version: "0.6.2" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" fake_async: dependency: transitive description: @@ -65,11 +233,51 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + url: "https://pub.dev" + source: hosted + version: "0.13.1" flutter_lints: dependency: "direct dev" description: @@ -78,6 +286,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + flutter_native_splash: + dependency: "direct dev" + description: + name: flutter_native_splash + sha256: "58fb249fb19ffe979e4ad288de018a118768988b1f497e6ff0b23ead6f5a1bc5" + url: "https://pub.dev" + source: hosted + version: "2.3.13" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "4bce556b7ecbfea26109638d5237684538d4abc509d253e6c5c4c5733b360098" + url: "https://pub.dev" + source: hosted + version: "2.4.10" flutter_svg: dependency: "direct main" description: @@ -96,6 +320,30 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + url: "https://pub.dev" + source: hosted + version: "7.6.7" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" go_router: dependency: "direct main" description: @@ -104,8 +352,40 @@ packages: url: "https://pub.dev" source: hosted version: "13.2.0" - http: + google_generative_ai: + dependency: "direct main" + description: + name: google_generative_ai + sha256: b2d3f7277a85e3e6be4c4392c59e73ea211b5b6c8bb21c24c71fd411a2d1822e + url: "https://pub.dev" + source: hosted + version: "0.2.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + hotreloader: dependency: transitive + description: + name: hotreloader + sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e + url: "https://pub.dev" + source: hosted + version: "4.2.0" + html: + dependency: "direct main" + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: "direct main" description: name: http sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" @@ -120,6 +400,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + url: "https://pub.dev" + source: hosted + version: "4.1.7" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" leak_tracker: dependency: transitive description: @@ -184,6 +488,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -200,6 +528,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" petitparser: dependency: transitive description: @@ -208,11 +584,139 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + url: "https://pub.dev" + source: hosted + version: "3.7.4" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + rive: + dependency: "direct main" + description: + name: rive + sha256: ae75a6e9cfbf146630bfb1feba97ee582d935508be6b362e4bd197b9c55a6dd3 + url: "https://pub.dev" + source: hosted + version: "0.12.4" + rive_common: + dependency: transitive + description: + name: rive_common + sha256: f4e20d0a99c5040c85624a3eb2b0b6b19e614d93a693c3bb25cf6e7bb2d3d6d3 + url: "https://pub.dev" + source: hosted + version: "0.2.8" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "548e2192eb7aeb826eb89387f814edb76594f3363e2c0bb99dd733d795ba3589" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: "8b71f03fc47ae27d13769496a1746332df4cec43918aeba9aff1e232783a780f" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + riverpod_annotation: + dependency: "direct main" + description: + name: riverpod_annotation + sha256: "77e5d51afa4fa3e67903fb8746f33d368728d7051a0b6c292bcee60aeba46d95" + url: "https://pub.dev" + source: hosted + version: "2.3.4" + riverpod_generator: + dependency: "direct dev" + description: + name: riverpod_generator + sha256: "359068f04879347ae4edbe66c81cc95f83fa1743806d1a0c86e55dd3c33ebb32" + url: "https://pub.dev" + source: hosted + version: "2.3.11" + riverpod_lint: + dependency: "direct dev" + description: + name: riverpod_lint + sha256: e9bbd02e9e89e18eecb183bbca556d7b523a0669024da9b8167c08903f442937 + url: "https://pub.dev" + source: hosted + version: "2.3.9" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" + url: "https://pub.dev" + source: hosted + version: "7.2.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 + url: "https://pub.dev" + source: hosted + version: "3.3.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" source_span: dependency: transitive description: @@ -221,6 +725,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" stack_trace: dependency: transitive description: @@ -229,6 +757,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" stream_channel: dependency: transitive description: @@ -237,6 +773,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -245,6 +789,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -269,6 +821,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + uuid: + dependency: transitive + description: + name: uuid + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + url: "https://pub.dev" + source: hosted + version: "4.3.3" vector_graphics: dependency: transitive description: @@ -309,6 +909,14 @@ packages: url: "https://pub.dev" source: hosted version: "13.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" web: dependency: transitive description: @@ -317,6 +925,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + win32: + dependency: transitive + description: + name: win32 + sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480" + url: "https://pub.dev" + source: hosted + version: "5.3.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" xml: dependency: transitive description: @@ -325,6 +949,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.13.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 89272c0..ddeb8d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,16 +7,32 @@ environment: sdk: '>=3.3.0 <4.0.0' dependencies: + async: ^2.11.0 bot_toast: ^4.1.3 + cached_network_image: ^3.3.1 flutter: sdk: flutter + flutter_riverpod: ^2.4.10 flutter_svg: ^2.0.10+1 + get_it: ^7.6.7 go_router: ^13.2.0 + google_generative_ai: ^0.2.2 + html: ^0.15.4 + http: ^1.2.1 + rive: ^0.12.4 + riverpod_annotation: ^2.3.4 + share_plus: ^7.2.2 + + dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 + riverpod_generator: ^2.3.5 + riverpod_lint: ^2.3.9 + flutter_launcher_icons: ^0.13.1 + flutter_native_splash: ^2.3.13 flutter: uses-material-design: true @@ -24,6 +40,7 @@ flutter: assets: - assets/images/ - assets/svgs/ + - assets/rive/ fonts: - family: Satoshi @@ -38,4 +55,32 @@ flutter: - asset: fonts/Satoshi-LightItalic.otf - asset: fonts/Satoshi-Medium.otf - asset: fonts/Satoshi-MediumItalic.otf - - asset: fonts/Satoshi-Regular.otf \ No newline at end of file + - asset: fonts/Satoshi-Regular.otf + + + +flutter_launcher_icons: + android: "launcher_icon" + ios: true + image_path: "assets/images/logo.jpg" + remove_alpha_ios: true + web: + generate: true + image_path: "assets/images/logo.jpg" + background_color: "#984061" + theme_color: "#984061" + windows: + generate: true + image_path: "assets/images/logo.jpg" + icon_size: 48 # min:48, max:256, default: 48 + macos: + generate: true + image_path: "assets/images/logo.jpg" + + +flutter_native_splash: + color: "#984061" + fullscreen: false + android_gravity: fill + ios_content_mode: scaleToFill + web_image_mode: cover \ No newline at end of file diff --git a/spider.yaml b/spider.yaml index ba1475e..f48bcd7 100644 --- a/spider.yaml +++ b/spider.yaml @@ -35,4 +35,7 @@ groups: types: [ .png, .jpg, .jpeg, .webp, .webm, .bmp ] - path: assets/svgs class_name: Svgs - types: [ .svg ] \ No newline at end of file + types: [ .svg ] + - path: assets/rive + class_name: RiveAssets + types: [ .riv ] \ No newline at end of file diff --git a/web/favicon.png b/web/favicon.png index 8aaa46a..2022511 100644 Binary files a/web/favicon.png and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png index b749bfe..73ab19c 100644 Binary files a/web/icons/Icon-192.png and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png index 88cfd48..ff6701e 100644 Binary files a/web/icons/Icon-512.png and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png index eb9b4d7..73ab19c 100644 Binary files a/web/icons/Icon-maskable-192.png and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png index d69c566..ff6701e 100644 Binary files a/web/icons/Icon-maskable-512.png and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html index c67036e..d3ae4c8 100644 --- a/web/index.html +++ b/web/index.html @@ -1,6 +1,4 @@ - - - + - + news_assistant @@ -37,7 +35,73 @@ const serviceWorkerVersion = null; - + + + + - - + + + \ No newline at end of file diff --git a/web/manifest.json b/web/manifest.json index 2066158..04848c2 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -3,8 +3,8 @@ "short_name": "news_assistant", "start_url": ".", "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", + "background_color": "#984061", + "theme_color": "#984061", "description": "A new Flutter project.", "orientation": "portrait-primary", "prefer_related_applications": false, @@ -32,4 +32,4 @@ "purpose": "maskable" } ] -} +} \ No newline at end of file diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..7546d6c 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,15 @@ #include "generated_plugin_registrant.h" +#include +#include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + RivePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RivePlugin")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..e603c71 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,9 @@ # list(APPEND FLUTTER_PLUGIN_LIST + rive_common + share_plus + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index c04e20c..6b149e4 100644 Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ