├── .github
├── FUNDING.yml
└── workflows
│ ├── configs
│ └── configuration.json
│ └── main.yaml
├── .gitignore
├── .metadata
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── ic_launcher-playstore.png
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutter_sharez
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ └── splash.png
│ │ │ ├── drawable-mdpi
│ │ │ └── splash.png
│ │ │ ├── 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-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_rounded.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── values-night-v31
│ │ │ └── styles.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ ├── values-v31
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── anim
│ ├── files.json
│ ├── scanning.json
│ └── starting_rocket.json
└── images
│ └── logo
│ ├── es.json
│ ├── ic_launcher.png
│ ├── ic_launcher_adaptive_back.png
│ ├── ic_launcher_adaptive_fore.png
│ ├── icon.svg
│ ├── logo_white_bg.png
│ ├── logo_white_fg.png
│ └── or.json
├── build.yaml
├── coverage
└── lcov.info
├── devtools_options.yaml
├── flutter_native_splash.yaml
├── icons_launcher.yaml
├── 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.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-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
└── RunnerTests
│ └── RunnerTests.swift
├── lib
├── app
│ ├── app.dart
│ └── view
│ │ └── app.dart
├── bootstrap.dart
├── const
│ ├── app_urls.dart
│ └── resource.dart
├── core
│ ├── local_storage
│ │ ├── app_storage.dart
│ │ └── app_storage_pod.dart
│ ├── router
│ │ ├── auto_route_observer.dart
│ │ ├── router.dart
│ │ ├── router.gr.dart
│ │ └── router_pod.dart
│ └── theme
│ │ ├── app_theme.dart
│ │ └── theme_controller.dart
├── data
│ ├── model
│ │ ├── check_server_model.dart
│ │ ├── file_model.dart
│ │ ├── file_paths_model.dart
│ │ ├── file_select_model.dart
│ │ ├── range_header.dart
│ │ ├── receiver_model.dart
│ │ ├── receiver_model.mapper.dart
│ │ ├── sender_model.dart
│ │ ├── server_info.dart
│ │ └── update_model.dart
│ └── service
│ │ ├── receiver
│ │ ├── receiver_service.dart
│ │ └── receiver_service_pod.dart
│ │ └── sender
│ │ ├── sender_service.dart
│ │ └── sender_service_pod.dart
├── features
│ ├── confirm_connection
│ │ └── view
│ │ │ └── confirm_connection_page.dart
│ ├── counter
│ │ ├── controller
│ │ │ ├── counter_state_pod.dart
│ │ │ └── notifier
│ │ │ │ └── counter_notifier.dart
│ │ ├── counter.dart
│ │ └── view
│ │ │ └── counter_page.dart
│ ├── device_share
│ │ ├── controller
│ │ │ └── files_list_pods.dart
│ │ └── view
│ │ │ ├── device_share_page.dart
│ │ │ └── tabs
│ │ │ ├── device_info_tab_page.dart
│ │ │ └── sender_files_tab_page.dart
│ ├── downloads
│ │ └── view
│ │ │ └── downloads_page.dart
│ ├── file_download_btn
│ │ ├── controller
│ │ │ ├── file_download_pod.dart
│ │ │ └── notifier
│ │ │ │ └── file_download_notifier.dart
│ │ ├── state
│ │ │ ├── file_download_state.dart
│ │ │ └── file_download_state.mapper.dart
│ │ └── view
│ │ │ └── file_download_btn.dart
│ ├── file_selector
│ │ ├── controller
│ │ │ ├── notifier
│ │ │ │ └── selected_files_notifier.dart
│ │ │ └── selected_files_list_pod.dart
│ │ ├── state
│ │ │ └── select_file_state.dart
│ │ └── view
│ │ │ ├── file_list_view.dart
│ │ │ └── file_selector_page.dart
│ ├── help_dialog
│ │ └── view
│ │ │ └── help_dialog_page.dart
│ ├── home
│ │ └── view
│ │ │ └── home_page.dart
│ ├── manual_connect
│ │ └── view
│ │ │ └── manual_connect_page.dart
│ ├── qr_scan
│ │ └── qr_scan_page.dart
│ ├── receive
│ │ ├── controller
│ │ │ ├── connect_pod.dart
│ │ │ ├── notifier
│ │ │ │ └── connect_btn_notifier.dart
│ │ │ └── receive_pods.dart
│ │ ├── state
│ │ │ ├── connect_btn_state_pod.dart
│ │ │ └── receive_scan_start.dart
│ │ └── view
│ │ │ ├── receive_page.dart
│ │ │ ├── receive_state_page.dart
│ │ │ └── widget
│ │ │ └── connect_btn.dart
│ ├── send
│ │ ├── controller
│ │ │ ├── notifier
│ │ │ │ └── send_state_notifier.dart
│ │ │ └── send_notifier_pod.dart
│ │ ├── state
│ │ │ └── send_state.dart
│ │ └── view
│ │ │ ├── send_page.dart
│ │ │ ├── send_state_page.dart
│ │ │ ├── ui_state
│ │ │ ├── started_server_view.dart
│ │ │ └── starting_server_view.dart
│ │ │ └── widgets
│ │ │ ├── action_dialog_page.dart
│ │ │ ├── files_bottomsheet.dart
│ │ │ ├── send_actions.dart
│ │ │ ├── server_info_box.dart
│ │ │ └── share_on_web.dart
│ ├── settings
│ │ ├── controller
│ │ │ └── current_version_pod.dart
│ │ └── view
│ │ │ ├── settings_page.dart
│ │ │ └── widget
│ │ │ └── about_app_tile.dart
│ ├── splash
│ │ ├── controller
│ │ │ ├── box_encryption_key_pod.dart
│ │ │ └── future_initializer.dart
│ │ └── view
│ │ │ └── splash_view.dart
│ ├── theme_segmented_btn
│ │ ├── controller
│ │ │ └── selection_theme_pod.dart
│ │ └── view
│ │ │ └── theme_segmented_btn.dart
│ └── update_app_version
│ │ ├── controller
│ │ ├── check_update_available.dart
│ │ ├── check_update_version.dart
│ │ └── get_changelog_pod.dart
│ │ └── view
│ │ ├── changelog_page.dart
│ │ ├── update_app_version_icon.dart
│ │ └── widgets
│ │ └── animated_sync.dart
├── i18n
│ ├── en.i18n.json
│ ├── es.i18n.json
│ ├── or.i18n.json
│ ├── strings.g.dart
│ ├── strings_en.g.dart
│ ├── strings_es.g.dart
│ └── strings_or.g.dart
├── init.dart
├── main.dart
├── main_development.dart
├── main_production.dart
├── main_staging.dart
├── shared
│ ├── api_client
│ │ └── dio
│ │ │ ├── bad_certificate_fixer.dart
│ │ │ ├── default_api_error_handler.dart
│ │ │ ├── default_api_interceptor.dart
│ │ │ ├── default_time_response_interceptor.dart
│ │ │ ├── dio_client_provider.dart
│ │ │ └── form_data_interceptor.dart
│ ├── exception
│ │ └── base_exception.dart
│ ├── extension
│ │ └── response_success_error_handler.dart
│ ├── helper
│ │ ├── file_list_html_render.dart
│ │ ├── global_helper.dart
│ │ ├── network_helper.dart
│ │ ├── range_downloader.dart
│ │ └── version.dart
│ ├── pods
│ │ ├── internet_checker_pod.dart
│ │ └── locale_pod.dart
│ ├── riverpod_ext
│ │ ├── asynvalue_easy_when.dart
│ │ ├── cache_extensions.dart
│ │ ├── cancel_extensions.dart
│ │ ├── riverpod_extensions.dart
│ │ └── riverpod_observer.dart
│ └── widget
│ │ ├── app_locale_popup.dart
│ │ ├── app_logo.dart
│ │ ├── custom_app_bar.dart
│ │ ├── no_internet_widget.dart
│ │ ├── os_logo.dart
│ │ └── responsive_wrapper.dart
├── splasher.dart
├── translation_override_map.dart
└── translation_pod.dart
├── 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
├── riverpod_simple_architecture.md
├── screenshot
├── 1.png
├── 10.png
├── 11.png
├── 12.png
├── 13.png
├── 14.png
├── 15.png
├── 16.png
├── 17.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── 8.png
└── 9.png
├── test
├── app
│ └── view
│ │ └── app_test.dart
├── core
│ ├── storage
│ │ └── app_storage_test.dart
│ └── theme
│ │ └── theme_controller_pod_test.dart
├── features
│ ├── counter
│ │ ├── pod
│ │ │ └── counter_pod_test.dart
│ │ └── view
│ │ │ └── counter_page_test.dart
│ └── theme_segment_btn
│ │ └── view
│ │ └── theme_segment_btn_test.dart
├── helpers
│ ├── helpers.dart
│ └── pump_app.dart
├── init_test.dart
├── shared
│ ├── api_client
│ │ └── dio
│ │ │ └── dio_client_provider_test.dart
│ ├── exception
│ │ └── exception_test.dart
│ ├── pods
│ │ ├── internet_checker_pod_test.dart
│ │ └── locale_pod_test.dart
│ ├── riverpod_ext
│ │ ├── asynvalue_easywhen_test.dart
│ │ └── cache_extension_test.dart
│ └── widgets
│ │ ├── app_locale_popup_test.dart
│ │ └── no_interenet_widget_test.dart
└── 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
└── light-background.png
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: Shreemanarjun
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
15 |
--------------------------------------------------------------------------------
/.github/workflows/configs/configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "categories": [
3 | {
4 | "title": "## 🚀 Features",
5 | "labels": ["feat"]
6 | },
7 | {
8 | "title": "## 🐛 Fixes",
9 | "labels": ["fix"]
10 | },
11 | {
12 | "title": "## 🧪 Tests",
13 | "labels": ["test"]
14 | },
15 | {
16 | "title": "## 🧪 Tests and some 🪄 Magic",
17 | "labels": ["test", "magic"],
18 | "exclude_labels": ["no-magic"],
19 | "exhaustive": true,
20 | "empty_content": "- no matching PRs"
21 | },
22 | {
23 | "title": "## 📦 Uncategorized",
24 | "labels": []
25 | }
26 | ],
27 | "ignore_labels": [
28 | "ignore"
29 | ],
30 | "sort": {
31 | "order": "ASC",
32 | "on_property": "mergedAt"
33 | },
34 | "template": "${{CHANGELOG}}\n\n\nUncategorized
\n\n${{UNCATEGORIZED}}\n ",
35 | "pr_template": "- ${{TITLE}}\n - PR: #${{NUMBER}}",
36 | "empty_template": "- no changes",
37 | "label_extractor": [
38 | {
39 | "pattern": "(.) (.+)",
40 | "target": "$1",
41 | "flags": "gu"
42 | },
43 | {
44 | "pattern": "\\[Issue\\]",
45 | "on_property": "title",
46 | "method": "match"
47 | }
48 | ],
49 | "duplicate_filter": {
50 | "pattern": "\\[ABC-....\\]",
51 | "on_property": "title",
52 | "method": "match"
53 | },
54 | "transformers": [
55 | {
56 | "pattern": "[\\-\\*] (\\[(...|TEST|CI|SKIP)\\])( )?(.+?)\n(.+?[\\-\\*] )(.+)",
57 | "target": "- $4\n - $6"
58 | }
59 | ],
60 | "max_tags_to_fetch": 200,
61 | "max_pull_requests": 200,
62 | "max_back_track_time_days": 365,
63 | "exclude_merge_branches": [
64 | "Owner/qa"
65 | ],
66 | "tag_resolver": {
67 | "method": "semver",
68 | "filter": {
69 | "pattern": "api-(.+)",
70 | "flags": "gu"
71 | }
72 | },
73 | "base_branches": [
74 | "main"
75 | ]
76 | }
--------------------------------------------------------------------------------
/.github/workflows/main.yaml:
--------------------------------------------------------------------------------
1 | name: Flutter Workflow
2 |
3 | on:
4 | #push:
5 | pull_request:
6 | # Sequence of patterns matched against refs/heads
7 | branches:
8 | - main
9 | - master
10 | permissions: read-all
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: write
16 | steps:
17 | - name: Checkout code
18 | uses: actions/checkout@v3
19 | - uses: actions/setup-java@v3
20 | with:
21 | distribution: 'zulu' # See 'Supported distributions' for available options
22 | java-version: '11'
23 | - name: Install Flutter
24 | uses: subosito/flutter-action@v2
25 | with:
26 | channel: 'stable'
27 | cache: true
28 | # - name: Install dependencies
29 | # run: flutter pub get
30 | - run: flutter --version
31 |
32 |
33 | - name: Run unit tests
34 | run: flutter test --coverage
35 |
36 | # - name: Run integration tests
37 | # uses: reactivecircus/android-emulator-runner@v1
38 | # with:
39 | # api-level: 29
40 | # script: flutter drive --driver=test_driver/main_test.dart --target integration_test/app_test.dart
41 | - name: create Fat APK
42 | run: flutter build apk --release
43 |
44 | - name: create Split APK
45 | run: flutter build apk --split-per-abi
46 |
47 | - name: Upload Fat APK
48 | uses: actions/upload-artifact@v3
49 | with:
50 | name: release-fat-apk
51 | path: build/app/outputs/apk/release/app-release.apk
52 |
53 | - name: Upload Split APK
54 | uses: actions/upload-artifact@v3
55 | with:
56 | name: release-split-apk
57 | path: build/app/outputs/flutter-apk/*.apk
58 |
59 | - id: read-version
60 | uses: NiklasLehnfeld/flutter-version-number-action@main
61 | with:
62 | file-path: pubspec.yaml
63 | - name: Push to Releases
64 | uses: ncipollo/release-action@v1
65 | with:
66 | artifacts: "build/app/outputs/apk/release/*.apk, build/app/outputs/flutter-apk/*.apk"
67 | tag: v${{ steps.read-version.outputs.version-number }}
68 | token: ${{ secrets.TOKEN }}
69 | generateReleaseNotes: true
70 | - name: Checkout
71 | uses: actions/checkout@v2
72 | with:
73 | fetch-depth: 0
74 | - name: "Build Changelog"
75 | uses: mikepenz/release-changelog-builder-action@v3
76 | with:
77 | configuration: ".github/workflows/configs/configuration.json"
78 | ignorePreReleases: "false"
79 | commitMode: "true"
80 | env:
81 | GITHUB_TOKEN: ${{ secrets.TOKEN }}
82 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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: "ead455963c12b453cdb2358cad34969c76daf180"
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: ead455963c12b453cdb2358cad34969c76daf180
17 | base_revision: ead455963c12b453cdb2358cad34969c76daf180
18 | - platform: android
19 | create_revision: ead455963c12b453cdb2358cad34969c76daf180
20 | base_revision: ead455963c12b453cdb2358cad34969c76daf180
21 | - platform: ios
22 | create_revision: ead455963c12b453cdb2358cad34969c76daf180
23 | base_revision: ead455963c12b453cdb2358cad34969c76daf180
24 | - platform: linux
25 | create_revision: ead455963c12b453cdb2358cad34969c76daf180
26 | base_revision: ead455963c12b453cdb2358cad34969c76daf180
27 | - platform: macos
28 | create_revision: ead455963c12b453cdb2358cad34969c76daf180
29 | base_revision: ead455963c12b453cdb2358cad34969c76daf180
30 | - platform: web
31 | create_revision: ead455963c12b453cdb2358cad34969c76daf180
32 | base_revision: ead455963c12b453cdb2358cad34969c76daf180
33 |
34 | # User provided section
35 |
36 | # List of Local paths (relative to this file) that should be
37 | # ignored by the migrate tool.
38 | #
39 | # Files that are not part of the templates will be ignored by default.
40 | unmanaged_files:
41 | - 'lib/main.dart'
42 | - 'ios/Runner.xcodeproj/project.pbxproj'
43 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "dart-code.dart-code",
6 | "dart-code.flutter",
7 | "aaron-bond.better-comments",
8 | "alexisvt.flutter-snippets",
9 | "BendixMa.dart-data-class-generator",
10 | "flutterando.flutter-coverage",
11 | "jeroen-meijer.pubspec-assist",
12 | "Nash.awesome-flutter-snippets",
13 | "pflannery.vscode-versionlens",
14 | "PratheeshRussell.flutter-commands",
15 | "robert-brunhage.flutter-riverpod-snippets",
16 | "ricardo-emerson.create-flutter-widgets-and-classes",
17 | "ryanluker.vscode-coverage-gutters"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch development",
9 | "request": "launch",
10 | "type": "dart",
11 | "program": "lib/main_development.dart",
12 | "args": [
13 | "--flavor",
14 | "development",
15 | "--target",
16 | "lib/main_development.dart"
17 | ]
18 | },
19 | {
20 | "name": "Launch staging",
21 | "request": "launch",
22 | "type": "dart",
23 | "program": "lib/main_staging.dart",
24 | "args": ["--flavor", "staging", "--target", "lib/main_staging.dart"]
25 | },
26 | {
27 | "name": "Launch production",
28 | "request": "launch",
29 | "type": "dart",
30 | "program": "lib/main_production.dart",
31 | "args": ["--flavor", "production", "--target", "lib/main_production.dart"]
32 | },
33 | {
34 | "name": "Launch normal",
35 | "request": "launch",
36 | "type": "dart",
37 | "program": "lib/main.dart",
38 |
39 | }
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dart.flutterSdkPath": "/Users/shreemanarjunsahu/.puro/envs/stable/flutter",
3 | "dart.sdkPath": "/Users/shreemanarjunsahu/.puro/envs/stable/flutter/bin/cache/dart-sdk"
4 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 1.0.9+1
2 | - 🌐 Update app name
3 | - Update some theme on report issue dialog
4 |
5 | # 1.0.8+1
6 | - Upgraded dependencies
7 |
8 | # 1.0.7+1
9 | - Fix ios 17 build
10 |
11 | # 1.0.6+1
12 | - Upgrade responsive framework
13 | - Upgrade dependencies
14 |
15 | # 1.0.5+1
16 | - Upgrade responsive framework
17 | - Upgrade dependencies
18 |
19 | # 1.0.4+1
20 | - fixed translations
21 |
22 | # 1.0.3+1
23 | - fixed updates
24 |
25 | # 1.0.2+5
26 | - update docs and update to add codepush docs in to-do
27 |
28 | # 1.0.2+4
29 | - Update logic enhanced
30 |
31 | # 1.0.2+3
32 | - Auto update app version support
33 | - Update settings for changelog view
34 |
35 | # 1.0.2+2
36 | - Upda7te setting pages to add app info, bug report feature
37 | - Added Localization
38 |
39 | # 1.0.2+1
40 | - Added Localization Support: Now available in English, Spanish, and Odia, enhancing accessibility for a broader audience.
41 | - Added Workflow
42 |
43 | # 1.0.1+1
44 | - Resumable Downloads: Introduce the ability to resume interrupted or paused downloads, ensuring a seamless download experience even in case of network disruptions (hyper_thread_downloader)
45 | - fix receive list auto refresh
46 | - UI improvements
47 | - docs updated
48 |
49 |
50 | # 1.0.0+1
51 | - Initial release
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributing to flutter_sharez
3 |
4 | Thank you for considering contributing to flutter_sharez! We appreciate your interest in helping us improve our project. Please follow these guidelines to make the contribution process smooth and effective.
5 |
6 | ## Getting Started
7 |
8 | 1. Fork the repository to your GitHub account.
9 | 2. Clone the forked repository to your local machine:
10 |
11 | ```
12 | git clone https://github.com/Shreemanarjun/flutter_sharez
13 | ```
14 |
15 | 3. Create a new branch for your changes:
16 |
17 | ```
18 | git checkout -b feature-name
19 | ```
20 |
21 | 4. Make your changes and commit them with a descriptive commit message:
22 |
23 | ```
24 | git commit -m "Description of the changes"
25 | ```
26 |
27 | 5. Push your changes to your forked repository:
28 |
29 | ```
30 | git push origin feature-name
31 | ```
32 |
33 | 6. Open a pull request on the `main` branch of this repository. Provide a clear and descriptive title for your pull request, explaining your changes.
34 |
35 | ## Contribution Guidelines
36 |
37 | - Please make sure your code adheres to the existing coding standards and style in the project.
38 | - If your contribution changes existing functionality, make sure to update the documentation accordingly.
39 | - Test your changes thoroughly before opening a pull request.
40 | - Be respectful and considerate in your comments and discussions on issues and pull requests.
41 |
42 | ## Code of Conduct
43 |
44 | Please note that this project is released with a Contributor Code of Conduct. By participating in this project, you agree to abide by its terms. You can read the full code of conduct [here](CODE_OF_CONDUCT.md).
45 |
46 | ## Need Help?
47 |
48 | If you have any questions or need further assistance, feel free to open an issue or join our community discussions.
49 |
50 | Thank you for contributing to flutter_sharez! We appreciate your help in making this project better.
51 |
52 | Happy Coding!
53 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2023] [Shreeman Arjun Sahu]
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.
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 | # analyzer:
3 | # plugins:
4 | # - custom_lint
5 | linter:
6 | rules:
7 | public_member_api_docs: false
8 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | namespace "com.example.flutter_sharez"
30 | compileSdkVersion 34
31 | ndkVersion flutter.ndkVersion
32 |
33 | compileOptions {
34 | sourceCompatibility JavaVersion.VERSION_1_8
35 | targetCompatibility JavaVersion.VERSION_1_8
36 | }
37 |
38 | kotlinOptions {
39 | jvmTarget = '1.8'
40 | }
41 |
42 | sourceSets {
43 | main.java.srcDirs += 'src/main/kotlin'
44 | }
45 |
46 | defaultConfig {
47 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
48 | applicationId "com.example.flutter_sharez"
49 | // You can update the following values to match your application needs.
50 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
51 | minSdkVersion 24
52 | targetSdkVersion flutter.targetSdkVersion
53 | versionCode flutterVersionCode.toInteger()
54 | versionName flutterVersionName
55 | }
56 |
57 | buildTypes {
58 | release {
59 | // TODO: Add your own signing config for the release build.
60 | // Signing with the debug keys for now, so `flutter run --release` works.
61 | signingConfig signingConfigs.debug
62 | }
63 | }
64 | }
65 |
66 | flutter {
67 | source '../..'
68 | }
69 |
70 |
71 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
16 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/android/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/flutter_sharez/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.flutter_sharez
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/drawable-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/drawable-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/drawable-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/drawable-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/drawable-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_rounded.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.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:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.8.20'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:8.5.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | tasks.register("clean", Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | android.defaults.buildfeatures.buildconfig=true
5 | android.nonTransitiveRClass=false
6 | android.nonFinalResIds=false
7 |
--------------------------------------------------------------------------------
/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.7-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/images/logo/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/assets/images/logo/ic_launcher.png
--------------------------------------------------------------------------------
/assets/images/logo/ic_launcher_adaptive_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/assets/images/logo/ic_launcher_adaptive_back.png
--------------------------------------------------------------------------------
/assets/images/logo/ic_launcher_adaptive_fore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/assets/images/logo/ic_launcher_adaptive_fore.png
--------------------------------------------------------------------------------
/assets/images/logo/logo_white_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/assets/images/logo/logo_white_bg.png
--------------------------------------------------------------------------------
/assets/images/logo/logo_white_fg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/assets/images/logo/logo_white_fg.png
--------------------------------------------------------------------------------
/build.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | $default:
3 | builders:
4 | auto_route_generator:auto_route_generator: # this for @RoutePage
5 | options:
6 | enable_cached_builds: true
7 | generate_for:
8 | - lib/features/**_page.dart
9 | auto_route_generator:auto_router_generator: # this for @AutoRouterConfig
10 | options:
11 | enable_cached_builds: true
12 | generate_for:
13 | - lib/core/router/router.dart
14 |
--------------------------------------------------------------------------------
/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | description: This file stores settings for Dart & Flutter DevTools.
2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3 | extensions:
4 |
--------------------------------------------------------------------------------
/icons_launcher.yaml:
--------------------------------------------------------------------------------
1 | icons_launcher:
2 | image_path: "assets/images/logo/ic_launcher_adaptive_fore.png"
3 | platforms:
4 | android:
5 | enable: true
6 | # adaptive_background_color: '#ffffff'
7 | adaptive_background_image: "assets/images/logo/ic_launcher_adaptive_back.png"
8 | adaptive_foreground_image: "assets/images/logo/ic_launcher_adaptive_fore.png"
9 | adaptive_round_image: "assets/images/logo/logo_white_fg.png"
10 | ios:
11 | enable: true
12 | image_path: "assets/images/logo/logo_white_fg.png"
13 | web:
14 | enable: true
15 | image_path: "assets/images/logo/ic_launcher.png"
16 | favicon_path: "assets/images/logo/logo_white_fg.png"
17 | macos:
18 | enable: true
19 | image_path: "assets/images/logo/ic_launcher.png"
20 | # windows:
21 | # enable: true
22 | # image_path: "assets/images/logo/ic_launcher.png"
23 | # linux:
24 | # enable: true
25 | # image_path: "assets/images/logo/ic_launcher.png"
--------------------------------------------------------------------------------
/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/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.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/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/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/a82c03912fdd7c55ef66d284b149c8cfa336c525/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@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/LaunchScreen.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 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/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 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Flutter Sharez
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | flutter_sharez
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/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/app/app.dart:
--------------------------------------------------------------------------------
1 | export 'view/app.dart';
2 |
--------------------------------------------------------------------------------
/lib/bootstrap.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: deprecated_member_use
2 |
3 | import 'dart:async';
4 | import 'dart:developer';
5 | import 'package:flutter/foundation.dart';
6 | import 'package:flutter/widgets.dart';
7 | import 'package:flutter_riverpod/flutter_riverpod.dart';
8 | import 'package:platform_info/platform_info.dart';
9 | import 'package:talker_flutter/talker_flutter.dart';
10 |
11 | // coverage:ignore-file
12 |
13 | /// This `talker` global variable used for logging and accessible
14 | /// to other classed or function
15 | // coverage:ignore-file
16 |
17 | final talker = TalkerFlutter.init(
18 | settings: TalkerSettings(
19 | // maxHistoryItems: null,
20 | useConsoleLogs: !kReleaseMode,
21 | enabled: !kReleaseMode,
22 | ),
23 | logger: TalkerLogger(
24 | // output: debugPrint,
25 | settings: TalkerLoggerSettings(
26 | enableColors: !Platform.I.iOS,
27 | ),
28 | ),
29 | );
30 |
31 | ///This bootstrap function builds widget asynchronusly
32 | ///where builder function used for building your start widget.
33 | ///You can override riverpod providers ,also setup observers
34 | ///or you can put a provider container in parent
35 | Future bootstrap(
36 | FutureOr Function() builder, {
37 | required ProviderContainer parent,
38 | }) async {
39 | FlutterError.onError = (details) {
40 | log(details.exceptionAsString(), stackTrace: details.stack);
41 | };
42 |
43 | runApp(
44 | UncontrolledProviderScope(
45 | container: parent,
46 | child: await builder(),
47 | ),
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/lib/const/app_urls.dart:
--------------------------------------------------------------------------------
1 | /// This class helping putting all
2 | /// the urls needed in apps
3 | class AppUrls {
4 | AppUrls._();
5 | }
6 |
--------------------------------------------------------------------------------
/lib/const/resource.dart:
--------------------------------------------------------------------------------
1 | /// Generate by [resource_generator](https://github.com/CaiJingLong/flutter_resource_generator) library.
2 | /// PLEASE DO NOT EDIT MANUALLY.
3 | // ignore_for_file: constant_identifier_names
4 | class R {
5 | const R._();
6 |
7 | /// 
8 | static const String ASSETS_ANIM_NOINTERNET_RIV = 'assets/anim/nointernet.riv';
9 | }
10 |
--------------------------------------------------------------------------------
/lib/core/local_storage/app_storage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:hive_ce_flutter/hive_flutter.dart';
3 |
4 | /// This class used for storing data in nosql hive boxes
5 | /// ,reading data and deleting data .
6 | class AppStorage {
7 | Box? appBox;
8 |
9 | AppStorage(this.appBox);
10 |
11 | Future init({isTest = false}) async {
12 | appBox = appBox ??
13 | await Hive.openBox(
14 | 'appBox',
15 | bytes: isTest ? Uint8List(0) : null,
16 | );
17 | }
18 |
19 | /// for getting value as String for a
20 | /// given key from the box
21 | String? get({required String key}) {
22 | return appBox?.get(key) as String?;
23 | }
24 |
25 | /// for storing value on defined key
26 | /// on the box
27 | Future put({
28 | required String key,
29 | required String value,
30 | }) async {
31 | await appBox?.put(key, value);
32 | }
33 |
34 | /// for clearing all data in box
35 | Future clearAllData() async {
36 | await appBox?.clear();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/core/local_storage/app_storage_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:hive_ce_flutter/hive_flutter.dart';
3 | import 'package:flutter_sharez/core/local_storage/app_storage.dart';
4 |
5 | /// This provider used for App Storage Service class which
6 | /// depends on appBoxProvider for getting intial Hive Box
7 | final appStorageProvider = Provider.autoDispose(
8 | (ref) => AppStorage(ref.watch(appBoxProvider)),
9 | name: 'appStorageProvider',
10 | );
11 |
12 | /// This provider used for Storing Hive Box which you can override on
13 | /// bootstrap function on start of the app
14 | final appBoxProvider = Provider.autoDispose(
15 | (ref) => throw UnimplementedError("appBoxProvider is not overriden"),
16 | name: 'appBoxProvider',
17 | );
18 |
--------------------------------------------------------------------------------
/lib/core/router/auto_route_observer.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: strict_raw_type
2 |
3 | import 'package:auto_route/auto_route.dart';
4 |
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter_sharez/bootstrap.dart';
7 |
8 | /// This class observers all events happening in routing/navigation
9 | class RouterObserver extends AutoRouterObserver {
10 | @override
11 | void didPush(Route route, Route? previousRoute) {
12 | talker.debug(
13 | 'New route pushed: ${route.settings.name} Previous route is: ${previousRoute?.settings.name}');
14 | }
15 |
16 | @override
17 | void didPop(Route route, Route? previousRoute) {
18 | talker.debug(
19 | 'Previous route poped: ${route.settings.name} Active route is: ${previousRoute?.settings.name}');
20 | }
21 |
22 | @override
23 | void didReplace({Route? newRoute, Route? oldRoute}) {
24 | talker.debug(
25 | 'Route ${newRoute?.settings.name} is replaced with ${oldRoute?.settings.name}');
26 | }
27 |
28 | @override
29 | void didRemove(Route route, Route? previousRoute) {
30 | talker.debug(
31 | 'Route ${route.settings.name} is removed. Previous route is: ${previousRoute?.settings.name}');
32 | }
33 |
34 | // only override to observer tab routes
35 | @override
36 | void didInitTabRoute(TabPageRoute route, TabPageRoute? previousRoute) {
37 | talker.debug(
38 | 'Tab route visited: ${route.name} Previous route is: ${previousRoute?.name}');
39 | }
40 |
41 | @override
42 | void didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) {
43 | talker.debug(
44 | 'Tab route re-visited: ${route.name} Previous route is: ${previousRoute.name}');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/core/router/router_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/core/router/router.dart';
4 |
5 | /// This global variable used for global working on ui elements where
6 | /// may be context is not present
7 | final navigatorKey = GlobalKey();
8 |
9 | /// This provider used for storing router
10 | /// and can be acessed by reading it using ProviderRef/WidgetRef
11 | final autorouterProvider = Provider.autoDispose(
12 | (ref) => AppRouter(),
13 | name: 'autorouterProvider',
14 | );
15 |
--------------------------------------------------------------------------------
/lib/core/theme/theme_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/core/local_storage/app_storage_pod.dart';
4 |
5 | ///This provider stores the ThemeModeController
6 | final themecontrollerProvider =
7 | NotifierProvider.autoDispose(
8 | ThemeModeController.new,
9 | name: 'themecontrollerProvider',
10 | );
11 |
12 | ///This controller class used change theme and
13 | ///get the intial theme from storage if its available
14 | class ThemeModeController extends AutoDisposeNotifier {
15 | final _themeKey = "theme";
16 |
17 | @override
18 | ThemeMode build() {
19 | final theme = ref.watch(appStorageProvider).get(key: _themeKey);
20 | if (theme != null) {
21 | if (theme == ThemeMode.light.name) {
22 | return ThemeMode.light;
23 | } else if (theme == ThemeMode.dark.name) {
24 | return ThemeMode.dark;
25 | }
26 | return ThemeMode.system;
27 | }
28 | return ThemeMode.system;
29 | }
30 |
31 | Future changeTheme(ThemeMode theme) async {
32 | state = theme;
33 | await ref.read(appStorageProvider).put(key: _themeKey, value: theme.name);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/data/model/check_server_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class CheckServerModel {
4 | final String message;
5 | final String? token;
6 | CheckServerModel({
7 | required this.message,
8 | this.token,
9 | });
10 |
11 | CheckServerModel copyWith({
12 | String? message,
13 | String? token,
14 | }) {
15 | return CheckServerModel(
16 | message: message ?? this.message,
17 | token: token ?? this.token,
18 | );
19 | }
20 |
21 | Map toMap() {
22 | return {
23 | 'message': message,
24 | 'token': token,
25 | };
26 | }
27 |
28 | factory CheckServerModel.fromMap(Map map) {
29 | return CheckServerModel(
30 | message: map['message'] ?? '',
31 | token: map['token'],
32 | );
33 | }
34 |
35 | String toJson() => json.encode(toMap());
36 |
37 | factory CheckServerModel.fromJson(String source) =>
38 | CheckServerModel.fromMap(json.decode(source));
39 |
40 | @override
41 | String toString() => 'CheckServerModel(message: $message, token: $token)';
42 |
43 | @override
44 | bool operator ==(Object other) {
45 | if (identical(this, other)) return true;
46 |
47 | return other is CheckServerModel &&
48 | other.message == message &&
49 | other.token == token;
50 | }
51 |
52 | @override
53 | int get hashCode => message.hashCode ^ token.hashCode;
54 | }
55 |
--------------------------------------------------------------------------------
/lib/data/model/file_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class FileModel {
4 | final String name;
5 | final int size;
6 |
7 | final String fileExt;
8 | FileModel({
9 | required this.name,
10 | required this.size,
11 | required this.fileExt,
12 | });
13 |
14 | FileModel copyWith({
15 | String? name,
16 | int? size,
17 | String? fileExt,
18 | }) {
19 | return FileModel(
20 | name: name ?? this.name,
21 | size: size ?? this.size,
22 | fileExt: fileExt ?? this.fileExt,
23 | );
24 | }
25 |
26 | Map toMap() {
27 | return {
28 | 'name': name,
29 | 'size': size,
30 | 'fileExt': fileExt,
31 | };
32 | }
33 |
34 | factory FileModel.fromMap(Map map) {
35 | return FileModel(
36 | name: map['name'] ?? '',
37 | size: map['size']?.toInt() ?? 0,
38 | fileExt: map['fileExt'] ?? '',
39 | );
40 | }
41 |
42 | String toJson() => json.encode(toMap());
43 |
44 | factory FileModel.fromJson(String source) =>
45 | FileModel.fromMap(json.decode(source));
46 |
47 | @override
48 | String toString() => 'FileModel(name: $name, size: $size, fileExt: $fileExt)';
49 |
50 | @override
51 | bool operator ==(Object other) {
52 | if (identical(this, other)) return true;
53 |
54 | return other is FileModel &&
55 | other.name == name &&
56 | other.size == size &&
57 | other.fileExt == fileExt;
58 | }
59 |
60 | @override
61 | int get hashCode => name.hashCode ^ size.hashCode ^ fileExt.hashCode;
62 | }
63 |
--------------------------------------------------------------------------------
/lib/data/model/file_select_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:file_picker/file_picker.dart';
2 |
3 | class FileSelectModel {
4 | final bool isSelected;
5 | final PlatformFile file;
6 | FileSelectModel({
7 | required this.isSelected,
8 | required this.file,
9 | });
10 |
11 | FileSelectModel copyWith({
12 | bool? isSelected,
13 | PlatformFile? file,
14 | }) {
15 | return FileSelectModel(
16 | isSelected: isSelected ?? this.isSelected,
17 | file: file ?? this.file,
18 | );
19 | }
20 |
21 | @override
22 | bool operator ==(Object other) {
23 | if (identical(this, other)) return true;
24 |
25 | return other is FileSelectModel &&
26 | other.isSelected == isSelected &&
27 | other.file == file;
28 | }
29 |
30 | @override
31 | int get hashCode => isSelected.hashCode ^ file.hashCode;
32 |
33 | @override
34 | String toString() => 'FileSelectModel(isSelected: $isSelected, file: $file)';
35 | }
36 |
--------------------------------------------------------------------------------
/lib/data/model/range_header.dart:
--------------------------------------------------------------------------------
1 | class RangeHeader {
2 | final int start;
3 | final int? end;
4 |
5 | RangeHeader(this.start, this.end);
6 |
7 | @override
8 | String toString() {
9 | if (end != null) {
10 | return 'bytes $start-$end';
11 | } else {
12 | return 'bytes $start-';
13 | }
14 | }
15 | }
16 |
17 | RangeHeader parseRangeHeader(String? rangeHeaderValue, int fileSize) {
18 | if (rangeHeaderValue == null) {
19 | return RangeHeader(0, null);
20 | }
21 |
22 | final matches = RegExp(r'bytes=(\d*)-(\d*)').firstMatch(rangeHeaderValue);
23 | if (matches != null) {
24 | final start = matches.group(1);
25 | final end = matches.group(2);
26 | if (start!.isNotEmpty) {
27 | final startByte = int.parse(start);
28 | if (end!.isNotEmpty) {
29 | final endByte = int.parse(end);
30 | if (endByte >= startByte && endByte < fileSize) {
31 | return RangeHeader(startByte, endByte);
32 | }
33 | } else {
34 | if (startByte < fileSize) {
35 | return RangeHeader(startByte, null);
36 | }
37 | }
38 | } else if (end!.isNotEmpty) {
39 | final endByte = int.parse(end);
40 | if (fileSize - endByte >= 0) {
41 | return RangeHeader(fileSize - endByte, fileSize - 1);
42 | }
43 | }
44 | }
45 | return RangeHeader(0, null);
46 | }
47 |
--------------------------------------------------------------------------------
/lib/data/model/receiver_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:dart_mappable/dart_mappable.dart';
2 | part 'receiver_model.mapper.dart';
3 |
4 | @MappableClass()
5 | class ReceiverModel with ReceiverModelMappable {
6 | final String ip;
7 | final int port;
8 | final String host;
9 | final String os;
10 | final String version;
11 | ReceiverModel({
12 | required this.ip,
13 | required this.port,
14 | required this.host,
15 | required this.os,
16 | required this.version,
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/lib/data/model/sender_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class SenderModel {
4 | final String? ip;
5 | final int? port;
6 | final int? filesCount;
7 | final String? host;
8 | final String? os;
9 | final String? version;
10 | SenderModel({
11 | this.ip,
12 | this.port,
13 | this.filesCount,
14 | this.host,
15 | this.os,
16 | this.version,
17 | });
18 |
19 | SenderModel copyWith({
20 | String? ip,
21 | int? port,
22 | int? filesCount,
23 | String? host,
24 | String? os,
25 | String? version,
26 | }) {
27 | return SenderModel(
28 | ip: ip ?? this.ip,
29 | port: port ?? this.port,
30 | filesCount: filesCount ?? this.filesCount,
31 | host: host ?? this.host,
32 | os: os ?? this.os,
33 | version: version ?? this.version,
34 | );
35 | }
36 |
37 | Map toMap() {
38 | return {
39 | 'ip': ip,
40 | 'port': port,
41 | 'filesCount': filesCount,
42 | 'host': host,
43 | 'os': os,
44 | 'version': version,
45 | };
46 | }
47 |
48 | factory SenderModel.fromMap(Map map) {
49 | return SenderModel(
50 | ip: map['ip'],
51 | port: map['port']?.toInt(),
52 | filesCount: map['filesCount']?.toInt(),
53 | host: map['host'],
54 | os: map['os'],
55 | version: map['version'],
56 | );
57 | }
58 |
59 | String toJson() => json.encode(toMap());
60 |
61 | factory SenderModel.fromJson(String source) =>
62 | SenderModel.fromMap(json.decode(source));
63 |
64 | @override
65 | String toString() {
66 | return 'SenderModel(ip: $ip, port: $port, filesCount: $filesCount, host: $host, os: $os, version: $version)';
67 | }
68 |
69 | @override
70 | bool operator ==(Object other) {
71 | if (identical(this, other)) return true;
72 |
73 | return other is SenderModel &&
74 | other.ip == ip &&
75 | other.port == port &&
76 | other.filesCount == filesCount &&
77 | other.host == host &&
78 | other.os == os &&
79 | other.version == version;
80 | }
81 |
82 | @override
83 | int get hashCode {
84 | return ip.hashCode ^
85 | port.hashCode ^
86 | filesCount.hashCode ^
87 | host.hashCode ^
88 | os.hashCode ^
89 | version.hashCode;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/data/model/server_info.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | class ServerInfo {
4 | final String ip;
5 | final int port;
6 | final String host;
7 | final String os;
8 | final String version;
9 | ServerInfo({
10 | required this.ip,
11 | required this.port,
12 | required this.host,
13 | required this.os,
14 | required this.version,
15 | });
16 |
17 | ServerInfo copyWith({
18 | String? ip,
19 | int? port,
20 | String? host,
21 | String? os,
22 | String? version,
23 | }) {
24 | return ServerInfo(
25 | ip: ip ?? this.ip,
26 | port: port ?? this.port,
27 | host: host ?? this.host,
28 | os: os ?? this.os,
29 | version: version ?? this.version,
30 | );
31 | }
32 |
33 | Map toMap() {
34 | return {
35 | 'ip': ip,
36 | 'port': port,
37 | 'host': host,
38 | 'os': os,
39 | 'version': version,
40 | };
41 | }
42 |
43 | factory ServerInfo.fromMap(Map map) {
44 | return ServerInfo(
45 | ip: map['ip'] ?? '',
46 | port: map['port']?.toInt() ?? 0,
47 | host: map['host'] ?? '',
48 | os: map['os'] ?? '',
49 | version: map['version'] ?? '',
50 | );
51 | }
52 |
53 | String toJson() => json.encode(toMap());
54 |
55 | factory ServerInfo.fromJson(String source) =>
56 | ServerInfo.fromMap(json.decode(source));
57 |
58 | @override
59 | String toString() {
60 | return 'ServerInfo(ip: $ip, port: $port, host: $host, os: $os, version: $version)';
61 | }
62 |
63 | @override
64 | bool operator ==(Object other) {
65 | if (identical(this, other)) return true;
66 |
67 | return other is ServerInfo &&
68 | other.ip == ip &&
69 | other.port == port &&
70 | other.host == host &&
71 | other.os == os &&
72 | other.version == version;
73 | }
74 |
75 | @override
76 | int get hashCode {
77 | return ip.hashCode ^
78 | port.hashCode ^
79 | host.hashCode ^
80 | os.hashCode ^
81 | version.hashCode;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/lib/data/service/receiver/receiver_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:dio/dio.dart';
4 | import 'package:flutter_sharez/data/model/check_server_model.dart';
5 | import 'package:flutter_sharez/data/model/file_paths_model.dart';
6 | import 'package:flutter_sharez/data/model/receiver_model.dart';
7 | import 'package:flutter_sharez/shared/exception/base_exception.dart';
8 | import 'package:multiple_result/multiple_result.dart';
9 |
10 | class ReceiverService {
11 | final Dio dio;
12 |
13 | ReceiverService({required this.dio});
14 |
15 | Future> connectToDevice({
16 | required String ip,
17 | required String port,
18 | required currentIP,
19 | required CancelToken cancelToken,
20 | }) async {
21 | final response = await dio.post(
22 | '/checkServer',
23 | data: ReceiverModel(
24 | ip: currentIP,
25 | port: 8080,
26 | host: Platform.localHostname,
27 | os: Platform.operatingSystem,
28 | version: Platform.operatingSystemVersion,
29 | ).toMap(),
30 | cancelToken: cancelToken,
31 | );
32 |
33 | if (response.statusCode == 200) {
34 | final checkServermodel = CheckServerModel.fromMap(response.data);
35 | if (checkServermodel.message.contains('Accepted')) {
36 | return const Success(true);
37 | } else {
38 | return const Success(false);
39 | }
40 | } else {
41 | try {
42 | final checkServermodel = CheckServerModel.fromMap(response.data);
43 | return Error(BaseException(message: checkServermodel.message));
44 | } catch (e) {
45 | return Error(BaseException(message: e.toString()));
46 | }
47 | }
48 | }
49 |
50 | Future> getFilePaths({
51 | required CancelToken cancelToken,
52 | }) async {
53 | final response = await dio.get(
54 | '/filepath',
55 | cancelToken: cancelToken,
56 | );
57 |
58 | if (response.statusCode == 200) {
59 | return Success(
60 | FilePathsModel.fromMap(response.data),
61 | );
62 | } else {
63 | return Error(
64 | BaseException(message: "Failed to get files"),
65 | );
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/data/service/receiver/receiver_service_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/data/model/sender_model.dart';
3 | import 'package:flutter_sharez/data/service/receiver/receiver_service.dart';
4 | import 'package:flutter_sharez/shared/api_client/dio/dio_client_provider.dart';
5 |
6 | final receiverServicePod =
7 | Provider.autoDispose.family(
8 | (ref, sendermodel) {
9 | return ReceiverService(
10 | dio: ref.watch(
11 | dioProvider('http://${sendermodel.ip}:${sendermodel.port}'),
12 | ),
13 | );
14 | },
15 | name: 'receiverServicePod',
16 | );
17 |
--------------------------------------------------------------------------------
/lib/data/service/sender/sender_service_pod.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:alfred/alfred.dart';
4 | import 'package:file_picker/file_picker.dart';
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 | import 'package:flutter_sharez/data/service/sender/sender_service.dart';
7 | import 'package:flutter_sharez/features/file_selector/controller/selected_files_list_pod.dart';
8 |
9 | final senderServicePod = Provider.autoDispose((ref) {
10 | return SenderService(
11 | app: ref.watch(alfredPod),
12 | port: ref.watch(defaultPortProvider),
13 | ref: ref,
14 | );
15 | }, name: 'senderServicePod');
16 |
17 | final alfredPod = Provider.autoDispose((ref) {
18 | FutureOr missingHandler(HttpRequest req, HttpResponse res) {
19 | res.statusCode = 404;
20 | return {'message': '${req.uri.toString()} not found'};
21 | }
22 |
23 | FutureOr onInternalError(HttpRequest req, HttpResponse res) {
24 | res.statusCode = 500;
25 | return {'message': 'Error in ${req..uri.toString()},'};
26 | }
27 |
28 | return Alfred(
29 | onNotFound: missingHandler,
30 | onInternalError: onInternalError,
31 | );
32 | }, name: 'alfredPod');
33 |
34 | final defaultPortProvider =
35 | StateProvider.autoDispose((ref) => 8080, name: 'defaultPortProvider');
36 |
37 | final paltformFilesPod = Provider.autoDispose>(
38 | (ref) {
39 | return ref.watch(
40 | selectedFilesPod.select(
41 | (value) => value.map((e) => e.file).toList(),
42 | ),
43 | );
44 | },
45 | name: 'paltformFilesPod',
46 | );
47 |
--------------------------------------------------------------------------------
/lib/features/counter/controller/counter_state_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/features/counter/counter.dart';
3 |
4 | /// This provider holds CounternNotifier
5 | final counterPod = NotifierProvider(
6 | CounterNotifier.new,
7 | name: 'counterPod',
8 | );
9 |
10 | ///This provider used to seup the intial value
11 | ///which can be overriden for test
12 | final intialCounterValuePod = Provider((ref) => 0);
13 |
--------------------------------------------------------------------------------
/lib/features/counter/controller/notifier/counter_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/features/counter/counter.dart';
3 |
4 | /// This notifier class used to build intial value
5 | /// from intial counter value which can be overriden.
6 |
7 | class CounterNotifier extends Notifier {
8 | @override
9 | int build() {
10 | return ref.read(intialCounterValuePod);
11 | }
12 |
13 | ///This function updates current state increase by 1
14 | void increment() => state = state + 1;
15 |
16 | ///This function updates current state decrease by 1
17 | void decrement() => state = state - 1;
18 | }
19 |
--------------------------------------------------------------------------------
/lib/features/counter/counter.dart:
--------------------------------------------------------------------------------
1 | export 'controller/counter_state_pod.dart';
2 | export 'controller/notifier/counter_notifier.dart';
3 | export 'view/counter_page.dart';
4 |
--------------------------------------------------------------------------------
/lib/features/device_share/controller/files_list_pods.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/data/model/file_paths_model.dart';
3 | import 'package:flutter_sharez/data/model/sender_model.dart';
4 | import 'package:flutter_sharez/data/service/receiver/receiver_service_pod.dart';
5 | import 'package:flutter_sharez/shared/riverpod_ext/cancel_extensions.dart';
6 |
7 | final senderfileListPod = FutureProvider.autoDispose
8 | .family((ref, sendermodel) async {
9 | final result = await ref
10 | .watch(receiverServicePod(sendermodel))
11 | .getFilePaths(cancelToken: ref.cancelToken());
12 | return result.when(
13 | (filepathsmodel) {
14 | return filepathsmodel;
15 | },
16 | (error) => throw error.message,
17 | );
18 | });
19 |
--------------------------------------------------------------------------------
/lib/features/device_share/view/device_share_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_sharez/core/router/router.gr.dart';
4 |
5 | import 'package:flutter_sharez/data/model/sender_model.dart';
6 | import 'package:velocity_x/velocity_x.dart';
7 |
8 | @RoutePage(
9 | deferredLoading: true,
10 | )
11 | class DeviceSharePage extends StatelessWidget {
12 | final SenderModel senderModel;
13 | const DeviceSharePage({super.key, required this.senderModel});
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return DeviceShareView(
18 | senderModel: senderModel,
19 | );
20 | }
21 | }
22 |
23 | class DeviceShareView extends StatelessWidget {
24 | final SenderModel senderModel;
25 | const DeviceShareView({super.key, required this.senderModel});
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return AutoTabsRouter.tabBar(
30 | routes: [
31 | DeviceInfoTabRoute(senderModel: senderModel),
32 | SenderFilesTabRoute(senderModel: senderModel)
33 | ],
34 | builder: (context, child, tabsRouter) {
35 | return Scaffold(
36 | body: [
37 | ColoredBox(
38 | color: context.theme.dialogBackgroundColor,
39 | child: TabBar(
40 | controller: tabsRouter,
41 | tabs: const [
42 | Tab(
43 | text: 'Device Info',
44 | icon: Icon(Icons.info_outline_rounded)),
45 | Tab(text: 'Files', icon: Icon(Icons.folder_open_outlined)),
46 | ],
47 | ),
48 | ).flexible(),
49 | child.expand()
50 | ].vStack(),
51 | );
52 | },
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/features/device_share/view/tabs/device_info_tab_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_sharez/data/model/sender_model.dart';
4 | import 'package:flutter_sharez/shared/widget/os_logo.dart';
5 | import 'package:velocity_x/velocity_x.dart';
6 |
7 | @RoutePage(
8 | deferredLoading: true,
9 | )
10 | class DeviceInfoTabPage extends StatelessWidget {
11 | final SenderModel senderModel;
12 | const DeviceInfoTabPage({super.key, required this.senderModel});
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return ListView(
17 | children: [
18 | ListTile(
19 | title: "Host: ${senderModel.host}".text.make(),
20 | ),
21 | ListTile(
22 | title: "IP: ${senderModel.ip}".text.make(),
23 | ),
24 | ListTile(
25 | title: "Port: ${senderModel.port}".text.make(),
26 | ),
27 | ListTile(
28 | title: "OS: ${senderModel.os}".text.make(),
29 | trailing: OSLogo(os: senderModel.os),
30 | ),
31 | ListTile(
32 | title: "Version: ${senderModel.version}".text.make(),
33 | )
34 | ],
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/features/downloads/view/downloads_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:auto_route/auto_route.dart';
3 |
4 | import 'package:flutter/material.dart';
5 |
6 | import 'package:flutter_sharez/translation_pod.dart';
7 | import 'package:velocity_x/velocity_x.dart';
8 |
9 | @RoutePage(
10 | deferredLoading: true,
11 | )
12 | class DownloadsPage extends ConsumerWidget {
13 | const DownloadsPage({super.key});
14 |
15 | @override
16 | Widget build(BuildContext context, WidgetRef ref) {
17 | final t = ref.watch(translationsPod);
18 | return Scaffold(
19 | appBar: AppBar(
20 | title: t.downloads.text.make(),
21 | ),
22 | body: ListView(
23 | physics: const ClampingScrollPhysics(),
24 | padding: const EdgeInsets.all(8),
25 | children: [
26 | ListTile(
27 | title: "Change".text.make(),
28 | onTap: () async {
29 | // Translations t2 = await AppLocaleUtils.v(
30 | // locale: AppLocaleUtils.parse("or"),
31 | // isFlatMap: false,
32 | // map: {
33 | // t.action_downloads: "action download",
34 | // t.downloads: 'updated transladsdtdsad',
35 | // },
36 | // );
37 | // ref.read(translationsPod.notifier).update(
38 | // (state) => t2,
39 | // );
40 | },
41 | )
42 | ],
43 | ),
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/features/file_download_btn/controller/file_download_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/data/model/file_paths_model.dart';
3 | import 'package:flutter_sharez/features/file_download_btn/controller/notifier/file_download_notifier.dart';
4 | import 'package:flutter_sharez/features/file_download_btn/state/file_download_state.dart';
5 |
6 | final fileDownloaderPod = AsyncNotifierProvider.autoDispose
7 | .family(
8 | FileDownloaderNotifier.new);
9 |
--------------------------------------------------------------------------------
/lib/features/file_download_btn/state/file_download_state.dart:
--------------------------------------------------------------------------------
1 | import 'package:dart_mappable/dart_mappable.dart';
2 | part 'file_download_state.mapper.dart';
3 |
4 | @MappableClass()
5 | sealed class DownloadState with DownloadStateMappable {
6 | const DownloadState(); // Factory constructor for initial state
7 | factory DownloadState.initial() => const InitialDownloadState();
8 |
9 | // Factory constructor for downloading state
10 | factory DownloadState.downloading({
11 | required Progress progress,
12 | required bool isPaused,
13 | }) =>
14 | DownloadingState(
15 | progress: progress,
16 | isPaused: isPaused,
17 | );
18 |
19 | // Factory constructor for completed state
20 | factory DownloadState.completed() => const CompletedDownloadState();
21 |
22 | // Factory constructor for error state
23 | factory DownloadState.error() => const ErrorDownloadState();
24 |
25 | // Factory constructor for merge done state
26 | factory DownloadState.mergeDone({required bool isCompleted}) =>
27 | MergeDoneState(isCompleted);
28 | }
29 |
30 | @MappableClass()
31 | class InitialDownloadState extends DownloadState
32 | with InitialDownloadStateMappable {
33 | const InitialDownloadState();
34 | }
35 |
36 | @MappableClass()
37 | class DownloadingState extends DownloadState with DownloadingStateMappable {
38 | final Progress progress;
39 | final bool isPaused;
40 |
41 | const DownloadingState({required this.progress, required this.isPaused});
42 | }
43 |
44 | @MappableClass()
45 | class CompletedDownloadState extends DownloadState
46 | with CompletedDownloadStateMappable {
47 | const CompletedDownloadState();
48 | }
49 |
50 | @MappableClass()
51 | class ErrorDownloadState extends DownloadState with ErrorDownloadStateMappable {
52 | const ErrorDownloadState();
53 | }
54 |
55 | @MappableClass()
56 | class MergeDoneState extends DownloadState with MergeDoneStateMappable {
57 | final bool isCompleted;
58 | const MergeDoneState(this.isCompleted);
59 | }
60 |
61 | @MappableClass()
62 | class Progress with ProgressMappable {
63 | double currentProgress;
64 | double speed;
65 | double remainTime;
66 |
67 | Progress({
68 | required this.currentProgress,
69 | required this.speed,
70 | required this.remainTime,
71 | });
72 | }
73 |
--------------------------------------------------------------------------------
/lib/features/file_selector/controller/selected_files_list_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/data/model/file_select_model.dart';
3 | import 'package:flutter_sharez/features/file_selector/controller/notifier/selected_files_notifier.dart';
4 |
5 | final selectedFilesPod =
6 | NotifierProvider.autoDispose>(
7 | FilesListNotifier.new,
8 | name: 'selectedFilesPod',
9 | );
10 |
--------------------------------------------------------------------------------
/lib/features/file_selector/state/select_file_state.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | sealed class SelectFileState {
4 | const SelectFileState();
5 | }
6 |
7 | class Initial implements SelectFileState {
8 | const Initial();
9 | }
10 |
11 | class PermissionDenied implements SelectFileState {
12 | const PermissionDenied();
13 | }
14 |
15 | class SelectFiles implements SelectFileState {
16 | const SelectFiles();
17 | }
18 |
19 | class SelectFileStateError implements SelectFileState {
20 | final String message;
21 | final String? details;
22 | SelectFileStateError({
23 | required this.message,
24 | this.details,
25 | });
26 |
27 | SelectFileStateError copyWith({
28 | String? message,
29 | String? details,
30 | }) {
31 | return SelectFileStateError(
32 | message: message ?? this.message,
33 | details: details ?? this.details,
34 | );
35 | }
36 |
37 | Map toMap() {
38 | return {
39 | 'message': message,
40 | 'details': details,
41 | };
42 | }
43 |
44 | factory SelectFileStateError.fromMap(Map map) {
45 | return SelectFileStateError(
46 | message: map['message'] ?? '',
47 | details: map['details'],
48 | );
49 | }
50 |
51 | String toJson() => json.encode(toMap());
52 |
53 | factory SelectFileStateError.fromJson(String source) =>
54 | SelectFileStateError.fromMap(json.decode(source));
55 |
56 | @override
57 | String toString() =>
58 | 'SelectFileStateError(message: $message, details: $details)';
59 |
60 | @override
61 | bool operator ==(Object other) {
62 | if (identical(this, other)) return true;
63 |
64 | return other is SelectFileStateError &&
65 | other.message == message &&
66 | other.details == details;
67 | }
68 |
69 | @override
70 | int get hashCode => message.hashCode ^ details.hashCode;
71 | }
72 |
--------------------------------------------------------------------------------
/lib/features/file_selector/view/file_list_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:file_sizes/file_sizes.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 | import 'package:flutter_sharez/data/model/file_select_model.dart';
5 | import 'package:flutter_sharez/features/file_selector/controller/selected_files_list_pod.dart';
6 | import 'package:velocity_x/velocity_x.dart';
7 |
8 | class FileListView extends StatelessWidget {
9 | final List files;
10 | const FileListView({super.key, required this.files});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return ListView.separated(
15 | itemCount: files.length,
16 | padding: const EdgeInsets.only(
17 | bottom: 80,
18 | top: 16,
19 | ),
20 | separatorBuilder: (context, index) => const Divider(),
21 | itemBuilder: (context, index) {
22 | final file = files[index];
23 | return ListTile(
24 | minVerticalPadding: 0,
25 | leading: index
26 | .toString()
27 | .text
28 | .color(context.colors.onSurface)
29 | .bold
30 | .makeCentered()
31 | .circle(
32 | radius: 24,
33 | backgroundColor: context.colors.surface,
34 | ),
35 | title: file.file.name.text.make(),
36 | subtitle: "size: ${FileSize.getSize(file.file.size)}"
37 | .toString()
38 | .text
39 | .make(),
40 | trailing: Consumer(
41 | builder: (context, ref, child) {
42 | return IconButton(
43 | onPressed: () {
44 | ref.read(selectedFilesPod.notifier).deleteItem(index);
45 | },
46 | icon: const Icon(
47 | Icons.delete,
48 | color: Vx.red400,
49 | ));
50 | },
51 | ),
52 | );
53 | },
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/features/help_dialog/view/help_dialog_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:auto_route/auto_route.dart';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_sharez/translation_pod.dart';
6 |
7 | import 'package:url_launcher/url_launcher.dart';
8 | import 'package:velocity_x/velocity_x.dart';
9 |
10 | @RoutePage(
11 | deferredLoading: true,
12 | )
13 | class HelpDialogPage extends ConsumerWidget {
14 | const HelpDialogPage({super.key});
15 |
16 | void launchGithubissue() async {
17 | final uri =
18 | Uri.parse('https://github.com/Shreemanarjun/flutter_sharez/issues');
19 | if (!await launchUrl(uri, mode: LaunchMode.externalApplication)) {
20 | throw Exception('Could not launch $uri');
21 | }
22 | }
23 |
24 | @override
25 | Widget build(BuildContext context, WidgetRef ref) {
26 | final t = ref.watch(translationsPod);
27 | return AlertDialog(
28 | title: t.reportABug.text.xl.isIntrinsic.makeCentered(),
29 | content: t.reportDescription.text.bold.lg.center.isIntrinsic.make(),
30 | actionsAlignment: MainAxisAlignment.spaceAround,
31 | actions: [
32 | TextButton(
33 | style: ElevatedButton.styleFrom(
34 | backgroundColor: context.colors.tertiary,
35 | foregroundColor: context.colors.surface,
36 | ),
37 | onPressed: () {
38 | context.back();
39 | },
40 | child: t.cancel.text.isIntrinsic.make(),
41 | ),
42 | TextButton(
43 | style: ElevatedButton.styleFrom(
44 | backgroundColor: context.colors.primary,
45 | foregroundColor: context.colors.surface,
46 | ),
47 | onPressed: launchGithubissue,
48 | child: t.report.text.isIntrinsic.make(),
49 | ),
50 | ],
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/features/home/view/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | import 'package:flutter_sharez/core/router/router.gr.dart';
6 | import 'package:flutter_sharez/core/router/router_pod.dart';
7 | import 'package:flutter_sharez/features/update_app_version/controller/check_update_available.dart';
8 | import 'package:flutter_sharez/translation_pod.dart';
9 |
10 | @RoutePage(
11 | deferredLoading: true,
12 | )
13 | class HomePage extends ConsumerWidget {
14 | const HomePage({super.key});
15 |
16 | @override
17 | Widget build(BuildContext context, WidgetRef ref) {
18 | final t = ref.watch(translationsPod);
19 | ref.listen(
20 | checkUpdateAvailablePod,
21 | (previous, next) {
22 | if (next is AsyncData && next.value != null) {
23 | ref
24 | .read(autorouterProvider)
25 | .navigate(ChangelogRoute(updateModel: next.value));
26 | }
27 | },
28 | );
29 | return AutoTabsScaffold(
30 | routes: const [
31 | SendRoute(),
32 | ReceiveRoute(),
33 | ],
34 | bottomNavigationBuilder: (context, tabsRouter) {
35 | return NavigationBar(
36 | selectedIndex: tabsRouter.activeIndex,
37 | onDestinationSelected: tabsRouter.setActiveIndex,
38 | destinations: [
39 | NavigationDestination(
40 | icon: const Icon(Icons.arrow_upward_outlined),
41 | label: t.sendLbl,
42 | ),
43 | NavigationDestination(
44 | icon: const Icon(Icons.arrow_downward_outlined),
45 | label: t.receiveLbl,
46 | ),
47 | ],
48 | );
49 | },
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/features/manual_connect/view/manual_connect_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:auto_route/auto_route.dart';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_form_builder/flutter_form_builder.dart';
6 | import 'package:flutter_sharez/translation_pod.dart';
7 |
8 | import 'package:velocity_x/velocity_x.dart';
9 |
10 | @RoutePage(
11 | deferredLoading: true,
12 | )
13 | class ManualConnectPage extends ConsumerStatefulWidget {
14 | const ManualConnectPage({super.key});
15 |
16 | @override
17 | ConsumerState createState() => _ManualConnectPageState();
18 | }
19 |
20 | class _ManualConnectPageState extends ConsumerState {
21 | final _formKey = GlobalKey();
22 | @override
23 | void dispose() {
24 | _formKey.currentState?.dispose();
25 | super.dispose();
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | final t = ref.watch(translationsPod);
31 | return AlertDialog(
32 | alignment: Alignment.center,
33 | content: FormBuilder(
34 | key: _formKey,
35 | child: [
36 | FormBuilderTextField(
37 | name: 'ip',
38 | decoration: InputDecoration(
39 | labelText: t.enterIp,
40 | ),
41 | ).p4(),
42 | FormBuilderTextField(
43 | name: 'port',
44 | decoration: InputDecoration(
45 | labelText: t.enterPort,
46 | ),
47 | ).p4(),
48 | ].vStack(
49 | crossAlignment: CrossAxisAlignment.start,
50 | alignment: MainAxisAlignment.spaceAround,
51 | axisSize: MainAxisSize.min,
52 | ),
53 | ),
54 | actions: [
55 | ElevatedButton(
56 | onPressed: () {},
57 | child: t.connect.text.isIntrinsic.make(),
58 | )
59 | ],
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/features/qr_scan/qr_scan_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:ai_barcode_scanner/ai_barcode_scanner.dart';
3 | import 'package:auto_route/auto_route.dart';
4 |
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter_sharez/bootstrap.dart';
7 | import 'package:flutter_sharez/translation_pod.dart';
8 |
9 | import 'package:platform_info/platform_info.dart';
10 | import 'package:velocity_x/velocity_x.dart';
11 |
12 | @RoutePage(
13 | deferredLoading: true,
14 | )
15 | class QrScanPage extends ConsumerStatefulWidget {
16 | const QrScanPage({super.key});
17 |
18 | @override
19 | ConsumerState createState() => _QrScanPageState();
20 | }
21 |
22 | class _QrScanPageState extends ConsumerState {
23 | final scannerController = MobileScannerController(
24 | detectionSpeed: DetectionSpeed.noDuplicates,
25 | );
26 |
27 | @override
28 | void dispose() {
29 | scannerController.dispose();
30 | super.dispose();
31 | }
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | final t = ref.watch(translationsPod);
36 | return AlertDialog(
37 | content: Platform.I.desktop
38 | ? [
39 | t.qrscannotSupported.text.isIntrinsic.make(),
40 | FilledButton(
41 | onPressed: () {
42 | Navigator.pop(context);
43 | },
44 | child: t.ok.text.isIntrinsic.make(),
45 | ).p8()
46 | ].vStack(
47 | axisSize: MainAxisSize.min,
48 | )
49 | : AiBarcodeScanner(
50 | onDetect: (value) {
51 | talker.debug(value);
52 | scannerController.stop();
53 | Navigator.of(context).pop();
54 | },
55 | controller: scannerController,
56 | ).hHalf(context),
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/lib/features/receive/controller/connect_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/data/model/sender_model.dart';
3 | import 'package:flutter_sharez/features/receive/controller/notifier/connect_btn_notifier.dart';
4 | import 'package:flutter_sharez/features/receive/state/connect_btn_state_pod.dart';
5 |
6 | final connectBtnPod = AsyncNotifierProvider.autoDispose
7 | .family(
8 | ConnectBtnNotifier.new);
9 |
--------------------------------------------------------------------------------
/lib/features/receive/controller/notifier/connect_btn_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 | import 'package:flutter_sharez/data/model/sender_model.dart';
5 | import 'package:flutter_sharez/data/service/receiver/receiver_service_pod.dart';
6 | import 'package:flutter_sharez/features/receive/state/connect_btn_state_pod.dart';
7 | import 'package:flutter_sharez/shared/riverpod_ext/cancel_extensions.dart';
8 |
9 |
10 | class ConnectBtnNotifier
11 | extends AutoDisposeFamilyAsyncNotifier {
12 | @override
13 | FutureOr build(SenderModel arg) {
14 | return UnconnectedState();
15 | }
16 |
17 | Future connectToDevice() async {
18 | state = AsyncData(ConnectingState());
19 | state = await AsyncValue.guard(() async {
20 | final receiverService = ref.watch(receiverServicePod(arg));
21 | // final currentIP = await NetworkDiscovery.discoverDeviceIpAddress();
22 | final result = await receiverService.connectToDevice(
23 | ip: arg.ip.toString(),
24 | port: arg.port.toString(),
25 | currentIP: "currentIP",
26 | cancelToken: ref.cancelToken(),
27 | );
28 | return result.when((isAccepted) {
29 | ref.keepAlive();
30 | return ConenctionAcceptanceState(isAccepted: isAccepted);
31 | }, (error) {
32 | return ConnectionFailedState(message: error.message);
33 | });
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/features/receive/state/connect_btn_state_pod.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | sealed class ConnectBtnState {
4 | const ConnectBtnState();
5 | }
6 |
7 | class UnconnectedState implements ConnectBtnState {}
8 |
9 | class ConnectingState implements ConnectBtnState {}
10 |
11 | class ConenctionAcceptanceState implements ConnectBtnState {
12 | final bool isAccepted;
13 | ConenctionAcceptanceState({
14 | required this.isAccepted,
15 | });
16 |
17 | ConenctionAcceptanceState copyWith({
18 | bool? isAccepted,
19 | }) {
20 | return ConenctionAcceptanceState(
21 | isAccepted: isAccepted ?? this.isAccepted,
22 | );
23 | }
24 |
25 | Map toMap() {
26 | return {
27 | 'isAccepted': isAccepted,
28 | };
29 | }
30 |
31 | factory ConenctionAcceptanceState.fromMap(Map map) {
32 | return ConenctionAcceptanceState(
33 | isAccepted: map['isAccepted'] ?? false,
34 | );
35 | }
36 |
37 | String toJson() => json.encode(toMap());
38 |
39 | factory ConenctionAcceptanceState.fromJson(String source) =>
40 | ConenctionAcceptanceState.fromMap(json.decode(source));
41 |
42 | @override
43 | String toString() => 'ConenctionAcceptanceState(isAccepted: $isAccepted)';
44 |
45 | @override
46 | bool operator ==(Object other) {
47 | if (identical(this, other)) return true;
48 |
49 | return other is ConenctionAcceptanceState && other.isAccepted == isAccepted;
50 | }
51 |
52 | @override
53 | int get hashCode => isAccepted.hashCode;
54 | }
55 |
56 | class ConnectionFailedState implements ConnectBtnState {
57 | final String message;
58 | ConnectionFailedState({
59 | required this.message,
60 | });
61 |
62 | ConnectionFailedState copyWith({
63 | String? message,
64 | }) {
65 | return ConnectionFailedState(
66 | message: message ?? this.message,
67 | );
68 | }
69 |
70 | Map toMap() {
71 | return {
72 | 'message': message,
73 | };
74 | }
75 |
76 | factory ConnectionFailedState.fromMap(Map map) {
77 | return ConnectionFailedState(
78 | message: map['message'] ?? '',
79 | );
80 | }
81 |
82 | String toJson() => json.encode(toMap());
83 |
84 | factory ConnectionFailedState.fromJson(String source) =>
85 | ConnectionFailedState.fromMap(json.decode(source));
86 |
87 | @override
88 | String toString() => 'ConnectionFailedState(message: $message)';
89 |
90 | @override
91 | bool operator ==(Object other) {
92 | if (identical(this, other)) return true;
93 |
94 | return other is ConnectionFailedState && other.message == message;
95 | }
96 |
97 | @override
98 | int get hashCode => message.hashCode;
99 | }
100 |
--------------------------------------------------------------------------------
/lib/features/receive/state/receive_scan_start.dart:
--------------------------------------------------------------------------------
1 | sealed class ReceieveScan {
2 | const ReceieveScan();
3 | }
4 |
5 | class InitialReceiveScan implements ReceieveScan {
6 | const InitialReceiveScan();
7 | }
8 |
9 | class Scanning implements ReceieveScan {
10 | const Scanning();
11 | }
12 |
13 | class ScanError implements ReceieveScan {
14 | final String error;
15 | ScanError({
16 | required this.error,
17 | });
18 |
19 | @override
20 | bool operator ==(Object other) {
21 | if (identical(this, other)) return true;
22 |
23 | return other is ScanError && other.error == error;
24 | }
25 |
26 | @override
27 | int get hashCode => error.hashCode;
28 | }
29 |
--------------------------------------------------------------------------------
/lib/features/receive/view/receive_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_sharez/core/router/router.gr.dart';
4 | import 'package:flutter_sharez/shared/widget/custom_app_bar.dart';
5 |
6 | @RoutePage(
7 | deferredLoading: true,
8 | )
9 | class ReceivePage extends StatelessWidget {
10 | const ReceivePage({super.key});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | appBar: CustomAppBar(
16 | appActions: [
17 | IconButton(
18 | onPressed: () {
19 | context.navigateTo(const DownloadsRoute());
20 | },
21 | icon: const Icon(
22 | Icons.download_outlined,
23 | ),
24 | tooltip: 'Downloads',
25 | ),
26 | IconButton(
27 | onPressed: () {
28 | context.navigateTo(const SettingsRoute());
29 | },
30 | icon: const Icon(Icons.settings_outlined),
31 | tooltip: 'App Settings',
32 | ),
33 | ],
34 | ),
35 | body: const AutoRouter(),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/features/send/controller/notifier/send_state_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 | import 'package:flutter_sharez/core/router/router.gr.dart';
5 | import 'package:flutter_sharez/core/router/router_pod.dart';
6 | import 'package:flutter_sharez/data/service/sender/sender_service_pod.dart';
7 | import 'package:flutter_sharez/features/file_selector/controller/selected_files_list_pod.dart';
8 | import 'package:flutter_sharez/features/send/state/send_state.dart';
9 |
10 | class SendStateNotifier extends AutoDisposeAsyncNotifier {
11 | @override
12 | FutureOr build() async {
13 | return await startServer();
14 | }
15 |
16 | Future startServer() async {
17 | SendState mystate = const StartingServer();
18 |
19 | final files = ref.read(selectedFilesPod);
20 | final sendService = ref.watch(senderServicePod);
21 | if (files.isNotEmpty) {
22 | final result = await sendService.startServer(
23 | onCheckServerCalled: (receivermodel) async {
24 | final Completer sendConfirmCompleter = Completer();
25 | if (sendConfirmCompleter.isCompleted) {
26 | return false;
27 | } else {
28 | final value = await ref
29 | .read(autorouterProvider)
30 | .navigate(ConfirmConnectionDialogRoute(
31 | receiverModel: receivermodel,
32 | onCofirmation: (v) {
33 | if (!sendConfirmCompleter.isCompleted) {
34 | sendConfirmCompleter.complete(v);
35 | }
36 | },
37 | ));
38 | if (value is bool) {
39 | return value;
40 | }
41 | return await sendConfirmCompleter.future;
42 | }
43 | },
44 | );
45 | result.when((success) {
46 | mystate = StartedServer(serverInfo: sendService.getServerInfo());
47 | }, (error) {
48 | mystate = ServerError(
49 | error:
50 | "Server cannot be started due to ${error.message}. Please make sure you have connected to wifi",
51 | );
52 | });
53 | } else {
54 | ref.read(selectedFilesPod.notifier).resetState();
55 | mystate = ServerError(error: 'No files Selected Yet');
56 | }
57 | return mystate;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/lib/features/send/controller/send_notifier_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/features/send/controller/notifier/send_state_notifier.dart';
3 | import 'package:flutter_sharez/features/send/state/send_state.dart';
4 |
5 | final sendStateNotifierPod =
6 | AsyncNotifierProvider.autoDispose(
7 | SendStateNotifier.new,
8 | name: 'sendStateNotifierPod',
9 | );
10 |
--------------------------------------------------------------------------------
/lib/features/send/state/send_state.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter_sharez/data/model/server_info.dart';
4 |
5 | sealed class SendState {
6 | const SendState();
7 | }
8 |
9 | class StartingServer implements SendState {
10 | const StartingServer();
11 | }
12 |
13 | class StartedServer implements SendState {
14 | final ServerInfo serverInfo;
15 | const StartedServer({
16 | required this.serverInfo,
17 | });
18 |
19 | StartedServer copyWith({
20 | ServerInfo? serverInfo,
21 | }) {
22 | return StartedServer(
23 | serverInfo: serverInfo ?? this.serverInfo,
24 | );
25 | }
26 |
27 | Map toMap() {
28 | return {
29 | 'serverInfo': serverInfo.toMap(),
30 | };
31 | }
32 |
33 | factory StartedServer.fromMap(Map map) {
34 | return StartedServer(
35 | serverInfo: ServerInfo.fromMap(map['serverInfo']),
36 | );
37 | }
38 |
39 | String toJson() => json.encode(toMap());
40 |
41 | factory StartedServer.fromJson(String source) =>
42 | StartedServer.fromMap(json.decode(source));
43 |
44 | @override
45 | String toString() => 'StartedServer(serverInfo: $serverInfo)';
46 |
47 | @override
48 | bool operator ==(Object other) {
49 | if (identical(this, other)) return true;
50 |
51 | return other is StartedServer && other.serverInfo == serverInfo;
52 | }
53 |
54 | @override
55 | int get hashCode => serverInfo.hashCode;
56 | }
57 |
58 | class StoppedServer implements SendState {
59 | const StoppedServer();
60 | }
61 |
62 | class ServerError implements SendState {
63 | final String error;
64 | ServerError({
65 | required this.error,
66 | });
67 |
68 | ServerError copyWith({
69 | String? error,
70 | }) {
71 | return ServerError(
72 | error: error ?? this.error,
73 | );
74 | }
75 |
76 | Map toMap() {
77 | return {
78 | 'error': error,
79 | };
80 | }
81 |
82 | factory ServerError.fromMap(Map map) {
83 | return ServerError(
84 | error: map['error'] ?? '',
85 | );
86 | }
87 |
88 | String toJson() => json.encode(toMap());
89 |
90 | factory ServerError.fromJson(String source) =>
91 | ServerError.fromMap(json.decode(source));
92 |
93 | @override
94 | String toString() => 'ServerError(error: $error)';
95 |
96 | @override
97 | bool operator ==(Object other) {
98 | if (identical(this, other)) return true;
99 |
100 | return other is ServerError && other.error == error;
101 | }
102 |
103 | @override
104 | int get hashCode => error.hashCode;
105 | }
106 |
--------------------------------------------------------------------------------
/lib/features/send/view/send_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:auto_route/auto_route.dart';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_sharez/core/router/router.gr.dart';
6 |
7 | import 'package:flutter_sharez/shared/widget/custom_app_bar.dart';
8 | import 'package:flutter_sharez/translation_pod.dart';
9 |
10 | @RoutePage(
11 | deferredLoading: true,
12 | )
13 | class SendPage extends ConsumerWidget {
14 | const SendPage({super.key});
15 |
16 | @override
17 | Widget build(BuildContext context, WidgetRef ref) {
18 | final t = ref.watch(translationsPod);
19 | return Scaffold(
20 | appBar: CustomAppBar(
21 | appActions: [
22 | IconButton(
23 | onPressed: () {
24 | context.navigateTo(const DownloadsRoute());
25 | },
26 | icon: const Icon(
27 | Icons.download_outlined,
28 | ),
29 | tooltip: t.actionDownloads,
30 | ),
31 | IconButton(
32 | onPressed: () {
33 | context.navigateTo(const SettingsRoute());
34 | },
35 | icon: const Icon(Icons.settings_outlined),
36 | tooltip: t.actionSettings,
37 | ),
38 | ],
39 | ),
40 | body: const AutoRouter(),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/features/send/view/send_state_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | import 'package:flutter_sharez/features/send/controller/send_notifier_pod.dart';
6 | import 'package:flutter_sharez/features/send/state/send_state.dart';
7 | import 'package:flutter_sharez/features/send/view/ui_state/started_server_view.dart';
8 | import 'package:flutter_sharez/features/send/view/ui_state/starting_server_view.dart';
9 |
10 | import 'package:flutter_sharez/shared/riverpod_ext/asynvalue_easy_when.dart';
11 | import 'package:flutter_sharez/translation_pod.dart';
12 | import 'package:velocity_x/velocity_x.dart';
13 |
14 | @RoutePage(
15 | deferredLoading: true,
16 | )
17 | class SendStatePage extends ConsumerStatefulWidget {
18 | const SendStatePage({
19 | super.key,
20 | });
21 |
22 | @override
23 | ConsumerState createState() => _SendStatePageState();
24 | }
25 |
26 | class _SendStatePageState extends ConsumerState {
27 | @override
28 | Widget build(BuildContext context) {
29 | final t = ref.watch(translationsPod);
30 | final sendStateAsync = ref.watch(sendStateNotifierPod);
31 | return sendStateAsync.easyWhen(
32 | data: (sendstate) {
33 | return switch (sendstate) {
34 | StartingServer() => const StartingServerView(),
35 | StartedServer(:final serverInfo) => StartedServerView(
36 | serverInfo: serverInfo,
37 | ),
38 | StoppedServer() => t.sendStateServerStopped.text.makeCentered(),
39 | ServerError(:final error) => error.text.makeCentered().p8(),
40 | };
41 | },
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/features/send/view/ui_state/starting_server_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_sharez/translation_pod.dart';
4 |
5 | import 'package:velocity_x/velocity_x.dart';
6 |
7 | class StartingServerView extends ConsumerWidget {
8 | const StartingServerView({super.key});
9 |
10 | @override
11 | Widget build(BuildContext context, WidgetRef ref) {
12 | final t = ref.watch(translationsPod);
13 | return [
14 | const CircularProgressIndicator.adaptive().p8(),
15 | t.settingUpServer.text.make().objectCenter(),
16 | ]
17 | .vStack(
18 | alignment: MainAxisAlignment.center,
19 | )
20 | .safeArea();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/features/send/view/widgets/action_dialog_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:auto_route/auto_route.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 | import 'package:flutter_sharez/data/service/sender/sender_service_pod.dart';
5 |
6 | import 'package:flutter_sharez/shared/helper/global_helper.dart';
7 | import 'package:flutter_sharez/translation_pod.dart';
8 | import 'package:velocity_x/velocity_x.dart';
9 |
10 | @RoutePage()
11 | class StopServerActionDialogPage extends ConsumerStatefulWidget {
12 | final VoidCallback onYesClicked;
13 | const StopServerActionDialogPage({
14 | super.key,
15 | required this.onYesClicked,
16 | });
17 |
18 | @override
19 | ConsumerState createState() =>
20 | _StopServerActionDialogState();
21 | }
22 |
23 | class _StopServerActionDialogState
24 | extends ConsumerState with GlobalHelper {
25 | @override
26 | Widget build(BuildContext context) {
27 | final t = ref.watch(translationsPod);
28 | return AlertDialog(
29 | actionsAlignment: MainAxisAlignment.spaceAround,
30 | actions: [
31 | ElevatedButton(
32 | onPressed: () async {
33 | await ref.read(senderServicePod).stopServer();
34 | if (context.mounted) {
35 | Navigator.of(context).pop();
36 | }
37 | widget.onYesClicked();
38 | },
39 | child: t.dialogActionYes.text.isIntrinsic.green500.bold.make(),
40 | ).p4(),
41 | ElevatedButton(
42 | onPressed: () {
43 | Navigator.of(context).pop();
44 | completer.complete(false);
45 | },
46 | child: t.dialogActionNo.text.isIntrinsic.red500.bold.make(),
47 | ).p4(),
48 | ],
49 | title: t.stopSharingTitle.text.center.isIntrinsic.make(),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/features/send/view/widgets/send_actions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/core/router/router.gr.dart';
4 | import 'package:flutter_sharez/core/router/router_pod.dart';
5 |
6 | import 'package:flutter_sharez/data/model/server_info.dart';
7 |
8 | import 'package:flutter_sharez/shared/helper/global_helper.dart';
9 | import 'package:flutter_sharez/translation_pod.dart';
10 |
11 | import 'package:velocity_x/velocity_x.dart';
12 |
13 | class SendActions extends ConsumerStatefulWidget {
14 | final ServerInfo serverInfo;
15 | const SendActions({
16 | super.key,
17 | required this.serverInfo,
18 | });
19 |
20 | @override
21 | ConsumerState createState() => _SendActionsState();
22 | }
23 |
24 | class _SendActionsState extends ConsumerState with GlobalHelper {
25 | @override
26 | Widget build(BuildContext context) {
27 | final t = ref.watch(translationsPod);
28 | return Wrap(
29 | children: [
30 | Tooltip(
31 | message: t.copyAddressTooltip,
32 | child: ElevatedButton.icon(
33 | onPressed: () async => await copyToClipBoard(
34 | text: '${widget.serverInfo.ip}:${widget.serverInfo.port}',
35 | message: t.addressCopiedMsg,
36 | ),
37 | icon: const Icon(Icons.content_copy_outlined),
38 | label: t.copyAddressTooltip.text.make(),
39 | ),
40 | ).p8(),
41 | Consumer(
42 | builder: (context, ref, child) {
43 | return ElevatedButton.icon(
44 | onPressed: () async {
45 | await ref.read(autorouterProvider).navigate(
46 | StopServerActionDialogRoute(
47 | onYesClicked: () {
48 | Navigator.pop(context);
49 | },
50 | ),
51 | );
52 | },
53 | label: t.stopSharing.text.red500.bold.make(),
54 | icon: const Icon(Icons.cancel_outlined),
55 | ).p8();
56 | },
57 | ),
58 | ],
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/features/send/view/widgets/share_on_web.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/data/model/server_info.dart';
4 |
5 | import 'package:flutter_sharez/shared/helper/global_helper.dart';
6 | import 'package:flutter_sharez/translation_pod.dart';
7 | import 'package:qr_flutter/qr_flutter.dart';
8 | import 'package:velocity_x/velocity_x.dart';
9 |
10 | class ShareOnWebSheet extends ConsumerStatefulWidget {
11 | final ServerInfo serverInfo;
12 | const ShareOnWebSheet({super.key, required this.serverInfo});
13 |
14 | @override
15 | ConsumerState createState() => _ShareOnWebSheetState();
16 | }
17 |
18 | class _ShareOnWebSheetState extends ConsumerState
19 | with GlobalHelper {
20 | @override
21 | Widget build(BuildContext context) {
22 | final t = ref.watch(translationsPod);
23 | return [
24 | QrImageView(
25 | data: '${widget.serverInfo.ip}:${widget.serverInfo.port}/filepath/web',
26 | version: QrVersions.auto,
27 | size: context.safePercentHeight * 18,
28 | gapless: true,
29 | embeddedImageStyle: const QrEmbeddedImageStyle(size: Size(120, 120)),
30 | embeddedImage: const AssetImage(
31 | 'assets/images/logo/ic_launcher_adaptive_fore.png',
32 | ),
33 | constrainErrorBounds: true,
34 | dataModuleStyle: QrDataModuleStyle(
35 | color: context.colors.primary,
36 | ),
37 | eyeStyle: QrEyeStyle(
38 | color: context.colors.primary,
39 | ),
40 | ).p8().flexible(),
41 | t.shareWebMsg.text.xl.bold.center.make().px4(),
42 | '${widget.serverInfo.ip}:${widget.serverInfo.port}/web '
43 | .text
44 | .extraBold
45 | .green500
46 | .lg
47 | .makeCentered()
48 | .py8(),
49 | Tooltip(
50 | message: t.copyAddressTooltip,
51 | child: ElevatedButton.icon(
52 | onPressed: () async => await copyToClipBoard(
53 | text: '${widget.serverInfo.ip}:${widget.serverInfo.port}/web ',
54 | message: t.addressCopiedMsg,
55 | ),
56 | icon: const Icon(Icons.content_copy_outlined),
57 | label: t.copyAddressTooltip.text.make(),
58 | ),
59 | ).p8(),
60 | ].vStack().whFull(context);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/features/settings/controller/current_version_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/bootstrap.dart';
3 | import 'package:package_info_plus/package_info_plus.dart';
4 |
5 | final currentVersionPod = FutureProvider.autoDispose((ref) async {
6 | PackageInfo packageInfo = await PackageInfo.fromPlatform();
7 |
8 | talker.log(packageInfo.toString());
9 | ref.keepAlive();
10 | return "v${packageInfo.version}+${packageInfo.buildNumber}";
11 | });
12 |
--------------------------------------------------------------------------------
/lib/features/settings/view/settings_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:auto_route/annotations.dart';
3 |
4 | import 'package:flutter/material.dart';
5 |
6 | import 'package:flutter_sharez/shared/widget/app_locale_popup.dart';
7 | import 'package:flutter_sharez/translation_pod.dart';
8 | import 'package:velocity_x/velocity_x.dart';
9 | import 'package:flutter_sharez/features/settings/view/widget/about_app_tile.dart';
10 | import 'package:flutter_sharez/features/theme_segmented_btn/view/theme_segmented_btn.dart';
11 |
12 | @RoutePage(
13 | deferredLoading: true,
14 | )
15 | class SettingsPage extends ConsumerWidget {
16 | const SettingsPage({super.key});
17 |
18 | @override
19 | Widget build(BuildContext context, WidgetRef ref) {
20 | final t = ref.watch(translationsPod);
21 | return Scaffold(
22 | appBar: AppBar(
23 | title: t.settingsPage.text.make(),
24 | ),
25 | bottomNavigationBar: BottomSheet(
26 | onClosing: () {},
27 | builder: (context) => const AboutAppTile(),
28 | enableDrag: false,
29 | showDragHandle: false,
30 | ).safeArea(),
31 | body: ListView(
32 | physics: const ClampingScrollPhysics(),
33 | padding: const EdgeInsets.all(8),
34 | children: [
35 | ListTile(
36 | title: t.changeLanguage.text.bold.make(),
37 | trailing: const AppLocalePopUp(),
38 | ),
39 | ListTile(
40 | title: t.switchTheme.text.bold.make(),
41 | trailing: const ThemeSegmentedBtn(),
42 | ),
43 | ],
44 | ),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/features/splash/controller/box_encryption_key_pod.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'dart:typed_data';
3 |
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | import 'package:flutter_secure_storage_x/flutter_secure_storage_x.dart';
6 |
7 | import 'package:hive_ce_flutter/hive_flutter.dart';
8 |
9 | final boxEncryptionKeyPod = FutureProvider.autoDispose((ref) async {
10 | const secureStorage = FlutterSecureStorage(
11 | aOptions: AndroidOptions(),
12 | iOptions: IOSOptions(
13 | accessibility: KeychainAccessibility.first_unlock,
14 | ));
15 |
16 | const secureStorageKey = "FlutterSharez";
17 | // if key not exists return null
18 | final encryptionKeyString = await secureStorage.read(key: secureStorageKey);
19 |
20 | if (encryptionKeyString == null) {
21 | final key = Hive.generateSecureKey();
22 | await secureStorage.write(
23 | key: secureStorageKey,
24 | value: base64UrlEncode(key),
25 | );
26 | }
27 | final key = await secureStorage.read(key: secureStorageKey);
28 | final encryptionKeyUint8List = base64Url.decode(key!);
29 | return encryptionKeyUint8List;
30 | });
31 |
--------------------------------------------------------------------------------
/lib/features/splash/controller/future_initializer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/i18n/strings.g.dart';
3 |
4 | import 'package:flutter_sharez/translation_pod.dart';
5 |
6 | import 'package:hive_ce_flutter/hive_flutter.dart';
7 | import 'package:platform_info/platform_info.dart';
8 | import 'package:flutter_sharez/bootstrap.dart';
9 | import 'package:flutter_sharez/core/local_storage/app_storage_pod.dart';
10 | import 'package:flutter_sharez/features/splash/controller/box_encryption_key_pod.dart';
11 | import 'package:flutter_sharez/init.dart';
12 |
13 | import 'package:talker_riverpod_logger/talker_riverpod_logger.dart';
14 |
15 | final futureInitializerPod =
16 | FutureProvider.autoDispose((ref) async {
17 | ///Additional intial delay duration for app
18 | // await Future.delayed(const Duration(seconds: 1));
19 | await (init());
20 | await Hive.initFlutter();
21 |
22 | AppLocale deviceLocale = AppLocaleUtils.findDeviceLocale();
23 | final translations = await deviceLocale.build();
24 |
25 | ///Replace `appBox` namw with any key you want
26 |
27 | final encryptionCipher = await Platform.I.when(
28 | mobile: () async {
29 | final encryptionKey = await ref.watch(boxEncryptionKeyPod.future);
30 | return HiveAesCipher(encryptionKey);
31 | },
32 | );
33 |
34 | final appBox = await Hive.openBox(
35 | 'FlutterSharezBox',
36 | encryptionCipher: encryptionCipher,
37 | );
38 | return ProviderContainer(
39 | overrides: [
40 | appBoxProvider.overrideWithValue(appBox),
41 | translationsPod.overrideWith(
42 | (ref) => translations,
43 | )
44 | ],
45 | observers: [
46 | ///Added new talker riverpod observer
47 | ///
48 | /// If you want old behaviour
49 | /// Replace with
50 | ///
51 | /// MyObserverLogger( talker: talker,)
52 | ///
53 | ///
54 | ///
55 | ///
56 | TalkerRiverpodObserver(
57 | talker: talker,
58 | settings: const TalkerRiverpodLoggerSettings(
59 | printProviderDisposed: true,
60 | ),
61 | ),
62 | ],
63 | );
64 | });
65 |
--------------------------------------------------------------------------------
/lib/features/theme_segmented_btn/controller/selection_theme_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/core/theme/theme_controller.dart';
4 |
5 | ///This provider gives initial value to theme segment button
6 | final themeSelectionPod = Provider.autoDispose>(
7 | (ref) => {ref.watch(themecontrollerProvider)},
8 | name: "themeSelectionPod",
9 | );
10 |
--------------------------------------------------------------------------------
/lib/features/theme_segmented_btn/view/theme_segmented_btn.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/core/theme/theme_controller.dart';
4 | import 'package:flutter_sharez/features/theme_segmented_btn/controller/selection_theme_pod.dart';
5 |
6 | ///This class provider segmented button which can be used
7 | ///for getting current theme and switching theme
8 | class ThemeSegmentedBtn extends ConsumerStatefulWidget {
9 | const ThemeSegmentedBtn({super.key});
10 |
11 | @override
12 | ConsumerState createState() => _ThemeSegmentedBtnState();
13 | }
14 |
15 | class _ThemeSegmentedBtnState extends ConsumerState {
16 | @override
17 | Widget build(BuildContext context) {
18 | return SegmentedButton(
19 | segments: const >[
20 | ButtonSegment(
21 | value: ThemeMode.light,
22 | icon: Icon(Icons.light_mode),
23 | ),
24 | ButtonSegment(
25 | value: ThemeMode.dark,
26 | icon: Icon(Icons.dark_mode),
27 | ),
28 | ButtonSegment(
29 | value: ThemeMode.system,
30 | icon: Icon(Icons.brightness_auto),
31 | ),
32 | ],
33 | selected: ref.watch(themeSelectionPod),
34 | onSelectionChanged: (thememodes) {
35 | ref
36 | .read(themecontrollerProvider.notifier)
37 | .changeTheme(thememodes.first);
38 | },
39 | style: const ButtonStyle(
40 | maximumSize: WidgetStatePropertyAll(Size.fromWidth(12))),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/features/update_app_version/controller/check_update_available.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/bootstrap.dart';
3 | import 'package:flutter_sharez/data/model/update_model.dart';
4 | import 'package:flutter_sharez/features/settings/controller/current_version_pod.dart';
5 | import 'package:flutter_sharez/features/update_app_version/controller/check_update_version.dart';
6 | import 'package:flutter_sharez/shared/helper/version.dart';
7 |
8 | final checkUpdateAvailablePod = FutureProvider.autoDispose(
9 | (ref) async {
10 | final updateModel = await ref.watch(getUpdateModelPod.future);
11 | if (updateModel == null) {
12 | return null;
13 | }
14 | final currentAppVersion =
15 | (await ref.watch(currentVersionPod.future))!.replaceFirst('v', '');
16 | final tagname = updateModel.name.replaceFirst('v', '');
17 | Version currentVersion = Version.parse(currentAppVersion);
18 |
19 | Version latestVersion = Version.parse(tagname);
20 | talker.debug("$currentVersion $latestVersion");
21 |
22 | /// updatemodel when update available
23 |
24 | if (currentVersion < latestVersion) {
25 | return updateModel;
26 | } else {
27 | return null;
28 | }
29 | },
30 | name: 'checkUpdateAvailablePod',
31 | );
32 |
--------------------------------------------------------------------------------
/lib/features/update_app_version/controller/check_update_version.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/data/model/update_model.dart';
4 | import 'package:flutter_sharez/shared/api_client/dio/dio_client_provider.dart';
5 | import 'package:flutter_sharez/shared/riverpod_ext/cancel_extensions.dart';
6 |
7 | final getUpdateModelPod = FutureProvider.autoDispose(
8 | (ref) async {
9 | if (kDebugMode) {
10 | return null;
11 | }
12 | final dio = ref.watch(dioProvider(
13 | "https://api.github.com/repos/Shreemanarjun/flutter_sharez"));
14 | final result = await dio.get(
15 | '/releases/latest',
16 | cancelToken: ref.cancelToken(),
17 | );
18 | return UpdateModel.fromMap(result.data);
19 | },
20 | name: 'getUpdateModelPod',
21 | );
22 |
--------------------------------------------------------------------------------
/lib/features/update_app_version/controller/get_changelog_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:flutter_sharez/shared/api_client/dio/dio_client_provider.dart';
3 | import 'package:flutter_sharez/shared/riverpod_ext/cancel_extensions.dart';
4 |
5 | final getChangeLogPod = FutureProvider.autoDispose(
6 | (ref) async {
7 | final dio = ref.watch(dioProvider(
8 | "https://raw.githubusercontent.com/Shreemanarjun/flutter_sharez/main"));
9 | final result = await dio.get(
10 | '/CHANGELOG.md',
11 | cancelToken: ref.cancelToken(),
12 | );
13 | if (result.statusCode == 200) {
14 | return result.data.toString();
15 | } else {
16 | throw "Error getting changelog";
17 | }
18 | },
19 | name: 'getChangeLogPod',
20 | );
21 |
--------------------------------------------------------------------------------
/lib/features/update_app_version/view/update_app_version_icon.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:flutter_sharez/core/router/router.gr.dart';
4 | import 'package:flutter_sharez/core/router/router_pod.dart';
5 | import 'package:flutter_sharez/features/update_app_version/controller/check_update_available.dart';
6 | import 'package:flutter_sharez/features/update_app_version/controller/check_update_version.dart';
7 | import 'package:flutter_sharez/features/update_app_version/view/widgets/animated_sync.dart';
8 | import 'package:flutter_sharez/shared/riverpod_ext/asynvalue_easy_when.dart';
9 |
10 | class UpdateAppVersionIcon extends ConsumerWidget {
11 | const UpdateAppVersionIcon({super.key});
12 |
13 | @override
14 | Widget build(BuildContext context, WidgetRef ref) {
15 | final updateCheckAsync = ref.watch(checkUpdateAvailablePod);
16 | return updateCheckAsync.easyWhen(
17 | data: (updatemodel) {
18 | return IconButton(
19 | onPressed: () async {
20 | ref.invalidate(getUpdateModelPod);
21 | final data = await ref.read(checkUpdateAvailablePod.future);
22 | ref
23 | .read(autorouterProvider)
24 | .navigate(ChangelogRoute(updateModel: data));
25 | },
26 | icon: Icon(
27 | Icons.sync,
28 | color: updatemodel != null ? Colors.green : null,
29 | ),
30 | );
31 | },
32 | errorWidget: (error, stackTrace) => IconButton(
33 | onPressed: () async {
34 | ref.invalidate(getUpdateModelPod);
35 | final data = await ref.read(checkUpdateAvailablePod.future);
36 | ref
37 | .read(autorouterProvider)
38 | .navigate(ChangelogRoute(updateModel: data));
39 | },
40 | icon: const Icon(
41 | Icons.sync,
42 | color: Colors.red,
43 | )),
44 | loadingWidget: () => const SpinningIconButton(
45 | iconData: Icons.sync,
46 | ),
47 | skipLoadingOnRefresh: false,
48 | skipLoadingOnReload: false);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/features/update_app_version/view/widgets/animated_sync.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class SpinningIconButton extends StatefulWidget {
4 | final IconData iconData;
5 |
6 | const SpinningIconButton({
7 | super.key,
8 | required this.iconData,
9 | });
10 |
11 | @override
12 | State createState() => _SpinningIconButtonState();
13 | }
14 |
15 | class _SpinningIconButtonState extends State
16 | with SingleTickerProviderStateMixin {
17 | late final AnimationController controller;
18 | late final Animation _animation;
19 | @override
20 | void initState() {
21 | controller =
22 | AnimationController(vsync: this, duration: const Duration(seconds: 10));
23 | _animation = CurvedAnimation(
24 | parent: controller,
25 | // Use whatever curve you would like, for more details refer to the Curves class
26 | curve: Curves.linearToEaseOut,
27 | );
28 | controller.forward();
29 |
30 | super.initState();
31 | }
32 |
33 | @override
34 | void dispose() {
35 | controller.stop();
36 | controller.dispose();
37 | super.dispose();
38 | }
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | return RotationTransition(
43 | turns: _animation,
44 | child: IconButton(
45 | icon: Icon(widget.iconData),
46 | onPressed: null,
47 | ));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/init.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 | import 'package:flutter_displaymode/flutter_displaymode.dart';
3 | import 'package:platform_info/platform_info.dart';
4 |
5 | ///This function is used for setting up default orientation,
6 | ///display refresh rate, hide keyboard etc system services.
7 | Future init() async {
8 | await SystemChrome.setPreferredOrientations([
9 | DeviceOrientation.portraitUp,
10 | DeviceOrientation.portraitDown,
11 | ]);
12 | SystemChrome.setEnabledSystemUIMode(
13 | SystemUiMode.edgeToEdge,
14 | overlays: [
15 | SystemUiOverlay.top,
16 | ],
17 | );
18 | await platform.when(
19 | android: FlutterDisplayMode.setHighRefreshRate,
20 | );
21 | await SystemChannels.textInput.invokeMethod('TextInput.hide');
22 | }
23 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 |
4 | import 'package:flutter_sharez/splasher.dart';
5 |
6 | /// This entry point should be used for production only
7 | void main() async {
8 | WidgetsFlutterBinding.ensureInitialized();
9 |
10 | runApp(
11 | ProviderScope(
12 | child: Splasher(),
13 | ),
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/lib/main_development.dart:
--------------------------------------------------------------------------------
1 |
2 | /// This entry point should be used for development only
3 | void main() {
4 | ///You can override your environment variable in bootstrap method here for providers
5 | // bootstrap(() => const App());
6 | }
7 |
--------------------------------------------------------------------------------
/lib/main_production.dart:
--------------------------------------------------------------------------------
1 |
2 | /// This entry point should be used for production only
3 | void main() {
4 | // ///You can override your environment variable in bootstrap method here for providers
5 | // bootstrap(() => const App());
6 | }
7 |
--------------------------------------------------------------------------------
/lib/main_staging.dart:
--------------------------------------------------------------------------------
1 |
2 | /// This entry point should be used for staging only
3 | void main() {
4 | ///You can override your environment variable in bootstrap method here for providers
5 | // bootstrap(() => const App());
6 | }
7 |
--------------------------------------------------------------------------------
/lib/shared/api_client/dio/bad_certificate_fixer.dart:
--------------------------------------------------------------------------------
1 | // coverage:ignore-file
2 |
3 | import 'dart:io';
4 | import 'package:dio/dio.dart';
5 | import 'package:dio/io.dart';
6 | import 'package:flutter/foundation.dart';
7 |
8 | ///This function used for those devices which doesnot support
9 | /// newer ssl certificate and disabled in web
10 | void fixBadCertificate({required Dio dio}) {
11 | if (!kIsWeb) {
12 | dio.httpClientAdapter = IOHttpClientAdapter(
13 | createHttpClient: () {
14 | // Don't trust any certificate just because their root cert is trusted.
15 | final HttpClient client =
16 | HttpClient(context: SecurityContext(withTrustedRoots: false));
17 | // You can test the intermediate / root cert here. We just ignore it.
18 | client.badCertificateCallback = (cert, host, port) => true;
19 | return client;
20 | },
21 | validateCertificate: (cert, host, port) => true,
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/shared/api_client/dio/default_api_interceptor.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter_sharez/shared/api_client/dio/default_api_error_handler.dart';
3 |
4 | // coverage:ignore-file
5 |
6 | ///This one is default interceptor which includes default api
7 | ///error handler
8 | class DefaultAPIInterceptor extends Interceptor {
9 | DefaultAPIInterceptor({
10 | required this.dio,
11 | });
12 | final Dio dio;
13 | @override
14 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
15 | print(options.uri);
16 | super.onRequest(options, handler);
17 | }
18 |
19 | @override
20 | void onError(DioException err, ErrorInterceptorHandler handler) {
21 | defaultAPIErrorHandler(err, handler, dio);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/shared/api_client/dio/default_time_response_interceptor.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: strict_raw_type
2 | // coverage:ignore-file
3 | import 'package:dio/dio.dart';
4 | import 'package:duration/duration.dart';
5 | import 'package:flutter_sharez/bootstrap.dart';
6 |
7 | ///This Interceptor is used check the response time from the server for each request
8 | class TimeResponseInterceptor extends Interceptor {
9 | late Stopwatch stopwatch;
10 |
11 | @override
12 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
13 | stopwatch = Stopwatch()..start();
14 |
15 | super.onRequest(options, handler);
16 | }
17 |
18 | @override
19 | void onResponse(Response response, ResponseInterceptorHandler handler) {
20 | final duration = prettyDuration(
21 | stopwatch.elapsed,
22 | tersity: DurationTersity.millisecond,
23 | );
24 | talker.log('\x1B[34mResponse time 😇 : $duration\x1B[0m');
25 |
26 | super.onResponse(response, handler);
27 | }
28 |
29 | @override
30 | void onError(DioException err, ErrorInterceptorHandler handler) {
31 | final duration = prettyDuration(
32 | stopwatch.elapsed,
33 | tersity: DurationTersity.millisecond,
34 | );
35 | talker.log('\x1B[34mError Response time 😇 : $duration\x1B[0m');
36 |
37 | super.onError(err, handler);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/shared/api_client/dio/dio_client_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import 'package:flutter/foundation.dart';
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | import 'package:flutter_sharez/bootstrap.dart';
6 | import 'package:flutter_sharez/shared/api_client/dio/bad_certificate_fixer.dart';
7 | import 'package:flutter_sharez/shared/api_client/dio/default_api_interceptor.dart';
8 | import 'package:flutter_sharez/shared/api_client/dio/default_time_response_interceptor.dart';
9 | import 'package:flutter_sharez/shared/api_client/dio/form_data_interceptor.dart';
10 | import 'package:talker_dio_logger/talker_dio_logger.dart';
11 |
12 | typedef DeviceAddress = String;
13 |
14 | ///This provider dioClient with interceptors(TimeResponseInterceptor,FormDataInterceptor,TalkerDioLogger,DefaultAPIInterceptor)
15 | ///with fixing bad certificate.
16 | final dioProvider = Provider.autoDispose.family(
17 | (ref, deviceAddress) {
18 | final dio = Dio();
19 | // ..options.receiveTimeout = 1.minutes
20 | // ..options.connectTimeout = 1.minutes;
21 | dio.options.baseUrl = deviceAddress;
22 | if (kDebugMode) {
23 | dio.interceptors.add(TimeResponseInterceptor());
24 | dio.interceptors.add(FormDataInterceptor());
25 | dio.interceptors.add(
26 | TalkerDioLogger(
27 | talker: talker,
28 | settings: const TalkerDioLoggerSettings(
29 | printRequestHeaders: true,
30 | printResponseHeaders: true,
31 | ),
32 | ),
33 | );
34 | }
35 |
36 | dio.interceptors.addAll([
37 | DefaultAPIInterceptor(dio: dio),
38 | // RetryInterceptor(
39 | // dio: dio,
40 | // logPrint: talker.log, // specify log function (optional)
41 | // // retry count (optional)
42 | // retries: 2,
43 | // retryDelays: [
44 | // const Duration(seconds: 2),
45 | // const Duration(seconds: 4),
46 | // const Duration(seconds: 6),
47 | // ],
48 | // retryEvaluator: (error, i) {
49 | // // only retry on DioError
50 | // if (error.error is SocketException) {
51 | // // only retry on timeout error
52 | // return true;
53 | // } else {
54 | // // coverage:ignore-line
55 | // return false;
56 | // }
57 | // },
58 | // ),
59 | ]);
60 | fixBadCertificate(dio: dio);
61 | return dio;
62 | },
63 | name: 'dioProvider',
64 | );
65 |
--------------------------------------------------------------------------------
/lib/shared/api_client/dio/form_data_interceptor.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter_sharez/bootstrap.dart';
3 |
4 | // coverage:ignore-file
5 |
6 | ///This interceptor to print form data content of the request body
7 | class FormDataInterceptor extends Interceptor {
8 | @override
9 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
10 | final data = options.data;
11 |
12 | if (data is FormData) {
13 | ///print form data
14 | for (final item in data.fields) {
15 | talker.log('${item.key} : ${item.value}');
16 | }
17 | }
18 | super.onRequest(options, handler);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/shared/exception/base_exception.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: avoid_dynamic_calls
2 |
3 | import 'dart:convert';
4 |
5 | ///This is the base class exception which can be
6 | ///used to throw with a message
7 | class BaseException implements Exception {
8 | BaseException({this.message = 'Unknown Error'});
9 | final String message;
10 | }
11 |
12 | ///This class used to throw error from API Providers
13 | class APIException implements BaseException {
14 | final int? statusCode;
15 | final String? statusMessage;
16 | final String errorMessage;
17 | APIException({
18 | this.statusCode,
19 | this.statusMessage,
20 | required this.errorMessage,
21 | });
22 |
23 | APIException copyWith({
24 | int? statusCode,
25 | String? statusMessage,
26 | String? errorMessage,
27 | }) {
28 | return APIException(
29 | statusCode: statusCode ?? this.statusCode,
30 | statusMessage: statusMessage ?? this.statusMessage,
31 | errorMessage: errorMessage ?? this.errorMessage,
32 | );
33 | }
34 |
35 | Map toMap() {
36 | return {
37 | 'statusCode': statusCode,
38 | 'statusMessage': statusMessage,
39 | 'errorMessage': errorMessage,
40 | };
41 | }
42 |
43 | factory APIException.fromMap(Map map) {
44 | return APIException(
45 | statusCode: map['statusCode']?.toInt(),
46 | statusMessage: map['statusMessage'],
47 | errorMessage: map['errorMessage'] ?? '',
48 | );
49 | }
50 |
51 | String toJson() => json.encode(toMap());
52 |
53 | factory APIException.fromJson(String source) =>
54 | APIException.fromMap(json.decode(source));
55 |
56 | @override
57 | String toString() =>
58 | 'APIException(statusCode: $statusCode, statusMessage: $statusMessage, errorMessage: $errorMessage)';
59 |
60 | @override
61 | bool operator ==(Object other) {
62 | if (identical(this, other)) return true;
63 |
64 | return other is APIException &&
65 | other.statusCode == statusCode &&
66 | other.statusMessage == statusMessage &&
67 | other.errorMessage == errorMessage;
68 | }
69 |
70 | @override
71 | int get hashCode =>
72 | statusCode.hashCode ^ statusMessage.hashCode ^ errorMessage.hashCode;
73 |
74 | @override
75 | String get message => errorMessage;
76 | }
77 |
--------------------------------------------------------------------------------
/lib/shared/extension/response_success_error_handler.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter_sharez/shared/exception/base_exception.dart';
4 | import 'package:multiple_result/multiple_result.dart';
5 |
6 | typedef Mapper = T Function(dynamic data);
7 |
8 | extension ResponseHandler on Response {
9 | Result successErrorHandler({
10 | required Mapper successMapper,
11 | Mapper? errorMapper,
12 | List defaultSuccessCode = const [200],
13 | }) {
14 | if (defaultSuccessCode.contains(statusCode)) {
15 | if (kDebugMode) {
16 | T successData = successMapper(data);
17 | return Result.success(successData);
18 | } else {
19 | try {
20 | T successData = successMapper(data);
21 | return Result.success(successData);
22 | } catch (e) {
23 | APIException errorData = errorMapper?.call(data) ??
24 | APIException(
25 | statusCode: statusCode,
26 | errorMessage: 'Error parsing response data $e',
27 | );
28 | return Result.error(errorData);
29 | }
30 | }
31 | } else {
32 | late APIException errorData;
33 | if (errorMapper != null) {
34 | errorData = errorMapper(data);
35 | } else {
36 | try {
37 | errorData = APIException.fromMap(data);
38 | } catch (e) {
39 | errorData = APIException(
40 | statusCode: statusCode,
41 | statusMessage: statusMessage,
42 | errorMessage: "Failed to get data $data",
43 | );
44 | }
45 | }
46 |
47 | return Result.error(errorData);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/shared/helper/network_helper.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter_sharez/bootstrap.dart';
4 | import 'package:flutter_sharez/shared/exception/base_exception.dart';
5 | import 'package:multiple_result/multiple_result.dart';
6 |
7 | Future> getDefaultAddress() async {
8 | final ipresult = await getAllIPs();
9 | return ipresult.when(
10 | (iplist) {
11 | if (iplist.isEmpty) {
12 | return Error(BaseException(message: "No IPs found"));
13 | } else {
14 | return Success(iplist.first);
15 | }
16 | },
17 | (error) {
18 | return Error(error);
19 | },
20 | );
21 | }
22 |
23 | Future, BaseException>> getAllIPs() async {
24 | final iplist = [];
25 | try {
26 | final networkinterfaces = await NetworkInterface.list(
27 | type: InternetAddressType.IPv4,
28 | );
29 |
30 | for (var newti in networkinterfaces) {
31 | for (var ip in newti.addresses) {
32 | talker.log(ip.address);
33 | if (ip.address.startsWith("192.168") || ip.address.startsWith("10.0")) {
34 | iplist.add(ip.address);
35 | }
36 | }
37 | }
38 | return Success(iplist);
39 | } catch (e) {
40 | return Error(BaseException(message: e.toString()));
41 | }
42 | }
43 |
44 | List getNetAddress(List ipList) {
45 | List netAdd = [];
46 | for (String ip in ipList) {
47 | var ipToList = ip.split('.');
48 | ipToList.removeLast();
49 | netAdd.add(ipToList.join('.'));
50 | }
51 | return netAdd;
52 | }
53 |
--------------------------------------------------------------------------------
/lib/shared/helper/range_downloader.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'package:dio/dio.dart';
3 |
4 | typedef ProgressCallback = void Function(double progress);
5 | typedef CompleteCallback = void Function();
6 |
7 | Future downloadFileWithResumeAndProgress({
8 | required Dio dio,
9 | required String url,
10 | required String savePath,
11 | required CancelToken cancelToken,
12 | required ProgressCallback onProgress,
13 | required CompleteCallback onComplete,
14 | }) async {
15 | final file = File(savePath);
16 |
17 | double receivedBytes = 0;
18 | if (await file.exists()) {
19 | receivedBytes = (await file.length()).toDouble();
20 | }
21 |
22 | final response = await dio.head(url);
23 | final totalBytes =
24 | double.parse(response.headers.value('content-length') ?? "-1");
25 |
26 | if (receivedBytes < totalBytes) {
27 | final options = Options(
28 | headers: {'range': 'bytes=$receivedBytes-$totalBytes'},
29 | );
30 |
31 | await dio.download(
32 | url,
33 | savePath,
34 | options: options,
35 | cancelToken: cancelToken,
36 | onReceiveProgress: (received, total) {
37 | if (total != -1) {
38 | double progress = received / total;
39 | if (progress <= 1) {
40 | onProgress(progress);
41 | }
42 | }
43 | },
44 | deleteOnError: true,
45 | );
46 |
47 | onComplete();
48 | } else {
49 | onComplete();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/shared/pods/internet_checker_pod.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
3 |
4 | ///This stream provider class holds stream notifier
5 | final internetCheckerNotifierPod =
6 | StreamNotifierProvider.autoDispose(
7 | InternetStatusNotifier.new);
8 |
9 | /// This provider used to when to enable internet checker which
10 | /// can be overriden for default value.
11 | final enableInternetCheckerPod = Provider.autoDispose((ref) {
12 | return true;
13 | });
14 |
15 | /// This provider used to give a instance Internet Connection Checker
16 | final internetConnectionCheckerInstancePod =
17 | Provider.autoDispose((ref) {
18 | final internetchecker = InternetConnection.createInstance(
19 | checkInterval: const Duration(seconds: 5),
20 | );
21 | return internetchecker;
22 | });
23 |
24 | ///This stream notifier class handles internet connection status, and changes status if needed
25 | class InternetStatusNotifier extends AutoDisposeStreamNotifier {
26 | @override
27 | Stream build() {
28 | final enabled = ref.watch(enableInternetCheckerPod);
29 | if (enabled) {
30 | final statuschange =
31 | ref.watch(internetConnectionCheckerInstancePod).onStatusChange;
32 |
33 | return statuschange.distinct();
34 | } else {
35 | return Stream.value(InternetStatus.connected);
36 | }
37 | }
38 |
39 | void change({required InternetStatus status}) {
40 | state = AsyncValue.data(status);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/shared/pods/locale_pod.dart:
--------------------------------------------------------------------------------
1 | /* import 'package:flutter/material.dart';
2 |
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 |
5 | import 'package:flutter_sharez/core/local_storage/app_storage_pod.dart';
6 |
7 | import 'package:flutter_sharez/shared/exception/base_exception.dart';
8 |
9 | ///This Notifier class used to get current locale and change local in DB
10 | class LocaleNotifier extends AutoDisposeNotifier {
11 | final _localeBoxKey = 'locale';
12 |
13 | @override
14 | Locale build() {
15 | final locale = ref.watch(appStorageProvider).get(key: _localeBoxKey);
16 |
17 | if (locale != null) {
18 | return AppLocalizations.supportedLocales
19 | .where((element) => element.languageCode == locale)
20 | .map((e) => Locale(e.languageCode))
21 | .first;
22 | } else {
23 | return AppLocalizations.supportedLocales.first;
24 | }
25 | }
26 |
27 | Future changeLocale({required Locale locale}) async {
28 | final isSupported = AppLocalizations.supportedLocales.contains(locale);
29 | if (isSupported) {
30 | state = locale;
31 | await ref.read(appStorageProvider).put(
32 | key: _localeBoxKey,
33 | value: locale.languageCode,
34 | );
35 | } else {
36 | throw BaseException(message: 'Language not supported');
37 | }
38 | }
39 | }
40 |
41 | final localePod = NotifierProvider.autoDispose(
42 | LocaleNotifier.new,
43 | name: 'localePod',
44 | );
45 | */
46 |
--------------------------------------------------------------------------------
/lib/shared/riverpod_ext/cache_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 |
5 | ///This
6 | extension CacheExtension on Ref {
7 | KeepAliveLink cacheFor([Duration duration = const Duration(seconds: 3)]) {
8 | Timer? timer;
9 | // prevents being disposed
10 | final link = keepAlive();
11 |
12 | // when the provider is no longer used (removed all listeners)
13 | // the timer will be started with the given cache duration
14 | // when the time expires, the link will be closed,
15 | // and the provider will dispose itself
16 | onCancel(() {
17 | timer?.cancel();
18 | link.close();
19 | });
20 |
21 | /// uncomment for better caching leaking fix
22 | /// // when we recall the provider again
23 | // the timer will be canceled and the link will no longer close.
24 | // onResume(() {
25 | // timer?.cancel();
26 | // timer = Timer(duration, link.close);
27 | // });
28 |
29 | timer = Timer(duration, link.close);
30 |
31 | return link;
32 | }
33 |
34 | /// Refreshes the provider's value automatically at a specified interval.
35 | ///
36 | /// This method is best suited for scenarios where real-time data updates are required.
37 | void autoRefresh({required Duration duration}) {
38 | final timer = Timer.periodic(duration, (_) => invalidateSelf());
39 | onDispose(timer.cancel);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/shared/riverpod_ext/cancel_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 |
4 | extension CancelTokenExtension on Ref {
5 | /// creates a token to cancel API requests
6 | CancelToken cancelToken() {
7 | final token = CancelToken();
8 | onCancel(token.cancel);
9 | return token;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lib/shared/riverpod_ext/riverpod_extensions.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_riverpod/flutter_riverpod.dart';
4 |
5 | extension DebounceExtension on Ref {
6 | /// delays the execution of the code for the given duration,
7 | /// if any dependency changes during the period,
8 | /// the timer will reset and restart
9 | /// if nothing changes, the rest of the code will be executed.
10 | Future debounce([
11 | Duration duration = const Duration(milliseconds: 350),
12 | ]) {
13 | final completer = Completer();
14 |
15 | /// creates a timer with the given duration
16 | /// when the time expires, and the completer hasn't completed yet, complete it.
17 | /// and the debounce function lets the rest of the code executed
18 | final timer = Timer(duration, () {
19 | if (!completer.isCompleted) completer.complete();
20 | });
21 |
22 | /// if provider disposed and the completer hasn't completed yet
23 | /// cancel the timer and throw canceled error
24 | onDispose(() {
25 | timer.cancel();
26 | if (!completer.isCompleted) {
27 | completer.complete();
28 | // completer.completeError(StateError('Canceled'));
29 | }
30 | });
31 |
32 | return completer.future;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/shared/riverpod_ext/riverpod_observer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_riverpod/flutter_riverpod.dart';
2 | import 'package:talker_flutter/talker_flutter.dart';
3 |
4 | // coverage:ignore-file
5 | class MyObserverLogger extends ProviderObserver {
6 | MyObserverLogger({required this.talker}) : super();
7 | final Talker talker;
8 |
9 | @override
10 | void didUpdateProvider(
11 | ProviderBase