├── .github └── workflows │ └── deploy.yaml ├── .gitignore ├── .metadata ├── LICENSE.md ├── Makefile ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle.kts │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── dev │ │ │ │ └── aladdine │ │ │ │ └── portfolio │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ └── splash.png │ │ │ ├── drawable-mdpi │ │ │ └── splash.png │ │ │ ├── drawable-night-hdpi │ │ │ └── splash.png │ │ │ ├── drawable-night-mdpi │ │ │ └── splash.png │ │ │ ├── drawable-night-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-night-xhdpi │ │ │ └── splash.png │ │ │ ├── drawable-night-xxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-night-xxxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-night │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21 │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── drawable-xhdpi │ │ │ └── splash.png │ │ │ ├── drawable-xxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-xxxhdpi │ │ │ └── splash.png │ │ │ ├── drawable │ │ │ ├── background.png │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night-v31 │ │ │ └── styles.xml │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ ├── values-v31 │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle.kts ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle.kts ├── assets ├── fonts │ ├── BoxIcons.ttf │ ├── FontAwesome.ttf │ ├── Nunito-Bold.ttf │ ├── Nunito-Regular.ttf │ └── OctIcons.ttf ├── icons │ ├── flags │ │ ├── france.svg │ │ └── united-states-of-america.svg │ ├── other │ │ ├── bootstrap.svg │ │ ├── dart.svg │ │ ├── express-js.svg │ │ └── firebase.svg │ └── software-development │ │ ├── css3.svg │ │ ├── docker.svg │ │ ├── flask.svg │ │ ├── flutter.svg │ │ ├── graphql.svg │ │ ├── html-5.svg │ │ ├── javascript.svg │ │ ├── mariadb.svg │ │ ├── mongodb.svg │ │ ├── nodejs.svg │ │ ├── postgresql.svg │ │ ├── python.svg │ │ └── typescript.svg ├── images │ ├── gsb-frais.png │ ├── gsb-rv-dr.png │ ├── gsb-rv-visiteur-serveur.png │ ├── learnflow-api.png │ ├── learnflow-backoffice.png │ ├── logo.png │ ├── logo.svg │ ├── portfolio.png │ ├── spinner-dark.apng │ └── spinner-light.apng └── translations │ ├── en.json │ └── fr.json ├── build.yaml ├── docs ├── images │ ├── github-actions-enable-workflows.png │ ├── github-pages-branch-gh-pages.png │ ├── github-pages-branch-none.png │ ├── mockups-1.png │ ├── mockups-2.png │ └── screenshot-desktop.png ├── packages-in-use.md └── translation-template.md ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon-production.appiconset │ │ │ ├── AppIcon-production-1024x1024@1x.png │ │ │ ├── AppIcon-production-20x20@1x.png │ │ │ ├── AppIcon-production-20x20@2x.png │ │ │ ├── AppIcon-production-20x20@3x.png │ │ │ ├── AppIcon-production-29x29@1x.png │ │ │ ├── AppIcon-production-29x29@2x.png │ │ │ ├── AppIcon-production-29x29@3x.png │ │ │ ├── AppIcon-production-40x40@1x.png │ │ │ ├── AppIcon-production-40x40@2x.png │ │ │ ├── AppIcon-production-40x40@3x.png │ │ │ ├── AppIcon-production-50x50@1x.png │ │ │ ├── AppIcon-production-50x50@2x.png │ │ │ ├── AppIcon-production-57x57@1x.png │ │ │ ├── AppIcon-production-57x57@2x.png │ │ │ ├── AppIcon-production-60x60@2x.png │ │ │ ├── AppIcon-production-60x60@3x.png │ │ │ ├── AppIcon-production-72x72@1x.png │ │ │ ├── AppIcon-production-72x72@2x.png │ │ │ ├── AppIcon-production-76x76@1x.png │ │ │ ├── AppIcon-production-76x76@2x.png │ │ │ ├── AppIcon-production-83.5x83.5@2x.png │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-50x50@1x.png │ │ │ ├── Icon-App-50x50@2x.png │ │ │ ├── Icon-App-57x57@1x.png │ │ │ ├── Icon-App-57x57@2x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-72x72@1x.png │ │ │ ├── Icon-App-72x72@2x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ ├── LaunchBackground.imageset │ │ │ ├── Contents.json │ │ │ ├── background.png │ │ │ └── darkbackground.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── LaunchImageDark.png │ │ │ ├── LaunchImageDark@2x.png │ │ │ ├── LaunchImageDark@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h └── RunnerTests │ └── RunnerTests.swift ├── lib ├── main.dart └── src │ ├── app.dart │ ├── app_startup.dart │ ├── common │ ├── data │ │ └── language_repository.dart │ ├── domain │ │ ├── icon.dart │ │ ├── language.dart │ │ ├── link.dart │ │ └── technology.dart │ ├── provider │ │ └── shared_preferences_provider.dart │ └── widgets │ │ ├── animated_fade_slide.dart │ │ ├── icon.dart │ │ ├── link.dart │ │ ├── responsive.dart │ │ ├── selection_area.dart │ │ ├── technology_chip.dart │ │ ├── technology_wrap_chips.dart │ │ └── wrap_links.dart │ ├── constants │ ├── sizes.dart │ ├── themes.dart │ └── transparent_image.dart │ ├── features │ ├── about │ │ └── presentation │ │ │ ├── about_desktop.dart │ │ │ └── about_section.dart │ ├── experience │ │ ├── data │ │ │ └── experience_repository.dart │ │ ├── domain │ │ │ └── experience.dart │ │ └── presentation │ │ │ ├── experience_desktop.dart │ │ │ ├── experience_section.dart │ │ │ └── widgets │ │ │ ├── experience_card.dart │ │ │ └── experience_date_text.dart │ ├── general │ │ ├── presentation │ │ │ ├── general_section.dart │ │ │ ├── general_section_desktop.dart │ │ │ ├── general_section_tablet.dart │ │ │ └── widgets │ │ │ │ ├── app_bar.dart │ │ │ │ ├── app_bar_button.dart │ │ │ │ ├── bottom_banner.dart │ │ │ │ ├── dark_mode_switch.dart │ │ │ │ ├── drawer_button.dart │ │ │ │ ├── end_drawer.dart │ │ │ │ ├── locale_button.dart │ │ │ │ ├── safe_area.dart │ │ │ │ └── sliver_app_bar.dart │ │ └── provider │ │ │ ├── brightness_controller.dart │ │ │ ├── dark_mode_controller.dart │ │ │ ├── scroll_controller.dart │ │ │ └── section_key_provider.dart │ ├── personal_info │ │ ├── data │ │ │ └── personal_info_repository.dart │ │ ├── domain │ │ │ ├── contact.dart │ │ │ └── resume.dart │ │ └── presentation │ │ │ ├── personal_info_desktop.dart │ │ │ ├── personal_info_mobile.dart │ │ │ ├── personal_info_section.dart │ │ │ ├── personal_info_tablet.dart │ │ │ └── widgets │ │ │ ├── contact_bar.dart │ │ │ ├── contact_icon_button.dart │ │ │ ├── resume_button.dart │ │ │ ├── resume_language_dialog.dart │ │ │ └── resume_language_dialog_tile.dart │ └── project │ │ ├── data │ │ └── project_repository.dart │ │ ├── domain │ │ └── project.dart │ │ └── presentation │ │ ├── project_desktop.dart │ │ ├── project_section.dart │ │ └── widgets │ │ ├── project_card.dart │ │ ├── project_description.dart │ │ ├── project_icon.dart │ │ └── project_image.dart │ ├── localization │ ├── app_localizations.dart │ ├── json_list_translation.dart │ └── locale_controller.dart │ └── utils │ ├── launch_url_helper.dart │ ├── localized_date_extension.dart │ ├── scaffold_messenger_helper.dart │ └── string_extension.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── main.cc ├── my_application.cc ├── my_application.h └── runner │ ├── CMakeLists.txt │ ├── main.cc │ ├── my_application.cc │ └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements └── RunnerTests │ └── RunnerTests.swift ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── index.html ├── manifest.json └── splash │ └── img │ ├── dark-1x.png │ ├── dark-2x.png │ ├── dark-3x.png │ ├── dark-4x.png │ ├── light-1x.png │ ├── light-2x.png │ ├── light-3x.png │ └── light-4x.png └── windows ├── .gitignore ├── CMakeLists.txt ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '**.md' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-24.04 14 | permissions: 15 | contents: write 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.ref }} 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - uses: subosito/flutter-action@v2 22 | with: 23 | channel: 'stable' 24 | flutter-version: 3.32.0 25 | cache: true 26 | 27 | - name: Install dependencies 28 | run: flutter pub get 29 | 30 | - name: Code generation 31 | run: | 32 | dart run build_runner build -d 33 | dart run easy_localization:generate -S assets/translations -f json -O lib/src/localization/generated -o locale_json.g.dart 34 | dart run easy_localization:generate -S assets/translations -f keys -O lib/src/localization/generated -o locale_keys.g.dart 35 | 36 | - name: Set base-href 37 | id: set_base_href 38 | run: | 39 | if [[ -z "${{ vars.CNAME }}" ]]; then 40 | echo "base_href=/${{ github.event.repository.name }}/" >> $GITHUB_OUTPUT 41 | else 42 | echo "base_href=/" >> $GITHUB_OUTPUT 43 | fi 44 | 45 | - name: Build 46 | run: flutter build web --wasm --release --no-tree-shake-icons --base-href "${{ steps.set_base_href.outputs.base_href }}" 47 | 48 | - name: Deploy 49 | uses: peaceiris/actions-gh-pages@v3 50 | if: github.ref == 'refs/heads/main' 51 | with: 52 | github_token: ${{ secrets.GITHUB_TOKEN }} 53 | publish_dir: ./build/web 54 | cname: ${{ vars.CNAME }} 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | 48 | # Dart generated files 49 | *.g.dart 50 | *.freezed.dart 51 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "b25305a8832cfc6ba632a7f87ad455e319dccce8" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 17 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 18 | - platform: android 19 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 20 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 21 | - platform: ios 22 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 23 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 24 | - platform: linux 25 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 26 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 27 | - platform: macos 28 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 29 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 30 | - platform: web 31 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 32 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 33 | - platform: windows 34 | create_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 35 | base_revision: b25305a8832cfc6ba632a7f87ad455e319dccce8 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Aladdine Abdou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | localization: 2 | dart run easy_localization:generate -S assets/translations -f json -O lib/src/localization/generated -o locale_json.g.dart 3 | dart run easy_localization:generate -S assets/translations -f keys -O lib/src/localization/generated -o locale_keys.g.dart 4 | 5 | launcher_icons: 6 | dart run flutter_launcher_icons 7 | 8 | native_splash: 9 | dart run flutter_native_splash:create 10 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | analyzer: 13 | exclude: 14 | - "**/*.g.dart" 15 | - "**/*.freezed.dart" 16 | errors: 17 | invalid_annotation_target: ignore 18 | plugins: 19 | - custom_lint 20 | 21 | linter: 22 | # The lint rules applied to this project can be customized in the 23 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 24 | # included above or to enable additional rules. A list of all available lints 25 | # and their documentation is published at 26 | # https://dart-lang.github.io/linter/lints/index.html. 27 | # 28 | # Instead of disabling a lint rule for the entire project in the 29 | # section below, it can also be suppressed for a single line of code 30 | # or a specific dart file by using the `// ignore: name_of_lint` and 31 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 32 | # producing the lint. 33 | rules: 34 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 35 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 36 | 37 | # Additional information about this file can be found at 38 | # https://dart.dev/guides/language/analysis-options 39 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | .cxx/ 9 | 10 | # Remember to never publicly share your keystore. 11 | # See https://flutter.dev/to/reference-keystore 12 | key.properties 13 | **/*.keystore 14 | **/*.jks 15 | -------------------------------------------------------------------------------- /android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id("dev.flutter.flutter-gradle-plugin") 6 | } 7 | 8 | android { 9 | namespace = "dev.aladdine.portfolio" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = "27.0.12077973" 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_11 15 | targetCompatibility = JavaVersion.VERSION_11 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_11.toString() 20 | } 21 | 22 | defaultConfig { 23 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 24 | applicationId = "dev.aladdine.portfolio" 25 | // You can update the following values to match your application needs. 26 | // For more information, see: https://flutter.dev/to/review-gradle-config. 27 | minSdk = flutter.minSdkVersion 28 | targetSdk = flutter.targetSdkVersion 29 | versionCode = flutter.versionCode 30 | versionName = flutter.versionName 31 | } 32 | 33 | buildTypes { 34 | release { 35 | // TODO: Add your own signing config for the release build. 36 | // Signing with the debug keys for now, so `flutter run --release` works. 37 | signingConfig = signingConfigs.getByName("debug") 38 | } 39 | } 40 | } 41 | 42 | flutter { 43 | source = "../.." 44 | } 45 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/dev/aladdine/portfolio/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package dev.aladdine.portfolio 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-night/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-night/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-v21/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-v31/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.3" apply false 22 | id("org.jetbrains.kotlin.android") version "2.1.0" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /assets/fonts/BoxIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/fonts/BoxIcons.ttf -------------------------------------------------------------------------------- /assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /assets/fonts/Nunito-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/fonts/Nunito-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Nunito-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/fonts/Nunito-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/OctIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/fonts/OctIcons.ttf -------------------------------------------------------------------------------- /assets/icons/flags/france.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/united-states-of-america.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/other/bootstrap.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/other/dart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/other/express-js.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/other/firebase.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/css3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/docker.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/flutter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/graphql.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/html-5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/javascript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/mariadb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/mongodb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/nodejs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/python.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/software-development/typescript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/gsb-frais.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/gsb-frais.png -------------------------------------------------------------------------------- /assets/images/gsb-rv-dr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/gsb-rv-dr.png -------------------------------------------------------------------------------- /assets/images/gsb-rv-visiteur-serveur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/gsb-rv-visiteur-serveur.png -------------------------------------------------------------------------------- /assets/images/learnflow-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/learnflow-api.png -------------------------------------------------------------------------------- /assets/images/learnflow-backoffice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/learnflow-backoffice.png -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/logo.png -------------------------------------------------------------------------------- /assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Layer 1 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Layer 1 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /assets/images/portfolio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/portfolio.png -------------------------------------------------------------------------------- /assets/images/spinner-dark.apng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/spinner-dark.apng -------------------------------------------------------------------------------- /assets/images/spinner-light.apng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/assets/images/spinner-light.apng -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | json_serializable: 5 | options: 6 | # Options configure how source code is generated for every 7 | # `@JsonSerializable`-annotated class in the package. 8 | # 9 | # The default value for each is listed. 10 | # any_map: false 11 | # checked: false 12 | # constructor: "" 13 | # create_factory: true 14 | # create_field_map: false 15 | # create_per_field_to_json: false 16 | # create_to_json: true 17 | # disallow_unrecognized_keys: false 18 | explicit_to_json: true 19 | # generic_argument_factories: false 20 | # ignore_unannotated: false 21 | # include_if_null: true -------------------------------------------------------------------------------- /docs/images/github-actions-enable-workflows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/docs/images/github-actions-enable-workflows.png -------------------------------------------------------------------------------- /docs/images/github-pages-branch-gh-pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/docs/images/github-pages-branch-gh-pages.png -------------------------------------------------------------------------------- /docs/images/github-pages-branch-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/docs/images/github-pages-branch-none.png -------------------------------------------------------------------------------- /docs/images/mockups-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/docs/images/mockups-1.png -------------------------------------------------------------------------------- /docs/images/mockups-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/docs/images/mockups-2.png -------------------------------------------------------------------------------- /docs/images/screenshot-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/docs/images/screenshot-desktop.png -------------------------------------------------------------------------------- /docs/packages-in-use.md: -------------------------------------------------------------------------------- 1 | ## Packages in use 📦 2 | 3 | These are the main packages used in the app: 4 | 5 | - [Hooks Riverpod](https://pub.dev/packages/hooks_riverpod) for state-management 6 | - [Flutter Hooks](https://pub.dev/packages/flutter_hooks) to reduce boilerplate code of stateful widgets and increase code reusability 7 | - [Freezed](https://pub.dev/packages/freezed) to reduce boilerplate code in model classes 8 | - [Flex Color Scheme](https://pub.dev/packages/flex_color_scheme) to make AWESOME Flutter Material Design themes 9 | - [Google Fonts](https://pub.dev/packages/google_fonts) to use fonts from https://fonts.google.com 10 | - [Icons Plus](https://pub.dev/packages/icons_plus) to use a collection of attractive icons from different packs 11 | - [Easy Localization](https://pub.dev/packages/easy_localization) for... easy localization 12 | - [Intl](https://pub.dev/packages/intl) for date formatting 13 | - [Shared Preferences](https://pub.dev/packages/shared_preferences) for persistent storage (used to store theme state) 14 | 15 | See the [`pubspec.yaml`](pubspec.yaml) file for the complete list 16 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_native_splash (2.4.3): 4 | - Flutter 5 | - path_provider_foundation (0.0.1): 6 | - Flutter 7 | - FlutterMacOS 8 | - shared_preferences_foundation (0.0.1): 9 | - Flutter 10 | - FlutterMacOS 11 | - url_launcher_ios (0.0.1): 12 | - Flutter 13 | 14 | DEPENDENCIES: 15 | - Flutter (from `Flutter`) 16 | - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) 17 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) 18 | - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) 19 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 20 | 21 | EXTERNAL SOURCES: 22 | Flutter: 23 | :path: Flutter 24 | flutter_native_splash: 25 | :path: ".symlinks/plugins/flutter_native_splash/ios" 26 | path_provider_foundation: 27 | :path: ".symlinks/plugins/path_provider_foundation/darwin" 28 | shared_preferences_foundation: 29 | :path: ".symlinks/plugins/shared_preferences_foundation/darwin" 30 | url_launcher_ios: 31 | :path: ".symlinks/plugins/url_launcher_ios/ios" 32 | 33 | SPEC CHECKSUMS: 34 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 35 | flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a 36 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 37 | shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 38 | url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe 39 | 40 | PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 41 | 42 | COCOAPODS: 1.12.1 43 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-50x50@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-50x50@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-57x57@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-57x57@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-72x72@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-72x72@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon-production.appiconset/AppIcon-production-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon-production.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-production-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-production-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-production-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-production-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-production-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-production-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-production-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-production-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-production-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-production-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-production-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-production-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-production-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-production-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-production-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-production-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-production-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-production-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-production-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-production-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-production-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-production-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-production-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-production-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-production-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "background.png", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "darkbackground.png", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "LaunchImage.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "LaunchImageDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "LaunchImage@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "LaunchImageDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "filename" : "LaunchImage@3x.png", 37 | "idiom" : "universal", 38 | "scale" : "3x" 39 | }, 40 | { 41 | "appearances" : [ 42 | { 43 | "appearance" : "luminosity", 44 | "value" : "dark" 45 | } 46 | ], 47 | "filename" : "LaunchImageDark@3x.png", 48 | "idiom" : "universal", 49 | "scale" : "3x" 50 | } 51 | ], 52 | "info" : { 53 | "author" : "xcode", 54 | "version" : 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | Portfolio 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | portfolio 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | UIApplicationSupportsIndirectInputEvents 30 | 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UIMainStoryboardFile 34 | Main 35 | UIStatusBarHidden 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | LSApplicationQueriesSchemes 53 | 54 | sms 55 | tel 56 | mailto 57 | https 58 | file 59 | 60 | CFBundleLocalizations 61 | 62 | en 63 | fr 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:google_fonts/google_fonts.dart'; 5 | import 'package:flutter_web_plugins/url_strategy.dart'; 6 | import 'package:portfolio/src/app.dart'; 7 | import 'package:portfolio/src/app_startup.dart'; 8 | import 'package:portfolio/src/localization/app_localizations.dart'; 9 | import 'package:portfolio/src/localization/locale_controller.dart'; 10 | 11 | void main() async { 12 | WidgetsFlutterBinding.ensureInitialized(); 13 | EasyLocalization.logger.enableBuildModes = []; 14 | usePathUrlStrategy(); 15 | GoogleFonts.config.allowRuntimeFetching = false; 16 | final supportedLocales = await AppLocalizations.supportedLocales(); 17 | runApp( 18 | ProviderScope( 19 | child: AppStartupWidget( 20 | onLoaded: (context) { 21 | return Consumer( 22 | builder: (context, ref, child) { 23 | ref.watch(localeControllerProvider); 24 | return EasyLocalization( 25 | supportedLocales: supportedLocales, 26 | path: AppLocalizations.translationsPath, 27 | fallbackLocale: supportedLocales.first, 28 | child: const MyApp(), 29 | ); 30 | }, 31 | ); 32 | }, 33 | ), 34 | ), 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/constants/themes.dart' as themes; 4 | import 'package:portfolio/src/features/general/presentation/general_section.dart'; 5 | import 'package:portfolio/src/features/general/provider/dark_mode_controller.dart'; 6 | import 'package:easy_localization/easy_localization.dart'; 7 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 8 | 9 | class MyApp extends ConsumerWidget { 10 | const MyApp({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context, WidgetRef ref) { 14 | return MaterialApp( 15 | debugShowCheckedModeBanner: false, 16 | onGenerateTitle: (_) => tr(LocaleKeys.name), 17 | localizationsDelegates: context.localizationDelegates, 18 | supportedLocales: context.supportedLocales, 19 | locale: context.locale, 20 | theme: themes.lightTheme, 21 | darkTheme: themes.darkTheme, 22 | themeMode: ref.watch(darkModeProvider).maybeWhen( 23 | data: (darkMode) => darkMode ? ThemeMode.dark : ThemeMode.light, 24 | orElse: () => ThemeMode.system, 25 | ), 26 | home: const GeneralSection(), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/app_startup.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:portfolio/src/constants/sizes.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'app_startup.g.dart'; 9 | 10 | @Riverpod(keepAlive: true) 11 | Future appStartup(Ref ref) async { 12 | await Future.wait([ 13 | EasyLocalization.ensureInitialized(), 14 | GoogleFonts.pendingFonts([GoogleFonts.nunito()]), 15 | ]); 16 | } 17 | 18 | class AppStartupWidget extends ConsumerWidget { 19 | const AppStartupWidget({ 20 | super.key, 21 | required this.onLoaded, 22 | }); 23 | 24 | final WidgetBuilder onLoaded; 25 | 26 | @override 27 | Widget build(BuildContext context, WidgetRef ref) { 28 | final appStartupState = ref.watch(appStartupProvider); 29 | return appStartupState.when( 30 | data: (_) => onLoaded(context), 31 | loading: () => const AppStartupLoadingWidget(), 32 | error: (error, stackTrace) => AppStartupErrorWidget( 33 | message: error.toString(), 34 | onRetry: () => ref.invalidate(appStartupProvider), 35 | ), 36 | ); 37 | } 38 | } 39 | 40 | class AppStartupLoadingWidget extends StatelessWidget { 41 | const AppStartupLoadingWidget({super.key}); 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | return const SizedBox.shrink(); 46 | } 47 | } 48 | 49 | class AppStartupErrorWidget extends StatelessWidget { 50 | const AppStartupErrorWidget({ 51 | super.key, 52 | required this.message, 53 | required this.onRetry, 54 | }); 55 | 56 | final String message; 57 | final VoidCallback onRetry; 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | return MaterialApp( 62 | home: Scaffold( 63 | body: Center( 64 | child: Column( 65 | mainAxisSize: MainAxisSize.min, 66 | children: [ 67 | Text( 68 | message, 69 | style: Theme.of(context).textTheme.headlineSmall, 70 | ), 71 | gapH16, 72 | ElevatedButton( 73 | onPressed: onRetry, 74 | child: const Icon(Icons.restart_alt), 75 | ), 76 | ], 77 | ), 78 | ), 79 | ), 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/common/data/language_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 2 | import 'package:portfolio/src/common/domain/language.dart'; 3 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 4 | import 'package:portfolio/src/localization/json_list_translation.dart'; 5 | import 'package:portfolio/src/localization/locale_controller.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'language_repository.g.dart'; 9 | 10 | @riverpod 11 | LanguageRepository languageRepository(Ref ref) { 12 | return LanguageRepository(ref); 13 | } 14 | 15 | class LanguageRepository { 16 | LanguageRepository(this._ref); 17 | 18 | final Ref _ref; 19 | 20 | List getLanguages() { 21 | final locale = _ref.watch(localeControllerProvider).requireValue.locale; 22 | final jsonLanguages = trList(locale, LocaleKeys.languages); 23 | final languages = jsonLanguages.map((jsonLanguage) { 24 | return Language.fromJson(jsonLanguage); 25 | }).toList(); 26 | return languages; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/common/domain/icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'icon.freezed.dart'; 4 | part 'icon.g.dart'; 5 | 6 | @freezed 7 | class IconModel with _$IconModel { 8 | const factory IconModel({ 9 | String? assetName, 10 | String? codePoint, 11 | String? fontFamily, 12 | String? color, 13 | }) = _IconModel; 14 | 15 | factory IconModel.fromJson(Map json) => 16 | _$IconModelFromJson(json); 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/common/domain/language.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:portfolio/src/common/domain/icon.dart'; 3 | 4 | part 'language.freezed.dart'; 5 | part 'language.g.dart'; 6 | 7 | @freezed 8 | class Language with _$Language { 9 | const factory Language({ 10 | String? code, 11 | String? name, 12 | String? nativeName, 13 | IconModel? icon, 14 | }) = _Language; 15 | 16 | factory Language.fromJson(Map json) => 17 | _$LanguageFromJson(json); 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/common/domain/link.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'link.freezed.dart'; 4 | part 'link.g.dart'; 5 | 6 | @freezed 7 | class Link with _$Link { 8 | const factory Link({ 9 | String? url, 10 | String? display, 11 | }) = _Link; 12 | 13 | factory Link.fromJson(Map json) => _$LinkFromJson(json); 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/common/domain/technology.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:portfolio/src/common/domain/icon.dart'; 3 | 4 | part 'technology.freezed.dart'; 5 | part 'technology.g.dart'; 6 | 7 | @freezed 8 | class Technology with _$Technology { 9 | const factory Technology({ 10 | String? name, 11 | IconModel? icon, 12 | }) = _Technology; 13 | 14 | factory Technology.fromJson(Map json) => 15 | _$TechnologyFromJson(json); 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/common/provider/shared_preferences_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 2 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | 5 | part 'shared_preferences_provider.g.dart'; 6 | 7 | @riverpod 8 | FutureOr sharedPreferences(Ref ref) async { 9 | return await SharedPreferences.getInstance(); 10 | } 11 | -------------------------------------------------------------------------------- /lib/src/common/widgets/animated_fade_slide.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:flutter_hooks/flutter_hooks.dart'; 4 | 5 | class AnimatedFadeSlide extends HookConsumerWidget { 6 | const AnimatedFadeSlide({ 7 | super.key, 8 | this.delay = const Duration(milliseconds: 0), 9 | this.duration = const Duration(milliseconds: 500), 10 | this.offset = const Offset(0, -64), 11 | required this.child, 12 | }); 13 | 14 | final Duration delay; 15 | final Duration duration; 16 | final Offset offset; 17 | final Widget child; 18 | 19 | @override 20 | Widget build(BuildContext context, WidgetRef ref) { 21 | final controller = useAnimationController(duration: duration); 22 | final curveAnimation = CurvedAnimation( 23 | parent: controller, 24 | curve: Curves.decelerate, 25 | ); 26 | final dxAnimation = useAnimation( 27 | Tween(begin: offset.dx, end: 0.0).animate(curveAnimation), 28 | ); 29 | final dyAnimation = useAnimation( 30 | Tween(begin: offset.dy, end: 0.0).animate(curveAnimation), 31 | ); 32 | 33 | useEffect(() { 34 | Future.delayed(delay, () { 35 | if (context.mounted) { 36 | controller.forward(); 37 | } 38 | }); 39 | return null; 40 | }, [controller]); 41 | 42 | return AnimatedBuilder( 43 | animation: controller, 44 | builder: (_, child) { 45 | return Opacity( 46 | opacity: controller.value, 47 | child: Transform.translate( 48 | offset: Offset(dxAnimation, dyAnimation), 49 | child: child, 50 | ), 51 | ); 52 | }, 53 | child: child, 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/common/widgets/icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/common/domain/icon.dart'; 5 | 6 | class MyIcon extends ConsumerWidget { 7 | const MyIcon({ 8 | super.key, 9 | this.icon, 10 | this.placeholder = const SizedBox.shrink(), 11 | this.size = 24, 12 | this.padding, 13 | }); 14 | 15 | final IconModel? icon; 16 | final double? size; 17 | final Widget placeholder; 18 | final EdgeInsetsGeometry? padding; 19 | 20 | @override 21 | Widget build(BuildContext context, WidgetRef ref) { 22 | final iconAssetName = icon?.assetName; 23 | final iconCodePoint = icon?.codePoint; 24 | final iconFontFamily = icon?.fontFamily; 25 | final iconColor = icon?.color; 26 | Color? color; 27 | if (iconColor != null) { 28 | final colorHex = int.tryParse(iconColor); 29 | if (colorHex != null) { 30 | color = Color(colorHex); 31 | } 32 | } 33 | if (iconCodePoint != null && iconFontFamily != null) { 34 | final iconCodePointHexa = int.tryParse(iconCodePoint); 35 | if (iconCodePointHexa != null) { 36 | final iconData = IconData( 37 | iconCodePointHexa, 38 | fontFamily: iconFontFamily, 39 | ); 40 | return Padding( 41 | padding: const EdgeInsets.all(2), 42 | child: FittedBox( 43 | child: Icon( 44 | iconData, 45 | color: color, 46 | size: size, 47 | ), 48 | ), 49 | ); 50 | } 51 | } else if (iconAssetName != null) { 52 | return SvgPicture.asset( 53 | iconAssetName, 54 | width: size, 55 | colorFilter: 56 | color == null ? null : ColorFilter.mode(color, BlendMode.srcIn), 57 | ); 58 | } 59 | return placeholder; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/common/widgets/responsive.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | 4 | class Responsive extends ConsumerWidget { 5 | final Widget desktop; 6 | final Widget? tablet; 7 | final Widget? mobile; 8 | 9 | const Responsive({ 10 | super.key, 11 | required this.desktop, 12 | this.tablet, 13 | this.mobile, 14 | }); 15 | 16 | static bool isDesktop(BuildContext context) => 17 | MediaQuery.sizeOf(context).width >= 1024; 18 | 19 | static bool isTablet(BuildContext context) => 20 | MediaQuery.sizeOf(context).width < 1024 && 21 | MediaQuery.sizeOf(context).width >= 640; 22 | 23 | static bool isMobile(BuildContext context) => 24 | MediaQuery.sizeOf(context).width < 640; 25 | 26 | @override 27 | Widget build(BuildContext context, WidgetRef ref) { 28 | final maxWidth = MediaQuery.sizeOf(context).width; 29 | if (maxWidth < 640 && mobile != null) { 30 | return mobile!; 31 | } else if (maxWidth < 1024 && tablet != null) { 32 | return tablet!; 33 | } else { 34 | return desktop; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/common/widgets/selection_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | 4 | class MySelectionArea extends ConsumerWidget { 5 | const MySelectionArea({ 6 | super.key, 7 | required this.child, 8 | this.mouseCursor = WidgetStateMouseCursor.textable, 9 | }); 10 | 11 | final Widget child; 12 | final MouseCursor mouseCursor; 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | return DefaultSelectionStyle( 17 | selectionColor: Theme.of(context).colorScheme.tertiary, 18 | mouseCursor: mouseCursor, 19 | child: SelectionArea( 20 | child: child, 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/common/widgets/technology_chip.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:portfolio/src/common/domain/technology.dart'; 3 | import 'package:portfolio/src/common/widgets/icon.dart'; 4 | import 'package:portfolio/src/constants/sizes.dart'; 5 | 6 | class TechnologyChip extends StatelessWidget { 7 | const TechnologyChip({super.key, required this.technology}); 8 | 9 | final Technology technology; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | padding: const EdgeInsets.symmetric(horizontal: 8), 15 | clipBehavior: Clip.hardEdge, 16 | decoration: BoxDecoration( 17 | color: Theme.of(context).colorScheme.secondary, 18 | borderRadius: const BorderRadius.all(Radius.circular(32)), 19 | ), 20 | height: 32, 21 | child: _buildTechnologyChip(context: context, technology: technology), 22 | ); 23 | } 24 | 25 | Widget? _buildTechnologyChip({ 26 | required BuildContext context, 27 | required Technology technology, 28 | }) { 29 | final technologyName = technology.name; 30 | final technologyIcon = technology.icon; 31 | if (technologyName == null) return null; 32 | return Row( 33 | mainAxisSize: MainAxisSize.min, 34 | children: [ 35 | if (technologyIcon == null) 36 | gapW4 37 | else 38 | Padding( 39 | padding: const EdgeInsets.fromLTRB(2, 4, 4, 4), 40 | child: MyIcon( 41 | icon: technologyIcon, 42 | size: 32, 43 | ), 44 | ), 45 | Text( 46 | technologyName, 47 | style: Theme.of(context).textTheme.bodySmall, 48 | ), 49 | gapW4 50 | ], 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/src/common/widgets/technology_wrap_chips.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/common/domain/technology.dart'; 4 | import 'package:portfolio/src/common/widgets/technology_chip.dart'; 5 | 6 | class TechnologyWrapChips extends ConsumerWidget { 7 | const TechnologyWrapChips({ 8 | super.key, 9 | required this.technologies, 10 | }); 11 | 12 | final List technologies; 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | return Wrap( 17 | spacing: 8, 18 | runSpacing: 8, 19 | children: technologies.map((technology) { 20 | return TechnologyChip(technology: technology); 21 | }).toList(), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/common/widgets/wrap_links.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/common/domain/link.dart'; 4 | import 'package:portfolio/src/common/widgets/link.dart'; 5 | 6 | class WrapLinks extends ConsumerWidget { 7 | const WrapLinks({ 8 | super.key, 9 | required this.links, 10 | }); 11 | 12 | final List links; 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | return Wrap( 17 | spacing: 16, 18 | runSpacing: 4, 19 | children: links.where((link) => link.url != null).map((link) { 20 | final projectLinkUrl = link.url; 21 | final projectLinkDisplay = link.display; 22 | if (projectLinkUrl == null) return const SizedBox.shrink(); 23 | return MyLink( 24 | url: projectLinkUrl, 25 | displayLink: projectLinkDisplay ?? projectLinkUrl, 26 | displayLeadingIcon: true, 27 | ); 28 | }).toList(), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/constants/sizes.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Sizes { 4 | static const p4 = 4.0; 5 | static const p8 = 8.0; 6 | static const p12 = 12.0; 7 | static const p16 = 16.0; 8 | static const p20 = 20.0; 9 | static const p24 = 24.0; 10 | static const p32 = 32.0; 11 | static const p40 = 40.0; 12 | static const p48 = 48.0; 13 | static const p64 = 64.0; 14 | static const p80 = 80.0; 15 | static const p100 = 100.0; 16 | static const p120 = 120.0; 17 | } 18 | 19 | const gapW4 = SizedBox(width: Sizes.p4); 20 | const gapW8 = SizedBox(width: Sizes.p8); 21 | const gapW12 = SizedBox(width: Sizes.p12); 22 | const gapW16 = SizedBox(width: Sizes.p16); 23 | const gapW20 = SizedBox(width: Sizes.p20); 24 | const gapW24 = SizedBox(width: Sizes.p24); 25 | const gapW32 = SizedBox(width: Sizes.p32); 26 | const gapW40 = SizedBox(width: Sizes.p40); 27 | const gapW48 = SizedBox(width: Sizes.p48); 28 | const gapW64 = SizedBox(width: Sizes.p64); 29 | const gapW80 = SizedBox(width: Sizes.p80); 30 | const gapW100 = SizedBox(width: Sizes.p100); 31 | const gapW120 = SizedBox(width: Sizes.p120); 32 | 33 | const gapH4 = SizedBox(height: Sizes.p4); 34 | const gapH8 = SizedBox(height: Sizes.p8); 35 | const gapH12 = SizedBox(height: Sizes.p12); 36 | const gapH16 = SizedBox(height: Sizes.p16); 37 | const gapH20 = SizedBox(height: Sizes.p20); 38 | const gapH24 = SizedBox(height: Sizes.p24); 39 | const gapH32 = SizedBox(height: Sizes.p32); 40 | const gapH40 = SizedBox(height: Sizes.p40); 41 | const gapH48 = SizedBox(height: Sizes.p48); 42 | const gapH64 = SizedBox(height: Sizes.p64); 43 | const gapH80 = SizedBox(height: Sizes.p80); 44 | const gapH100 = SizedBox(height: Sizes.p100); 45 | const gapH120 = SizedBox(height: Sizes.p120); 46 | -------------------------------------------------------------------------------- /lib/src/constants/transparent_image.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | final Uint8List transparentImage = Uint8List.fromList([ 4 | 0x89, 5 | 0x50, 6 | 0x4E, 7 | 0x47, 8 | 0x0D, 9 | 0x0A, 10 | 0x1A, 11 | 0x0A, 12 | 0x00, 13 | 0x00, 14 | 0x00, 15 | 0x0D, 16 | 0x49, 17 | 0x48, 18 | 0x44, 19 | 0x52, 20 | 0x00, 21 | 0x00, 22 | 0x00, 23 | 0x01, 24 | 0x00, 25 | 0x00, 26 | 0x00, 27 | 0x01, 28 | 0x08, 29 | 0x06, 30 | 0x00, 31 | 0x00, 32 | 0x00, 33 | 0x1F, 34 | 0x15, 35 | 0xC4, 36 | 0x89, 37 | 0x00, 38 | 0x00, 39 | 0x00, 40 | 0x0A, 41 | 0x49, 42 | 0x44, 43 | 0x41, 44 | 0x54, 45 | 0x78, 46 | 0x9C, 47 | 0x63, 48 | 0x00, 49 | 0x01, 50 | 0x00, 51 | 0x00, 52 | 0x05, 53 | 0x00, 54 | 0x01, 55 | 0x0D, 56 | 0x0A, 57 | 0x2D, 58 | 0xB4, 59 | 0x00, 60 | 0x00, 61 | 0x00, 62 | 0x00, 63 | 0x49, 64 | 0x45, 65 | 0x4E, 66 | 0x44, 67 | 0xAE, 68 | 0x42, 69 | 0x60, 70 | 0x82, 71 | ]); 72 | -------------------------------------------------------------------------------- /lib/src/features/about/presentation/about_desktop.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 5 | 6 | class AboutDesktop extends ConsumerWidget { 7 | const AboutDesktop({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return Column( 12 | crossAxisAlignment: CrossAxisAlignment.start, 13 | children: [ 14 | Padding( 15 | padding: const EdgeInsets.only(bottom: 32), 16 | child: Text( 17 | tr(LocaleKeys.aboutSectionTitleAlt), 18 | style: Theme.of(context).textTheme.titleLarge, 19 | ), 20 | ), 21 | Text( 22 | tr(LocaleKeys.aboutDescription), 23 | style: Theme.of(context).textTheme.bodyLarge, 24 | ), 25 | ], 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/features/about/presentation/about_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/about/presentation/about_desktop.dart'; 4 | import 'package:portfolio/src/common/widgets/responsive.dart'; 5 | 6 | class AboutSection extends ConsumerWidget { 7 | const AboutSection({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return const Responsive( 12 | desktop: AboutDesktop(), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/features/experience/data/experience_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 2 | import 'package:portfolio/src/features/experience/domain/experience.dart'; 3 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 4 | import 'package:portfolio/src/localization/json_list_translation.dart'; 5 | import 'package:portfolio/src/localization/locale_controller.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'experience_repository.g.dart'; 9 | 10 | @riverpod 11 | ExperienceRepository experienceRepository(Ref ref) { 12 | return ExperienceRepository(ref); 13 | } 14 | 15 | class ExperienceRepository { 16 | ExperienceRepository(this._ref); 17 | 18 | final Ref _ref; 19 | 20 | List getExperiences() { 21 | final locale = _ref.watch(localeControllerProvider).requireValue.locale; 22 | final jsonExperiences = trList(locale, LocaleKeys.experiences); 23 | final experiences = jsonExperiences.map((jsonExperience) { 24 | return Experience.fromJson(jsonExperience); 25 | }).toList(); 26 | return experiences; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/features/experience/domain/experience.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:portfolio/src/common/domain/link.dart'; 3 | import 'package:portfolio/src/common/domain/technology.dart'; 4 | 5 | part 'experience.freezed.dart'; 6 | part 'experience.g.dart'; 7 | 8 | @freezed 9 | class Experience with _$Experience { 10 | const factory Experience({ 11 | String? role, 12 | String? company, 13 | String? description, 14 | String? url, 15 | bool? isPresent, 16 | int? startYear, 17 | int? startMonth, 18 | int? endYear, 19 | int? endMonth, 20 | List? technologies, 21 | List? links, 22 | }) = _Experience; 23 | 24 | factory Experience.fromJson(Map json) => 25 | _$ExperienceFromJson(json); 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/features/experience/presentation/experience_desktop.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:portfolio/src/constants/sizes.dart'; 6 | import 'package:portfolio/src/features/experience/data/experience_repository.dart'; 7 | import 'package:portfolio/src/features/experience/presentation/widgets/experience_card.dart'; 8 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 9 | 10 | class ExperienceDesktop extends ConsumerWidget { 11 | const ExperienceDesktop({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context, WidgetRef ref) { 15 | final experiences = 16 | ref.watch(experienceRepositoryProvider).getExperiences(); 17 | 18 | return Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Padding( 22 | padding: const EdgeInsets.only(left: 12, bottom: 20), 23 | child: Text( 24 | tr(LocaleKeys.experienceSectionTitle), 25 | style: Theme.of(context).textTheme.titleLarge, 26 | ), 27 | ), 28 | ...experiences.mapIndexed((index, experience) { 29 | return Column( 30 | children: [ 31 | ExperienceCard(experience: experience), 32 | if (index != experiences.length - 1) gapH24, 33 | ], 34 | ); 35 | }), 36 | ], 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/features/experience/presentation/experience_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/experience/presentation/experience_desktop.dart'; 4 | import 'package:portfolio/src/common/widgets/responsive.dart'; 5 | 6 | class ExperienceSection extends ConsumerWidget { 7 | const ExperienceSection({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return const Responsive( 12 | desktop: ExperienceDesktop(), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/features/experience/presentation/widgets/experience_date_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/features/experience/domain/experience.dart'; 5 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 6 | import 'package:portfolio/src/utils/localized_date_extension.dart'; 7 | import 'package:portfolio/src/utils/string_extension.dart'; 8 | 9 | class ExperienceDateText extends ConsumerWidget { 10 | const ExperienceDateText({super.key, required this.experience}); 11 | 12 | final Experience experience; 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | final locale = context.locale; 17 | final startMonth = experience.startMonth?.localizedMonth(locale) ?? ""; 18 | final startYear = experience.startYear?.localizedYear(locale); 19 | final startDate = startMonth.isEmpty ? startYear : "$startMonth $startYear"; 20 | final endMonth = experience.endMonth?.localizedMonth(locale) ?? ""; 21 | final endYear = experience.endYear?.localizedYear(locale); 22 | String? endDate; 23 | if (experience.isPresent == true) { 24 | endDate = tr(LocaleKeys.present); 25 | } else { 26 | endDate = endMonth.isEmpty ? endYear : "$endMonth $endYear"; 27 | } 28 | if (startDate == null || endDate == null) return const Text(""); 29 | return Text( 30 | "${startDate.capitalize()} - ${endDate.capitalize()}", 31 | style: Theme.of(context).textTheme.bodyMedium, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/general_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/general/presentation/general_section_desktop.dart'; 4 | import 'package:portfolio/src/features/general/presentation/general_section_tablet.dart'; 5 | import 'package:portfolio/src/features/general/presentation/widgets/bottom_banner.dart'; 6 | import 'package:portfolio/src/features/general/presentation/widgets/end_drawer.dart'; 7 | import 'package:portfolio/src/features/general/presentation/widgets/safe_area.dart'; 8 | import 'package:portfolio/src/common/widgets/responsive.dart'; 9 | 10 | class GeneralSection extends ConsumerWidget { 11 | const GeneralSection({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context, WidgetRef ref) { 15 | return Scaffold( 16 | backgroundColor: Theme.of(context).colorScheme.secondary, 17 | endDrawer: const MySafeArea( 18 | child: EndDrawer(), 19 | ), 20 | body: const MySafeArea( 21 | child: Stack( 22 | children: [ 23 | Responsive( 24 | desktop: GeneralDesktop(), 25 | tablet: GeneralTablet(), 26 | ), 27 | Align( 28 | alignment: Alignment.bottomCenter, 29 | child: BottomBanner(), 30 | ) 31 | ], 32 | ), 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/widgets/app_bar_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | 4 | class AppBarButton extends ConsumerWidget { 5 | const AppBarButton({super.key, this.onPressed, required this.title}); 6 | 7 | final VoidCallback? onPressed; 8 | final String title; 9 | 10 | @override 11 | Widget build(BuildContext context, WidgetRef ref) { 12 | return MaterialButton( 13 | hoverColor: Theme.of(context).colorScheme.primary, 14 | splashColor: Theme.of(context).colorScheme.tertiary, 15 | shape: const Border(), 16 | onPressed: onPressed, 17 | child: SizedBox( 18 | height: kToolbarHeight, 19 | child: Center( 20 | child: Text( 21 | title, 22 | style: Theme.of(context).textTheme.titleMedium, 23 | ), 24 | ), 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/widgets/dark_mode_switch.dart: -------------------------------------------------------------------------------- 1 | import 'package:animated_toggle_switch/animated_toggle_switch.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/features/general/provider/dark_mode_controller.dart'; 5 | 6 | class DarkModeSwitch extends ConsumerWidget { 7 | const DarkModeSwitch({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return SelectionContainer.disabled( 12 | child: AnimatedToggleSwitch.dual( 13 | current: _getDarkMode(ref), 14 | onChanged: (_) => ref.read(darkModeProvider.notifier).updateTheme(), 15 | first: false, 16 | second: true, 17 | spacing: 8, 18 | height: 36, 19 | indicatorSize: const Size.square(32), 20 | animationCurve: Curves.decelerate, 21 | style: ToggleStyle( 22 | backgroundColor: Theme.of(context).colorScheme.primary, 23 | borderColor: Colors.transparent, 24 | ), 25 | styleBuilder: (_) => ToggleStyle( 26 | indicatorColor: _getDarkMode(ref) 27 | ? Theme.of(context).colorScheme.onPrimary 28 | : Theme.of(context).switchTheme.thumbColor?.resolve({}), 29 | ), 30 | iconBuilder: (darkMode) { 31 | return _buildSwitchIcon( 32 | ref: ref, 33 | context: context, 34 | darkMode: darkMode, 35 | ); 36 | }, 37 | textBuilder: (darkMode) { 38 | return _buildSwitchIcon( 39 | ref: ref, 40 | context: context, 41 | darkMode: !darkMode, 42 | ); 43 | }, 44 | ), 45 | ); 46 | } 47 | 48 | bool _getDarkMode(WidgetRef ref) { 49 | return ref.watch(darkModeProvider).maybeWhen( 50 | data: (darkMode) => darkMode, 51 | orElse: () => ThemeMode.system == ThemeMode.dark, 52 | ); 53 | } 54 | 55 | Icon _buildSwitchIcon({ 56 | required WidgetRef ref, 57 | required BuildContext context, 58 | required bool darkMode, 59 | }) { 60 | if (darkMode) { 61 | if (_getDarkMode(ref)) { 62 | return Icon( 63 | Icons.mode_night_outlined, 64 | color: Theme.of(context).colorScheme.onInverseSurface, 65 | ); 66 | } 67 | return const Icon(Icons.mode_night_outlined); 68 | } 69 | if (!_getDarkMode(ref)) { 70 | return Icon( 71 | Icons.wb_sunny_outlined, 72 | color: Theme.of(context).colorScheme.onInverseSurface, 73 | ); 74 | } 75 | return const Icon(Icons.wb_sunny_outlined); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/widgets/drawer_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_hooks/flutter_hooks.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | 5 | class MyDrawerButton extends StatefulHookConsumerWidget { 6 | const MyDrawerButton({ 7 | super.key, 8 | required this.title, 9 | required this.sectionKey, 10 | }); 11 | 12 | final String title; 13 | final GlobalKey sectionKey; 14 | 15 | @override 16 | ConsumerState createState() => _MyDrawerButtonState(); 17 | } 18 | 19 | class _MyDrawerButtonState extends ConsumerState { 20 | late ColorTween _colorTween; 21 | 22 | @override 23 | void didChangeDependencies() { 24 | _colorTween = ColorTween( 25 | begin: Theme.of(context).colorScheme.inverseSurface, 26 | end: Theme.of(context).colorScheme.onSecondary, 27 | ); 28 | super.didChangeDependencies(); 29 | } 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | final isHovered = useState(false); 34 | final controller = useAnimationController( 35 | duration: const Duration(milliseconds: 200), 36 | ); 37 | final colorAnimation = useAnimation(_colorTween.animate(controller)); 38 | 39 | return DefaultTextStyle( 40 | style: Theme.of(context).textTheme.headlineMedium!, 41 | child: MouseRegion( 42 | cursor: SystemMouseCursors.click, 43 | onEnter: (_) { 44 | if (!isHovered.value) { 45 | isHovered.value = true; 46 | controller.forward(); 47 | } 48 | }, 49 | onExit: (_) { 50 | if (isHovered.value) { 51 | isHovered.value = false; 52 | controller.reverse(); 53 | } 54 | }, 55 | child: GestureDetector( 56 | onTap: () => _onTap(context), 57 | child: Text( 58 | widget.title, 59 | style: TextStyle(color: colorAnimation), 60 | ), 61 | ), 62 | ), 63 | ); 64 | } 65 | 66 | void _onTap(BuildContext context) { 67 | final sectionKeyCurrentContext = widget.sectionKey.currentContext; 68 | if (sectionKeyCurrentContext != null) { 69 | Scrollable.ensureVisible( 70 | sectionKeyCurrentContext, 71 | duration: const Duration(milliseconds: 500), 72 | curve: Curves.decelerate, 73 | ); 74 | } 75 | Navigator.of(context).pop(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/widgets/locale_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:portfolio/src/common/data/language_repository.dart'; 6 | import 'package:portfolio/src/common/widgets/icon.dart'; 7 | import 'package:portfolio/src/constants/sizes.dart'; 8 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 9 | import 'package:portfolio/src/common/domain/language.dart'; 10 | import 'package:portfolio/src/localization/locale_controller.dart'; 11 | 12 | class LocaleButton extends ConsumerWidget { 13 | const LocaleButton({super.key}); 14 | 15 | @override 16 | Widget build(BuildContext context, WidgetRef ref) { 17 | final languages = ref.watch(languageRepositoryProvider).getLanguages(); 18 | 19 | return DropdownButton( 20 | padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12), 21 | value: context.locale, 22 | dropdownColor: Theme.of(context).colorScheme.primary, 23 | focusNode: FocusNode(canRequestFocus: false), 24 | focusColor: Colors.transparent, 25 | underline: const SizedBox.shrink(), 26 | items: languages.mapIndexed((index, language) { 27 | return DropdownMenuItem( 28 | value: Locale(language.code ?? ""), 29 | child: Row( 30 | children: [ 31 | MyIcon( 32 | icon: language.icon, 33 | placeholder: const Icon(Icons.translate), 34 | ), 35 | gapW8, 36 | Text(_getLanguageName(language)), 37 | ], 38 | ), 39 | ); 40 | }).toList(), 41 | onChanged: (locale) async { 42 | await _onLocaleChanged(context, ref, locale: locale); 43 | }, 44 | ); 45 | } 46 | 47 | Future _onLocaleChanged( 48 | BuildContext context, 49 | WidgetRef ref, { 50 | required Locale? locale, 51 | }) async { 52 | if (locale != null) { 53 | await context.setLocale(locale); 54 | await ref.read(localeControllerProvider).requireValue.setLocale(locale); 55 | } 56 | } 57 | 58 | String _getLanguageName(Language language) { 59 | final languageName = language.name; 60 | final languageNativeName = language.nativeName; 61 | if (languageNativeName != null) return languageNativeName; 62 | if (languageName != null) return languageName; 63 | return tr(LocaleKeys.unknownLanguageError); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/widgets/safe_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | 4 | class MySafeArea extends ConsumerWidget { 5 | const MySafeArea({super.key, required this.child}); 6 | 7 | final Widget child; 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return SafeArea( 12 | left: false, 13 | right: false, 14 | bottom: false, 15 | child: child, 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/features/general/presentation/widgets/sliver_app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/general/presentation/widgets/app_bar.dart'; 4 | 5 | class MySliverAppBar extends ConsumerWidget { 6 | const MySliverAppBar({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context, WidgetRef ref) { 10 | return SliverPersistentHeader( 11 | delegate: _AppBarDelegate(), 12 | floating: true, 13 | ); 14 | } 15 | } 16 | 17 | class _AppBarDelegate extends SliverPersistentHeaderDelegate { 18 | @override 19 | Widget build( 20 | BuildContext context, 21 | double shrinkOffset, 22 | bool overlapsContent, 23 | ) { 24 | return const MyAppBar(); 25 | } 26 | 27 | @override 28 | double get minExtent => kToolbarHeight; 29 | 30 | @override 31 | double get maxExtent => kToolbarHeight; 32 | 33 | @override 34 | bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { 35 | return false; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/features/general/provider/brightness_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:portfolio/src/common/provider/shared_preferences_provider.dart'; 2 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 3 | import 'dart:ui'; 4 | 5 | part 'brightness_controller.g.dart'; 6 | 7 | @riverpod 8 | class BrightnessController extends _$BrightnessController { 9 | static const _brightnessKey = "brightness"; 10 | 11 | @override 12 | FutureOr build() async => _getBrightness(); 13 | 14 | Future updateBrightness() async { 15 | state = const AsyncValue.loading(); 16 | state = await AsyncValue.guard(() async { 17 | final brightness = await _getBrightness(); 18 | final Brightness newBrightness; 19 | if (brightness.name == Brightness.dark.name) { 20 | newBrightness = Brightness.light; 21 | } else { 22 | newBrightness = Brightness.dark; 23 | } 24 | await _setBrightness(newBrightness); 25 | return newBrightness; 26 | }); 27 | } 28 | 29 | Future _getBrightness() async { 30 | final sharedPreferences = await ref.watch(sharedPreferencesProvider.future); 31 | final brightnessValue = sharedPreferences.getString(_brightnessKey); 32 | if (brightnessValue == Brightness.dark.name) { 33 | return Brightness.dark; 34 | } else if (brightnessValue == Brightness.light.name) { 35 | return Brightness.light; 36 | } else { 37 | // first build 38 | final platformDispatcher = PlatformDispatcher.instance; 39 | final platformBrightness = platformDispatcher.platformBrightness; 40 | await _setBrightness(platformBrightness); 41 | return platformBrightness; 42 | } 43 | } 44 | 45 | Future _setBrightness(Brightness brightness) async { 46 | ref.watch(sharedPreferencesProvider).whenData((sharedPreferences) async { 47 | await sharedPreferences.setString(_brightnessKey, brightness.name); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/features/general/provider/dark_mode_controller.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:portfolio/src/features/general/provider/brightness_controller.dart'; 4 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 | 6 | part 'dark_mode_controller.g.dart'; 7 | 8 | @riverpod 9 | class DarkMode extends _$DarkMode { 10 | @override 11 | FutureOr build() async { 12 | final brightness = await ref.watch(brightnessControllerProvider.future); 13 | return brightness == Brightness.dark; 14 | } 15 | 16 | Future updateTheme() async { 17 | await ref.watch(brightnessControllerProvider.notifier).updateBrightness(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/features/general/provider/scroll_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | 4 | final scrollControllerProvider = Provider((ref) { 5 | return ScrollController(); 6 | }); 7 | -------------------------------------------------------------------------------- /lib/src/features/general/provider/section_key_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 4 | 5 | part 'section_key_provider.g.dart'; 6 | 7 | @riverpod 8 | GlobalKey homeSectionKey(Ref ref) { 9 | return GlobalKey(); 10 | } 11 | 12 | @riverpod 13 | GlobalKey aboutSectionKey(Ref ref) { 14 | return GlobalKey(); 15 | } 16 | 17 | @riverpod 18 | GlobalKey experienceSectionKey(Ref ref) { 19 | return GlobalKey(); 20 | } 21 | 22 | @riverpod 23 | GlobalKey projectSectionKey(Ref ref) { 24 | return GlobalKey(); 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/data/personal_info_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 2 | import 'package:portfolio/src/features/personal_info/domain/contact.dart'; 3 | import 'package:portfolio/src/features/personal_info/domain/resume.dart'; 4 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 5 | import 'package:portfolio/src/localization/json_list_translation.dart'; 6 | import 'package:portfolio/src/localization/locale_controller.dart'; 7 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 8 | 9 | part 'personal_info_repository.g.dart'; 10 | 11 | @riverpod 12 | PersonalInfoRepository personalInfoRepository(Ref ref) { 13 | return PersonalInfoRepository(ref); 14 | } 15 | 16 | class PersonalInfoRepository { 17 | PersonalInfoRepository(this._ref); 18 | 19 | final Ref _ref; 20 | 21 | List getResumes() { 22 | final locale = _ref.watch(localeControllerProvider).requireValue.locale; 23 | final jsonResumes = trList(locale, LocaleKeys.resumes); 24 | final resumes = jsonResumes.map((jsonResume) { 25 | return Resume.fromJson(jsonResume); 26 | }).toList(); 27 | return resumes; 28 | } 29 | 30 | List getContacts() { 31 | final locale = _ref.watch(localeControllerProvider).requireValue.locale; 32 | final jsonContacts = trList(locale, LocaleKeys.contacts); 33 | final contacts = jsonContacts.map((jsonContact) { 34 | return Contact.fromJson(jsonContact); 35 | }).toList(); 36 | return contacts; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/domain/contact.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:portfolio/src/common/domain/icon.dart'; 3 | 4 | part 'contact.freezed.dart'; 5 | part 'contact.g.dart'; 6 | 7 | @freezed 8 | class Contact with _$Contact { 9 | const factory Contact({ 10 | String? tooltip, 11 | String? url, 12 | IconModel? icon, 13 | }) = _Contact; 14 | 15 | factory Contact.fromJson(Map json) => 16 | _$ContactFromJson(json); 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/domain/resume.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'resume.freezed.dart'; 4 | part 'resume.g.dart'; 5 | 6 | @freezed 7 | class Resume with _$Resume { 8 | const factory Resume({ 9 | String? languageCode, 10 | String? language, 11 | String? url, 12 | }) = _Resume; 13 | 14 | factory Resume.fromJson(Map json) => _$ResumeFromJson(json); 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/personal_info_desktop.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/constants/sizes.dart'; 5 | import 'package:portfolio/src/features/personal_info/data/personal_info_repository.dart'; 6 | import 'package:portfolio/src/features/personal_info/domain/resume.dart'; 7 | import 'package:portfolio/src/features/personal_info/presentation/widgets/contact_bar.dart'; 8 | import 'package:portfolio/src/features/personal_info/presentation/widgets/resume_button.dart'; 9 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 10 | 11 | class PersonalInfoDesktop extends ConsumerWidget { 12 | const PersonalInfoDesktop({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | final resumes = ref.watch(personalInfoRepositoryProvider).getResumes(); 17 | final contacts = ref.watch(personalInfoRepositoryProvider).getContacts(); 18 | 19 | return Column( 20 | crossAxisAlignment: CrossAxisAlignment.start, 21 | children: [ 22 | Text( 23 | tr(LocaleKeys.name), 24 | style: Theme.of(context).textTheme.displayLarge, 25 | ), 26 | gapH4, 27 | Text( 28 | tr(LocaleKeys.description), 29 | style: Theme.of(context).textTheme.titleLarge, 30 | ), 31 | gapH8, 32 | Text( 33 | tr(LocaleKeys.subDescription), 34 | style: Theme.of(context).textTheme.bodyLarge, 35 | ), 36 | _buildResumeButton(ref, resumes: resumes.toList()), 37 | const Spacer(), 38 | gapH8, 39 | ContactBar(contacts: contacts.toList()), 40 | ], 41 | ); 42 | } 43 | 44 | Widget _buildResumeButton(WidgetRef ref, {required List resumes}) { 45 | if (resumes.isEmpty) return const SizedBox.shrink(); 46 | return Column( 47 | children: [ 48 | gapH40, 49 | Padding( 50 | padding: const EdgeInsets.symmetric(vertical: 24), 51 | child: ResumeButton(resumes: resumes), 52 | ), 53 | ], 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/personal_info_mobile.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/constants/sizes.dart'; 5 | import 'package:portfolio/src/features/personal_info/data/personal_info_repository.dart'; 6 | import 'package:portfolio/src/features/personal_info/domain/resume.dart'; 7 | import 'package:portfolio/src/features/personal_info/presentation/widgets/contact_bar.dart'; 8 | import 'package:portfolio/src/features/personal_info/presentation/widgets/resume_button.dart'; 9 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 10 | 11 | class PersonalInfoMobile extends ConsumerWidget { 12 | const PersonalInfoMobile({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | final resumes = ref.watch(personalInfoRepositoryProvider).getResumes(); 17 | final contacts = ref.watch(personalInfoRepositoryProvider).getContacts(); 18 | 19 | return Column( 20 | crossAxisAlignment: CrossAxisAlignment.start, 21 | children: [ 22 | Text( 23 | tr(LocaleKeys.name), 24 | style: Theme.of(context).textTheme.displayMedium, 25 | ), 26 | gapH4, 27 | Text( 28 | tr(LocaleKeys.description), 29 | style: Theme.of(context).textTheme.titleLarge?.copyWith(fontSize: 20), 30 | ), 31 | gapH8, 32 | Text( 33 | tr(LocaleKeys.subDescription), 34 | style: Theme.of(context).textTheme.bodyLarge, 35 | ), 36 | _buildResumeButton(ref, resumes: resumes.toList()), 37 | gapH8, 38 | ContactBar(contacts: contacts.toList()), 39 | ], 40 | ); 41 | } 42 | 43 | Widget _buildResumeButton(WidgetRef ref, {required List resumes}) { 44 | if (resumes.isEmpty) return const SizedBox.shrink(); 45 | return Padding( 46 | padding: const EdgeInsets.symmetric(vertical: 28), 47 | child: ResumeButton(resumes: resumes), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/personal_info_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/personal_info/presentation/personal_info_desktop.dart'; 4 | import 'package:portfolio/src/features/personal_info/presentation/personal_info_mobile.dart'; 5 | import 'package:portfolio/src/features/personal_info/presentation/personal_info_tablet.dart'; 6 | import 'package:portfolio/src/common/widgets/responsive.dart'; 7 | 8 | class PersonalInfoSection extends ConsumerWidget { 9 | const PersonalInfoSection({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context, WidgetRef ref) { 13 | return const Responsive( 14 | mobile: PersonalInfoMobile(), 15 | tablet: PersonalInfoTablet(), 16 | desktop: PersonalInfoDesktop(), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/personal_info_tablet.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/constants/sizes.dart'; 5 | import 'package:portfolio/src/features/personal_info/data/personal_info_repository.dart'; 6 | import 'package:portfolio/src/features/personal_info/domain/resume.dart'; 7 | import 'package:portfolio/src/features/personal_info/presentation/widgets/contact_bar.dart'; 8 | import 'package:portfolio/src/features/personal_info/presentation/widgets/resume_button.dart'; 9 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 10 | 11 | class PersonalInfoTablet extends ConsumerWidget { 12 | const PersonalInfoTablet({super.key}); 13 | 14 | @override 15 | Widget build(BuildContext context, WidgetRef ref) { 16 | final resumes = ref.watch(personalInfoRepositoryProvider).getResumes(); 17 | final contacts = ref.watch(personalInfoRepositoryProvider).getContacts(); 18 | 19 | return Column( 20 | crossAxisAlignment: CrossAxisAlignment.start, 21 | children: [ 22 | Text( 23 | tr(LocaleKeys.name), 24 | style: Theme.of(context).textTheme.displayLarge, 25 | ), 26 | gapH4, 27 | Text( 28 | tr(LocaleKeys.description), 29 | style: Theme.of(context).textTheme.titleLarge, 30 | ), 31 | gapH8, 32 | Text( 33 | tr(LocaleKeys.subDescription), 34 | style: Theme.of(context).textTheme.bodyLarge, 35 | ), 36 | _buildResumeButton(ref, resumes: resumes.toList()), 37 | gapH8, 38 | ContactBar(contacts: contacts.toList()), 39 | ], 40 | ); 41 | } 42 | 43 | Widget _buildResumeButton(WidgetRef ref, {required List resumes}) { 44 | if (resumes.isEmpty) return const SizedBox.shrink(); 45 | return Padding( 46 | padding: const EdgeInsets.symmetric(vertical: 36), 47 | child: ResumeButton(resumes: resumes), 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/widgets/contact_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/personal_info/presentation/widgets/contact_icon_button.dart'; 4 | import 'package:portfolio/src/features/personal_info/domain/contact.dart'; 5 | 6 | class ContactBar extends ConsumerWidget { 7 | const ContactBar({super.key, required this.contacts}); 8 | 9 | final List contacts; 10 | 11 | @override 12 | Widget build(BuildContext context, WidgetRef ref) { 13 | return Wrap( 14 | children: contacts.map((contact) { 15 | return ContactIconButton(contact: contact); 16 | }).toList(), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/widgets/contact_icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/common/widgets/icon.dart'; 4 | import 'package:portfolio/src/features/personal_info/domain/contact.dart'; 5 | import 'package:portfolio/src/utils/launch_url_helper.dart'; 6 | import 'package:portfolio/src/utils/scaffold_messenger_helper.dart'; 7 | 8 | class ContactIconButton extends ConsumerWidget { 9 | const ContactIconButton({super.key, required this.contact}); 10 | 11 | final Contact contact; 12 | 13 | @override 14 | Widget build(BuildContext context, WidgetRef ref) { 15 | final contactUrl = contact.url; 16 | final icon = _buildIcon(contact: contact); 17 | if (contactUrl == null || icon == null) { 18 | return const SizedBox.shrink(); 19 | } 20 | return IconButton( 21 | tooltip: contact.tooltip, 22 | icon: icon, 23 | onPressed: () async { 24 | try { 25 | await LaunchUrlHelper.launchURL(contactUrl); 26 | } catch (e) { 27 | if (context.mounted) { 28 | ScaffoldMessengerHelper.showLaunchUrlError( 29 | context, 30 | url: contactUrl, 31 | ); 32 | } 33 | } 34 | }, 35 | ); 36 | } 37 | 38 | Widget? _buildIcon({required Contact contact}) { 39 | final contactTooltip = contact.tooltip; 40 | return MyIcon( 41 | icon: contact.icon, 42 | placeholder: contactTooltip == null 43 | ? const SizedBox.shrink() 44 | : Row( 45 | mainAxisSize: MainAxisSize.min, 46 | children: [ 47 | const Icon(Icons.link), 48 | const SizedBox(width: 4), 49 | Text(contactTooltip), 50 | ], 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/widgets/resume_language_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:portfolio/src/common/widgets/selection_area.dart'; 6 | import 'package:portfolio/src/features/personal_info/domain/resume.dart'; 7 | import 'package:portfolio/src/features/personal_info/presentation/widgets/resume_language_dialog_tile.dart'; 8 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 9 | 10 | class ResumeLanguageDialog extends ConsumerWidget { 11 | const ResumeLanguageDialog({super.key, required this.resumes}); 12 | 13 | final List resumes; 14 | 15 | @override 16 | Widget build(BuildContext context, WidgetRef ref) { 17 | return SimpleDialog( 18 | title: MySelectionArea( 19 | child: Center( 20 | child: Text(tr(LocaleKeys.downloadResume)), 21 | ), 22 | ), 23 | titlePadding: const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 8.0), 24 | contentPadding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 40.0), 25 | children: [ 26 | const Divider(height: 0), 27 | ...resumes.mapIndexed((index, resume) { 28 | return Column( 29 | children: [ 30 | ResumeLanguageDialogTile(resume: resume), 31 | if (index != resumes.length) const Divider(height: 0) 32 | ], 33 | ); 34 | }), 35 | ], 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/features/personal_info/presentation/widgets/resume_language_dialog_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 4 | import 'package:portfolio/src/common/data/language_repository.dart'; 5 | import 'package:portfolio/src/common/widgets/icon.dart'; 6 | import 'package:portfolio/src/constants/sizes.dart'; 7 | import 'package:portfolio/src/features/personal_info/domain/resume.dart'; 8 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 9 | import 'package:portfolio/src/utils/launch_url_helper.dart'; 10 | import 'package:portfolio/src/utils/scaffold_messenger_helper.dart'; 11 | 12 | class ResumeLanguageDialogTile extends ConsumerWidget { 13 | const ResumeLanguageDialogTile({super.key, required this.resume}); 14 | final Resume resume; 15 | 16 | @override 17 | Widget build(BuildContext context, WidgetRef ref) { 18 | return InkWell( 19 | onTap: () { 20 | final resumeUrl = resume.url; 21 | if (resumeUrl == null) return; 22 | _onPressed(context, resumeUrl: resumeUrl); 23 | }, 24 | child: Row( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | children: [ 27 | Padding( 28 | padding: const EdgeInsets.symmetric(vertical: 16), 29 | child: _buildResumeLanguageTileContent( 30 | context, 31 | ref, 32 | resume: resume, 33 | ), 34 | ), 35 | ], 36 | ), 37 | ); 38 | } 39 | } 40 | 41 | Widget _buildResumeLanguageTileContent( 42 | BuildContext context, 43 | WidgetRef ref, { 44 | required Resume resume, 45 | }) { 46 | final languages = ref.watch(languageRepositoryProvider).getLanguages(); 47 | final resumeLanguageCode = resume.languageCode; 48 | if (resumeLanguageCode == null) { 49 | return Text( 50 | tr(LocaleKeys.unknownLanguageError), 51 | style: Theme.of(context).textTheme.titleMedium, 52 | ); 53 | } 54 | final language = languages.firstWhere((language) { 55 | return language.code == resumeLanguageCode; 56 | }); 57 | return Row( 58 | children: [ 59 | MyIcon( 60 | icon: language.icon, 61 | placeholder: const Icon(Icons.translate), 62 | ), 63 | gapW8, 64 | Text( 65 | language.name ?? tr(LocaleKeys.unknownLanguageError), 66 | style: Theme.of(context).textTheme.titleMedium, 67 | ) 68 | ], 69 | ); 70 | } 71 | 72 | void _onPressed(BuildContext context, {required String resumeUrl}) async { 73 | try { 74 | await LaunchUrlHelper.launchURL(resumeUrl); 75 | } catch (e) { 76 | if (context.mounted) { 77 | ScaffoldMessengerHelper.showLaunchUrlError(context, url: resumeUrl); 78 | } 79 | } 80 | if (context.mounted) { 81 | Navigator.of(context).pop(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/src/features/project/data/project_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 2 | import 'package:portfolio/src/features/project/domain/project.dart'; 3 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 4 | import 'package:portfolio/src/localization/json_list_translation.dart'; 5 | import 'package:portfolio/src/localization/locale_controller.dart'; 6 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 7 | 8 | part 'project_repository.g.dart'; 9 | 10 | @riverpod 11 | ProjectRepository projectRepository(Ref ref) { 12 | return ProjectRepository(ref); 13 | } 14 | 15 | class ProjectRepository { 16 | ProjectRepository(this._ref); 17 | 18 | final Ref _ref; 19 | 20 | List getProjects() { 21 | final locale = _ref.watch(localeControllerProvider).requireValue.locale; 22 | final jsonProjects = trList(locale, LocaleKeys.projects); 23 | final projects = jsonProjects.map((jsonProject) { 24 | return Project.fromJson(jsonProject); 25 | }).toList(); 26 | return projects; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/features/project/domain/project.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:portfolio/src/common/domain/icon.dart'; 3 | import 'package:portfolio/src/common/domain/link.dart'; 4 | import 'package:portfolio/src/common/domain/technology.dart'; 5 | 6 | part 'project.freezed.dart'; 7 | part 'project.g.dart'; 8 | 9 | @freezed 10 | class Project with _$Project { 11 | const factory Project({ 12 | String? name, 13 | String? description, 14 | String? url, 15 | IconModel? icon, 16 | String? screenshotPath, 17 | List? technologies, 18 | List? links, 19 | }) = _Project; 20 | 21 | factory Project.fromJson(Map json) => 22 | _$ProjectFromJson(json); 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/features/project/presentation/project_desktop.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | import 'package:easy_localization/easy_localization.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | import 'package:portfolio/src/constants/sizes.dart'; 6 | import 'package:portfolio/src/features/project/data/project_repository.dart'; 7 | import 'package:portfolio/src/features/project/presentation/widgets/project_card.dart'; 8 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 9 | 10 | class ProjectDesktop extends ConsumerWidget { 11 | const ProjectDesktop({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context, WidgetRef ref) { 15 | final projects = ref.watch(projectRepositoryProvider).getProjects(); 16 | 17 | return Column( 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | children: [ 20 | Padding( 21 | padding: const EdgeInsets.only(left: 12, bottom: 20), 22 | child: Text( 23 | tr(LocaleKeys.projectsSectionTitle), 24 | style: Theme.of(context).textTheme.titleLarge, 25 | ), 26 | ), 27 | ...projects.mapIndexed((index, project) { 28 | return Column( 29 | children: [ 30 | ProjectCard(project: project), 31 | if (index != projects.length - 1) gapH24, 32 | ], 33 | ); 34 | }), 35 | ], 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/features/project/presentation/project_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/features/project/presentation/project_desktop.dart'; 4 | import 'package:portfolio/src/common/widgets/responsive.dart'; 5 | 6 | class ProjectSection extends ConsumerWidget { 7 | const ProjectSection({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return const Responsive( 12 | desktop: ProjectDesktop(), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/features/project/presentation/widgets/project_description.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | import 'package:portfolio/src/common/widgets/technology_wrap_chips.dart'; 4 | import 'package:portfolio/src/common/widgets/wrap_links.dart'; 5 | import 'package:portfolio/src/constants/sizes.dart'; 6 | import 'package:portfolio/src/features/project/domain/project.dart'; 7 | 8 | class ProjectDescription extends ConsumerWidget { 9 | const ProjectDescription({super.key, required this.project}); 10 | 11 | final Project project; 12 | 13 | @override 14 | Widget build(BuildContext context, WidgetRef ref) { 15 | final theme = Theme.of(context); 16 | final projectName = project.name; 17 | 18 | return Column( 19 | crossAxisAlignment: CrossAxisAlignment.start, 20 | children: [ 21 | Row( 22 | children: [ 23 | Text( 24 | projectName != null ? "$projectName " : "", 25 | style: theme.textTheme.titleMedium 26 | ?.copyWith(fontWeight: FontWeight.bold), 27 | ), 28 | const Icon(Icons.open_in_new), 29 | ], 30 | ), 31 | gapH8, 32 | Row( 33 | children: [ 34 | Expanded( 35 | child: Text( 36 | project.description ?? "", 37 | style: theme.textTheme.bodyMedium, 38 | ), 39 | ), 40 | ], 41 | ), 42 | gapH12, 43 | Column( 44 | crossAxisAlignment: CrossAxisAlignment.start, 45 | children: [ 46 | _buildLinks(context), 47 | if (project.links?.isNotEmpty == true) gapH12 else gapH4, 48 | _buildChips(), 49 | ], 50 | ), 51 | ], 52 | ); 53 | } 54 | 55 | Widget _buildChips() { 56 | final projectTechnologies = project.technologies; 57 | if (projectTechnologies == null) return const SizedBox.shrink(); 58 | return TechnologyWrapChips(technologies: projectTechnologies); 59 | } 60 | 61 | Widget _buildLinks(BuildContext context) { 62 | final projectLinks = project.links; 63 | if (projectLinks == null) return const SizedBox.shrink(); 64 | return WrapLinks(links: projectLinks); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/src/features/project/presentation/widgets/project_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 3 | 4 | class ProjectIcon extends ConsumerWidget { 5 | const ProjectIcon({super.key, required this.iconData}); 6 | 7 | final IconData iconData; 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return Icon( 12 | color: Colors.white, 13 | size: 32, 14 | iconData, 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/localization/app_localizations.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | import 'package:path/path.dart' as path; 6 | 7 | class AppLocalizations { 8 | static const translationsPath = "assets/translations"; 9 | 10 | static Future> supportedLocales() async { 11 | final manifestContent = await rootBundle.loadString('AssetManifest.json'); 12 | final Map manifestMap = json.decode(manifestContent); 13 | List assets = manifestMap.keys.where((String key) { 14 | return key.startsWith(translationsPath); 15 | }).toList(); 16 | List fileNames = assets.map((String asset) { 17 | final filenameLanguageCode = path.basenameWithoutExtension(asset); 18 | return Locale(filenameLanguageCode); 19 | }).toList(); 20 | return fileNames; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/localization/json_list_translation.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:portfolio/src/localization/generated/locale_json.g.dart'; 4 | 5 | List> trList(Locale locale, String key) { 6 | final mapLocales = CodegenLoader.mapLocales[locale.languageCode]; 7 | final mapValue = mapLocales?[key]; 8 | return mapValue; 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/localization/locale_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | // ignore: implementation_imports 3 | import 'package:easy_localization/src/easy_localization_controller.dart'; 4 | import 'package:portfolio/src/localization/app_localizations.dart'; 5 | import 'package:riverpod_annotation/riverpod_annotation.dart'; 6 | 7 | final localeControllerProvider = 8 | FutureProvider((ref) async { 9 | final supportedLocales = await AppLocalizations.supportedLocales(); 10 | return EasyLocalizationController( 11 | supportedLocales: await AppLocalizations.supportedLocales(), 12 | path: AppLocalizations.translationsPath, 13 | fallbackLocale: supportedLocales.first, 14 | useFallbackTranslations: true, 15 | saveLocale: true, 16 | assetLoader: const RootBundleAssetLoader(), 17 | useOnlyLangCode: false, 18 | onLoadError: (_) {}, 19 | ); 20 | }); 21 | -------------------------------------------------------------------------------- /lib/src/utils/launch_url_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 3 | import 'package:url_launcher/url_launcher.dart'; 4 | 5 | class LaunchUrlHelper { 6 | LaunchUrlHelper._(); 7 | 8 | static Future launchURL(String url) async { 9 | try { 10 | await launchUrl(Uri.parse(url)); 11 | } catch (e) { 12 | throw '${tr(LocaleKeys.openUrlError)} $url'; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/utils/localized_date_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:intl/intl.dart'; 4 | 5 | extension LocalizedDate on int { 6 | String localizedYear(Locale locale) { 7 | return DateFormat.y(locale.languageCode).format(DateTime(this)); 8 | } 9 | 10 | String localizedMonth(Locale locale) { 11 | return DateFormat.MMM(locale.languageCode).format(DateTime(0, this)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/src/utils/scaffold_messenger_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_localization/easy_localization.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:portfolio/src/localization/generated/locale_keys.g.dart'; 4 | 5 | class ScaffoldMessengerHelper { 6 | ScaffoldMessengerHelper._(); 7 | 8 | static void showLaunchUrlError(BuildContext context, {String? url}) { 9 | if (context.mounted) { 10 | ScaffoldMessenger.of(context).showSnackBar( 11 | SnackBar( 12 | content: Text("${tr(LocaleKeys.openUrlError)} $url"), 13 | ), 14 | ); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/utils/string_extension.dart: -------------------------------------------------------------------------------- 1 | extension StringExtension on String { 2 | String capitalize() { 3 | if (trim().isEmpty) return ""; 4 | return split(" ").map((element) { 5 | return "${element[0].toUpperCase()}${element.substring(1).toLowerCase()}"; 6 | }).join(" "); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | 12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 13 | # which isn't available in 3.10. 14 | function(list_prepend LIST_NAME PREFIX) 15 | set(NEW_LIST "") 16 | foreach(element ${${LIST_NAME}}) 17 | list(APPEND NEW_LIST "${PREFIX}${element}") 18 | endforeach(element) 19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 20 | endfunction() 21 | 22 | # === Flutter Library === 23 | # System-level dependencies. 24 | find_package(PkgConfig REQUIRED) 25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 28 | 29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 30 | 31 | # Published to parent scope for install step. 32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 36 | 37 | list(APPEND FLUTTER_LIBRARY_HEADERS 38 | "fl_basic_message_channel.h" 39 | "fl_binary_codec.h" 40 | "fl_binary_messenger.h" 41 | "fl_dart_project.h" 42 | "fl_engine.h" 43 | "fl_json_message_codec.h" 44 | "fl_json_method_codec.h" 45 | "fl_message_codec.h" 46 | "fl_method_call.h" 47 | "fl_method_channel.h" 48 | "fl_method_codec.h" 49 | "fl_method_response.h" 50 | "fl_plugin_registrar.h" 51 | "fl_plugin_registry.h" 52 | "fl_standard_message_codec.h" 53 | "fl_standard_method_codec.h" 54 | "fl_string_codec.h" 55 | "fl_value.h" 56 | "fl_view.h" 57 | "flutter_linux.h" 58 | ) 59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 60 | add_library(flutter INTERFACE) 61 | target_include_directories(flutter INTERFACE 62 | "${EPHEMERAL_DIR}" 63 | ) 64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 65 | target_link_libraries(flutter INTERFACE 66 | PkgConfig::GTK 67 | PkgConfig::GLIB 68 | PkgConfig::GIO 69 | ) 70 | add_dependencies(flutter flutter_assemble) 71 | 72 | # === Flutter tool backend === 73 | # _phony_ is a non-existent file to force this command to run every time, 74 | # since currently there's no way to get a full input/output list from the 75 | # flutter tool. 76 | add_custom_command( 77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 79 | COMMAND ${CMAKE_COMMAND} -E env 80 | ${FLUTTER_TOOL_ENVIRONMENT} 81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} 83 | VERBATIM 84 | ) 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ) 89 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | 11 | void fl_register_plugins(FlPluginRegistry* registry) { 12 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 13 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 14 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 15 | } 16 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | url_launcher_linux 7 | ) 8 | 9 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 10 | ) 11 | 12 | set(PLUGIN_BUNDLED_LIBRARIES) 13 | 14 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 19 | endforeach(plugin) 20 | 21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 24 | endforeach(ffi_plugin) 25 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /linux/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} 10 | "main.cc" 11 | "my_application.cc" 12 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 13 | ) 14 | 15 | # Apply the standard set of build settings. This can be removed for applications 16 | # that need different build settings. 17 | apply_standard_settings(${BINARY_NAME}) 18 | 19 | # Add preprocessor definitions for the application ID. 20 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 21 | 22 | # Add dependency libraries. Add any application-specific dependencies here. 23 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 24 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 25 | 26 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 27 | -------------------------------------------------------------------------------- /linux/runner/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /linux/runner/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import path_provider_foundation 9 | import shared_preferences_foundation 10 | import url_launcher_macos 11 | 12 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 13 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 14 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 15 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 16 | } 17 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_macos_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FlutterMacOS (1.0.0) 3 | - path_provider_foundation (0.0.1): 4 | - Flutter 5 | - FlutterMacOS 6 | - shared_preferences_foundation (0.0.1): 7 | - Flutter 8 | - FlutterMacOS 9 | - url_launcher_macos (0.0.1): 10 | - FlutterMacOS 11 | 12 | DEPENDENCIES: 13 | - FlutterMacOS (from `Flutter/ephemeral`) 14 | - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) 15 | - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) 16 | - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) 17 | 18 | EXTERNAL SOURCES: 19 | FlutterMacOS: 20 | :path: Flutter/ephemeral 21 | path_provider_foundation: 22 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin 23 | shared_preferences_foundation: 24 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin 25 | url_launcher_macos: 26 | :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos 27 | 28 | SPEC CHECKSUMS: 29 | FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 30 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 31 | shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 32 | url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 33 | 34 | PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 35 | 36 | COCOAPODS: 1.15.2 37 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | }, 6 | "images": [ 7 | { 8 | "size": "16x16", 9 | "idiom": "mac", 10 | "filename": "app_icon_16.png", 11 | "scale": "1x" 12 | }, 13 | { 14 | "size": "16x16", 15 | "idiom": "mac", 16 | "filename": "app_icon_32.png", 17 | "scale": "2x" 18 | }, 19 | { 20 | "size": "32x32", 21 | "idiom": "mac", 22 | "filename": "app_icon_32.png", 23 | "scale": "1x" 24 | }, 25 | { 26 | "size": "32x32", 27 | "idiom": "mac", 28 | "filename": "app_icon_64.png", 29 | "scale": "2x" 30 | }, 31 | { 32 | "size": "128x128", 33 | "idiom": "mac", 34 | "filename": "app_icon_128.png", 35 | "scale": "1x" 36 | }, 37 | { 38 | "size": "128x128", 39 | "idiom": "mac", 40 | "filename": "app_icon_256.png", 41 | "scale": "2x" 42 | }, 43 | { 44 | "size": "256x256", 45 | "idiom": "mac", 46 | "filename": "app_icon_256.png", 47 | "scale": "1x" 48 | }, 49 | { 50 | "size": "256x256", 51 | "idiom": "mac", 52 | "filename": "app_icon_512.png", 53 | "scale": "2x" 54 | }, 55 | { 56 | "size": "512x512", 57 | "idiom": "mac", 58 | "filename": "app_icon_512.png", 59 | "scale": "1x" 60 | }, 61 | { 62 | "size": "512x512", 63 | "idiom": "mac", 64 | "filename": "app_icon_1024.png", 65 | "scale": "2x" 66 | } 67 | ] 68 | } -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = portfolio 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = dev.aladdine.portfolio 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 dev.aladdine. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import FlutterMacOS 2 | import Cocoa 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: portfolio 2 | description: Portfolio developed in flutter. 3 | publish_to: 'none' 4 | 5 | version: 1.0.0+1 6 | 7 | environment: 8 | sdk: '>=3.0.0 <4.0.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | flutter_web_plugins: 14 | sdk: flutter 15 | flex_color_scheme: ^8.2.0 16 | google_fonts: ^6.2.1 17 | riverpod_annotation: ^2.6.1 18 | hooks_riverpod: ^2.6.1 19 | flutter_hooks: ^0.20.5 20 | collection: ^1.18.0 21 | url_launcher: ^6.2.6 22 | intl: ^0.20.2 23 | easy_localization: ^3.0.7+1 24 | easy_logger: ^0.0.2 25 | freezed_annotation: ^2.4.4 26 | json_annotation: ^4.9.0 27 | shared_preferences: ^2.5.2 28 | flutter_svg: ^2.0.17 29 | animated_toggle_switch: ^0.8.4 30 | path: ^1.9.1 31 | 32 | dev_dependencies: 33 | flutter_test: 34 | sdk: flutter 35 | 36 | flutter_lints: ^5.0.0 37 | custom_lint: ^0.7.3 38 | riverpod_lint: ^2.6.4 39 | riverpod_generator: ^2.6.4 40 | build_runner: ^2.4.15 41 | freezed: ^2.5.8 42 | json_serializable: ^6.9.4 43 | flutter_native_splash: ^2.4.0 44 | flutter_launcher_icons: ^0.14.3 45 | 46 | flutter: 47 | 48 | uses-material-design: true 49 | 50 | assets: 51 | - assets/fonts/ 52 | - assets/icons/flags/ 53 | - assets/icons/other/ 54 | - assets/icons/software-development/ 55 | - assets/images/ 56 | - assets/translations/ 57 | 58 | fonts: 59 | - family: BoxIcons 60 | fonts: 61 | - asset: assets/fonts/BoxIcons.ttf 62 | - family: FontAwesome 63 | fonts: 64 | - asset: assets/fonts/FontAwesome.ttf 65 | - family: OctIcons 66 | fonts: 67 | - asset: assets/fonts/OctIcons.ttf 68 | 69 | flutter_native_splash: 70 | color: "#60a3d9" 71 | image: "assets/images/spinner-light.apng" 72 | color_dark: "#122035" 73 | image_dark: "assets/images/spinner-dark.apng" 74 | 75 | flutter_launcher_icons: 76 | android: "ic_launcher" 77 | ios: true 78 | remove_alpha_ios: true 79 | image_path: "assets/images/logo.png" 80 | min_sdk_android: 21 # android min sdk min:16, default 21 81 | web: 82 | generate: true 83 | image_path: "assets/images/logo.png" 84 | windows: 85 | generate: true 86 | image_path: "assets/images/logo.png" 87 | icon_size: 256 # min:48, max:256, default: 48 88 | macos: 89 | generate: true 90 | image_path: "assets/images/logo.png" -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:portfolio/src/app.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio", 3 | "short_name": "portfolio", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /web/splash/img/dark-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/dark-1x.png -------------------------------------------------------------------------------- /web/splash/img/dark-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/dark-2x.png -------------------------------------------------------------------------------- /web/splash/img/dark-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/dark-3x.png -------------------------------------------------------------------------------- /web/splash/img/dark-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/dark-4x.png -------------------------------------------------------------------------------- /web/splash/img/light-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/light-1x.png -------------------------------------------------------------------------------- /web/splash/img/light-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/light-2x.png -------------------------------------------------------------------------------- /web/splash/img/light-3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/light-3x.png -------------------------------------------------------------------------------- /web/splash/img/light-4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/web/splash/img/light-4x.png -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | 11 | void RegisterPlugins(flutter::PluginRegistry* registry) { 12 | UrlLauncherWindowsRegisterWithRegistrar( 13 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 14 | } 15 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | url_launcher_windows 7 | ) 8 | 9 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 10 | ) 11 | 12 | set(PLUGIN_BUNDLED_LIBRARIES) 13 | 14 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 19 | endforeach(plugin) 20 | 21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 24 | endforeach(ffi_plugin) 25 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"portfolio", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AladdineDev/portfolio/6cc5a771e35292c14ee1e8c63cedf4ea42db2296/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length <= 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | --------------------------------------------------------------------------------