├── .github └── FUNDING.yml ├── .gitignore ├── .pubignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_CN.md ├── analysis_options.yaml ├── example ├── .gitignore ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── codiss │ │ │ │ │ └── easy │ │ │ │ │ └── refresh │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── image │ │ ├── cryptocurrency │ │ │ ├── bitcoin.svg │ │ │ ├── bnb.svg │ │ │ ├── dogecoin.svg │ │ │ ├── ethereum.svg │ │ │ ├── matic.svg │ │ │ ├── more.svg │ │ │ ├── trx.svg │ │ │ ├── usdc.svg │ │ │ └── usdt.svg │ │ ├── pay_alipay.jpg │ │ ├── pay_wechat.jpg │ │ └── user_head.jpg │ └── rive │ │ └── raster_graphics.riv ├── example.md ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── 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 │ │ └── zh-Hans.lproj │ │ ├── LaunchScreen.strings │ │ └── Main.strings ├── lib │ ├── config │ │ └── routes.dart │ ├── example.dart │ ├── l10n │ │ ├── translations.dart │ │ └── translations │ │ │ ├── en.dart │ │ │ └── zh_cn.dart │ ├── main.dart │ ├── page │ │ ├── home.dart │ │ ├── more │ │ │ ├── cryptocurrency_page.dart │ │ │ ├── more_page.dart │ │ │ ├── support_me_page.dart │ │ │ └── theme_page.dart │ │ ├── sample │ │ │ ├── carousel_page.dart │ │ │ ├── chat_page.dart │ │ │ ├── listener_header_page.dart │ │ │ ├── nested_scroll_view.dart │ │ │ ├── page_view_page.dart │ │ │ ├── paging_page.dart │ │ │ ├── refresh_on_start_page.dart │ │ │ ├── sample_page.dart │ │ │ ├── secondary_page.dart │ │ │ ├── tab_bar_view_page.dart │ │ │ ├── test_page.dart │ │ │ ├── theme_switch_page.dart │ │ │ └── user_profile_page.dart │ │ └── style │ │ │ ├── bezier_circle_page.dart │ │ │ ├── bezier_page.dart │ │ │ ├── bubbles_page.dart │ │ │ ├── classical_page.dart │ │ │ ├── cupertino_page.dart │ │ │ ├── delivery_page.dart │ │ │ ├── halloween_page.dart │ │ │ ├── material_page.dart │ │ │ ├── phoenix_page.dart │ │ │ ├── skating_page.dart │ │ │ ├── space_page.dart │ │ │ ├── squats_page.dart │ │ │ ├── style_page.dart │ │ │ └── taurus_page.dart │ ├── util │ │ └── color_utils.dart │ └── widget │ │ ├── icon │ │ └── path_icons.dart │ │ ├── list_item.dart │ │ ├── menu_bottom_bar.dart │ │ ├── paths_painter.dart │ │ └── skeleton_item.dart ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Podfile │ ├── 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 │ │ ├── zh-HK.lproj │ │ └── MainMenu.strings │ │ ├── zh-Hans.lproj │ │ └── MainMenu.strings │ │ └── zh-Hant.lproj │ │ └── MainMenu.strings ├── pubspec.yaml ├── res │ └── values │ │ ├── strings_en.arb │ │ └── strings_zh_CN.arb ├── test │ └── widget_test.dart ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ ├── Icon-512.png │ │ ├── Icon-maskable-192.png │ │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json └── windows │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake │ └── runner │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── resources │ └── app_icon.ico │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── lib ├── easy_paging.dart ├── easy_refresh.dart └── src │ ├── behavior │ └── scroll_behavior.dart │ ├── controller │ └── controller.dart │ ├── easy_paging.dart │ ├── easy_refresh.dart │ ├── indicator │ ├── footer │ │ ├── footer.dart │ │ └── footer_locator.dart │ ├── header │ │ ├── header.dart │ │ └── header_locator.dart │ └── indicator.dart │ ├── notifier │ └── indicator_notifier.dart │ ├── painter │ └── paths_painter.dart │ ├── physics │ └── scroll_physics.dart │ └── styles │ ├── bezier │ ├── bezier_background.dart │ ├── bezier_circle_indicator.dart │ ├── bezier_indicator.dart │ ├── footer │ │ └── bezier_footer.dart │ ├── header │ │ ├── bezier_circle_header.dart │ │ └── bezier_header.dart │ └── spin │ │ └── hour_glass.dart │ ├── classic │ ├── classic_indicator.dart │ ├── footer │ │ └── classic_footer.dart │ └── header │ │ └── classic_header.dart │ ├── cupertino │ ├── cupertino_activity_indicator.dart │ ├── cupertino_indicator.dart │ ├── footer │ │ └── cupertino_footer.dart │ └── header │ │ └── cupertino_header.dart │ ├── delivery │ ├── delivery_indicator.dart │ ├── footer │ │ └── delivery_footer.dart │ └── header │ │ └── delivery_header.dart │ ├── material │ ├── footer │ │ └── material_footer.dart │ ├── header │ │ └── material_header.dart │ └── material_indicator.dart │ ├── phoenix │ ├── footer │ │ └── phoenix_footer.dart │ ├── header │ │ └── phoenix_header.dart │ └── phoenix_indicator.dart │ └── taurus │ ├── footer │ └── taurus_footer.dart │ ├── header │ └── taurus_header.dart │ └── taurus_indicator.dart ├── pubspec.yaml ├── styles ├── easy_refresh_bubbles │ ├── .flutter-plugins │ ├── .flutter-plugins-dependencies │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ │ └── bubbles.riv │ ├── example │ │ └── main.dart │ ├── lib │ │ ├── easy_refresh_bubbles.dart │ │ └── src │ │ │ ├── bubbles_footer.dart │ │ │ ├── bubbles_header.dart │ │ │ └── bubbles_indicator.dart │ └── pubspec.yaml ├── easy_refresh_halloween │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ │ └── halloween.riv │ ├── example │ │ └── main.dart │ ├── lib │ │ ├── easy_refresh_halloween.dart │ │ └── src │ │ │ ├── halloween_footer.dart │ │ │ ├── halloween_header.dart │ │ │ └── halloween_indicator.dart │ └── pubspec.yaml ├── easy_refresh_skating │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ │ └── skating.riv │ ├── example │ │ └── main.dart │ ├── lib │ │ ├── easy_refresh_skating.dart │ │ └── src │ │ │ ├── skating_footer.dart │ │ │ ├── skating_header.dart │ │ │ └── skating_indicator.dart │ └── pubspec.yaml ├── easy_refresh_space │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ │ └── space_reload.riv │ ├── example │ │ └── main.dart │ ├── lib │ │ ├── easy_refresh_space.dart │ │ └── src │ │ │ ├── space_footer.dart │ │ │ ├── space_header.dart │ │ │ └── space_indicator.dart │ └── pubspec.yaml └── easy_refresh_squats │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ └── lumberjack_squats.riv │ ├── example │ └── main.dart │ ├── lib │ ├── easy_refresh_squats.dart │ └── src │ │ ├── squats_footer.dart │ │ ├── squats_header.dart │ │ └── squats_indicator.dart │ └── pubspec.yaml └── test └── widget_test.dart /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: https://xuelongqy.github.io/flutter_easy_refresh/#/support-me 4 | ko_fi: xuelongqy 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | .vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /.pubignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | .vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | 32 | # styles 33 | /styles -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 xuelongqy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.cn/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.cn/guides/language/analysis-options -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | .vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | /pubspec.lock 26 | **/doc/api/ 27 | **/ios/Flutter/.last_build_id 28 | .dart_tool/ 29 | .flutter-plugins 30 | .flutter-plugins-dependencies 31 | .packages 32 | .pub-cache/ 33 | .pub/ 34 | /build/ 35 | 36 | # Web related 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | 44 | # Android Studio will place build artifacts here 45 | /android/app/debug 46 | /android/app/profile 47 | /android/app/release 48 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | EasyRefresh example. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.cn/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.cn/guides/language/analysis-options -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "com.codiss.easy.refresh.example" 27 | compileSdk flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "com.codiss.easy.refresh.example" 46 | // You can update the following values to match your application needs. 47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 48 | minSdkVersion flutter.minSdkVersion 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | 53 | // ndk { 54 | // abiFilters 'arm64-v8a' 55 | // } 56 | } 57 | 58 | buildTypes { 59 | release { 60 | // TODO: Add your own signing config for the release build. 61 | // Signing with the debug keys for now, so `flutter run --release` works. 62 | signingConfig signingConfigs.debug 63 | } 64 | } 65 | } 66 | 67 | flutter { 68 | source '../..' 69 | } 70 | 71 | dependencies { 72 | // Alipay 73 | implementation 'moe.feng:AlipayZeroSdk:1.1' 74 | } 75 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/codiss/easy/refresh/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.codiss.easy.refresh.example 2 | 3 | import android.os.Build 4 | import android.os.Bundle 5 | import android.view.WindowManager 6 | import io.flutter.embedding.android.FlutterActivity 7 | import io.flutter.embedding.engine.FlutterEngine 8 | import io.flutter.embedding.engine.plugins.FlutterPlugin 9 | import io.flutter.plugins.GeneratedPluginRegistrant 10 | import io.flutter.plugin.common.MethodChannel 11 | import moe.feng.alipay.zerosdk.AlipayZeroSdk 12 | 13 | class MainActivity: FlutterActivity() { 14 | // 伴生对象 15 | companion object { 16 | // 交互通道名字 17 | const val CHANNEL = "com.codiss.easy.refresh.example/channel" 18 | // 支付宝捐赠 19 | const val ALIPAY_DONATION = "aliPayDonation" 20 | } 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | // 取消全屏 24 | window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) 25 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 26 | //API>21,设置状态栏颜色透明 27 | window.statusBarColor = 0 28 | } 29 | } 30 | 31 | // 配置Flutter引擎 32 | override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 33 | super.configureFlutterEngine(flutterEngine) 34 | // 注册插件 35 | GeneratedPluginRegistrant.registerWith(flutterEngine) 36 | flutterEngine.plugins.add(object : FlutterPlugin { 37 | override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { 38 | // 注册通道 39 | MethodChannel(binding.binaryMessenger, CHANNEL).setMethodCallHandler { methodCall, _ -> 40 | // 判断交互方法 41 | when (methodCall.method) { 42 | ALIPAY_DONATION -> AlipayZeroSdk.startAlipayClient(this@MainActivity, "FKX03889Z997BS1BNALOC9") 43 | } 44 | } 45 | } 46 | 47 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {} 48 | }) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | maven { url 'https://maven.aliyun.com/repository/google' } 4 | maven { url 'https://maven.aliyun.com/repository/public' } 5 | maven { url 'https://maven.aliyun.com/repository/central' } 6 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } 7 | google() 8 | jcenter() 9 | maven { url 'https://jitpack.io' } 10 | mavenCentral() 11 | gradlePluginPortal() 12 | } 13 | } 14 | 15 | rootProject.buildDir = '../build' 16 | subprojects { 17 | project.buildDir = "${rootProject.buildDir}/${project.name}" 18 | } 19 | subprojects { 20 | project.evaluationDependsOn(':app') 21 | } 22 | 23 | tasks.register("clean", Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | #systemProp.http.proxyHost=127.0.0.1 5 | #systemProp.http.proxyPort=7890 6 | #systemProp.https.proxyHost=127.0.0.1 7 | #systemProp.https.proxyPort=7890 8 | #systemProp.socksProxyHost=127.0.0.1 9 | #systemProp.socksProxyPort=7890 -------------------------------------------------------------------------------- /example/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-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | maven { url 'https://maven.aliyun.com/repository/google' } 15 | maven { url 'https://maven.aliyun.com/repository/public' } 16 | maven { url 'https://maven.aliyun.com/repository/central' } 17 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } 18 | google() 19 | jcenter() 20 | maven { url 'https://jitpack.io' } 21 | mavenCentral() 22 | gradlePluginPortal() 23 | } 24 | } 25 | 26 | plugins { 27 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 28 | id "com.android.application" version "7.3.0" apply false 29 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 30 | } 31 | 32 | include ":app" 33 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/bitcoin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/bnb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/dogecoin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/ethereum.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/matic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/more.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/trx.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/usdc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example/assets/image/cryptocurrency/usdt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/assets/image/pay_alipay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/assets/image/pay_alipay.jpg -------------------------------------------------------------------------------- /example/assets/image/pay_wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/assets/image/pay_wechat.jpg -------------------------------------------------------------------------------- /example/assets/image/user_head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/assets/image/user_head.jpg -------------------------------------------------------------------------------- /example/assets/rive/raster_graphics.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/assets/rive/raster_graphics.riv -------------------------------------------------------------------------------- /example/example.md: -------------------------------------------------------------------------------- 1 | ```dart 2 | import 'package:flutter/material.dart'; 3 | import 'package:easy_refresh/easy_refresh.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const MaterialApp( 13 | title: 'EasyRefresh', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | const HomePage({Key? key}) : super(key: key); 21 | 22 | @override 23 | State createState() => _HomePageState(); 24 | } 25 | 26 | class _HomePageState extends State { 27 | int _count = 10; 28 | late EasyRefreshController _controller; 29 | 30 | @override 31 | void initState() { 32 | super.initState(); 33 | _controller = EasyRefreshController( 34 | controlFinishRefresh: true, 35 | controlFinishLoad: true, 36 | ); 37 | } 38 | 39 | @override 40 | void dispose() { 41 | _controller.dispose(); 42 | super.dispose(); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return Scaffold( 48 | appBar: AppBar( 49 | title: const Text('EasyRefresh'), 50 | ), 51 | body: EasyRefresh( 52 | controller: _controller, 53 | header: const ClassicHeader(), 54 | footer: const ClassicFooter(), 55 | onRefresh: () async { 56 | await Future.delayed(const Duration(seconds: 4)); 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _count = 10; 62 | }); 63 | _controller.finishRefresh(); 64 | _controller.resetFooter(); 65 | }, 66 | onLoad: () async { 67 | await Future.delayed(const Duration(seconds: 4)); 68 | if (!mounted) { 69 | return; 70 | } 71 | setState(() { 72 | _count += 5; 73 | }); 74 | _controller.finishLoad( 75 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 76 | }, 77 | child: ListView.builder( 78 | itemBuilder: (context, index) { 79 | return Card( 80 | child: Container( 81 | alignment: Alignment.center, 82 | height: 80, 83 | child: Text('${index + 1}'), 84 | ), 85 | ); 86 | }, 87 | itemCount: _count, 88 | ), 89 | ), 90 | ); 91 | } 92 | } 93 | ``` 94 | 95 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/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 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/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. -------------------------------------------------------------------------------- /example/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 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | zh_CN 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleLocalizations 16 | 17 | en 18 | zh_CN 19 | 20 | CFBundleName 21 | EasyRefresh 22 | CFBundlePackageType 23 | APPL 24 | CFBundleShortVersionString 25 | $(FLUTTER_BUILD_NAME) 26 | CFBundleSignature 27 | ???? 28 | CFBundleVersion 29 | $(FLUTTER_BUILD_NUMBER) 30 | LSRequiresIPhoneOS 31 | 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIViewControllerBasedStatusBarAppearance 50 | 51 | UIApplicationSupportsIndirectInputEvents 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /example/ios/Runner/zh-Hans.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/ios/Runner/zh-Hans.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/lib/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:easy_refresh/easy_refresh.dart'; 3 | 4 | void main() => runApp(const MyApp()); 5 | 6 | class MyApp extends StatelessWidget { 7 | const MyApp({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return const MaterialApp( 12 | title: 'EasyRefresh', 13 | home: HomePage(), 14 | ); 15 | } 16 | } 17 | 18 | class HomePage extends StatefulWidget { 19 | const HomePage({super.key}); 20 | 21 | @override 22 | State createState() => _HomePageState(); 23 | } 24 | 25 | class _HomePageState extends State { 26 | int _count = 10; 27 | late EasyRefreshController _controller; 28 | 29 | @override 30 | void initState() { 31 | super.initState(); 32 | _controller = EasyRefreshController( 33 | controlFinishRefresh: true, 34 | controlFinishLoad: true, 35 | ); 36 | } 37 | 38 | @override 39 | void dispose() { 40 | _controller.dispose(); 41 | super.dispose(); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Scaffold( 47 | appBar: AppBar( 48 | title: const Text('EasyRefresh'), 49 | ), 50 | body: EasyRefresh( 51 | controller: _controller, 52 | header: const ClassicHeader(), 53 | footer: const ClassicFooter(), 54 | onRefresh: () async { 55 | await Future.delayed(const Duration(seconds: 4)); 56 | if (!mounted) { 57 | return; 58 | } 59 | setState(() { 60 | _count = 10; 61 | }); 62 | _controller.finishRefresh(); 63 | _controller.resetFooter(); 64 | }, 65 | onLoad: () async { 66 | await Future.delayed(const Duration(seconds: 4)); 67 | if (!mounted) { 68 | return; 69 | } 70 | setState(() { 71 | _count += 5; 72 | }); 73 | _controller.finishLoad( 74 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 75 | }, 76 | child: ListView.builder( 77 | itemBuilder: (context, index) { 78 | return Card( 79 | child: Container( 80 | alignment: Alignment.center, 81 | height: 80, 82 | child: Text('${index + 1}'), 83 | ), 84 | ); 85 | }, 86 | itemCount: _count, 87 | ), 88 | ), 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /example/lib/l10n/translations.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/l10n/translations/en.dart'; 2 | import 'package:example/l10n/translations/zh_cn.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:get/get.dart'; 5 | 6 | class AppTranslations extends Translations { 7 | @override 8 | Map> get keys => { 9 | 'en': en, 10 | 'zh_CN': zhCN, 11 | }; 12 | 13 | static const List supportedLocales = [ 14 | Locale('en'), 15 | Locale('zh', 'CN'), 16 | ]; 17 | 18 | static const fallbackLocale = Locale('en'); 19 | } 20 | -------------------------------------------------------------------------------- /example/lib/l10n/translations/zh_cn.dart: -------------------------------------------------------------------------------- 1 | const zhCN = { 2 | 'Sample': '示例', 3 | 'Style': '样式', 4 | 'More': '更多', 5 | 'Theme': '主题', 6 | 'System': '系统', 7 | 'Light': '明亮', 8 | 'Dark': '暗黑', 9 | 'Classic': '经典', 10 | 'Classic and default': '经典和默认', 11 | 'Direction': '方向', 12 | 'Vertical': '垂直', 13 | 'Horizontal': '水平', 14 | 'Clamping': '固定', 15 | 'Background': '背景', 16 | 'Alignment': '对齐', 17 | 'Center': '中心', 18 | 'Start': '开端', 19 | 'End': '结尾', 20 | 'Infinite': '无限', 21 | 'Message': '信息', 22 | 'Text': '文本', 23 | 'Animation': '动画', 24 | 'Bounce': '回弹', 25 | 'List Spring': '列表弹簧', 26 | 'Pull to refresh': '下拉刷新', 27 | 'Release ready': '释放开始', 28 | 'Refreshing...': '刷新中...', 29 | 'Succeeded': '成功了', 30 | 'No more': '没有更多', 31 | 'Failed': '失败了', 32 | 'Last updated at %T': '最后更新于 %T', 33 | 'Pull to load': '上拉加载', 34 | 'Loading...': '加载中...', 35 | 'Bezier curve': '贝塞尔曲线', 36 | 'Disable': '禁用', 37 | 'Display balls': '显示小球', 38 | 'Spin in center': 'Spin居中', 39 | 'Only show spin': '只显示Spin', 40 | 'Bezier circle': '弹出圆圈', 41 | 'Golden campus': '金色校园', 42 | 'Rush to the sky': '冲上云霄', 43 | 'Balloon delivery': '气球快递', 44 | 'Star track': '太空轨道', 45 | 'Lumberjack Squats': '暴力深蹲', 46 | 'Skating boy': '滑雪少年', 47 | 'Halloween horror': '万圣节惊魂', 48 | 'User profile': '个人中心', 49 | 'User personal center': '用户个人中心', 50 | 'QQ group': 'QQ群', 51 | 'Name': '名字', 52 | 'Age': '年龄', 53 | 'Not yet bald': '尚未秃顶', 54 | 'City': '城市', 55 | 'China - ChengDu': '中国 - 成都', 56 | 'Phone': '电话', 57 | 'Mail': '邮箱', 58 | 'NestedScrollView example': 'NestedScrollView示例', 59 | 'Carousel': '轮播', 60 | 'Carousel example': '轮播示例', 61 | 'Refresh on start': '启动时刷新', 62 | 'Refresh when the list is displayed and specify the Header': 63 | '列表显示时刷新并指定Header', 64 | 'Listener': '监听器', 65 | 'Use listener to respond anywhere': '使用监听器,在任意位置响应', 66 | 'Secondary': '二楼', 67 | 'Combine existing Header with secondary': '将已有的Header结合二楼', 68 | 'Open the second floor': '打开二楼', 69 | 'Chat': '聊天', 70 | 'Chat page example': '聊天页面示例', 71 | 'PageView example': 'PageView 示例', 72 | 'Join discussion': '加入讨论', 73 | 'Join the QQ group (554981921)': '加入QQ群(554981921)', 74 | 'Repository': '项目地址', 75 | 'Support me': '支持作者', 76 | 'Buy me a coffee ~': '请作者喝一杯咖啡~', 77 | 'Alipay': '支付宝', 78 | 'Alipay donation': '支付宝捐赠', 79 | 'Wechat': '微信', 80 | 'Wechat donation': '微信捐赠', 81 | 'Cryptocurrency': '加密货币', 82 | 'Cryptocurrency donation': '加密货币捐赠', 83 | 'Bitcoin donation': '比特币捐赠', 84 | 'Ethereum series, ETH, BNB, MATIC, USDT and other tokens': 85 | '以太坊系列,ETH、BNB、MATIC、USDT及其他代币', 86 | 'Tron chain, TRX, USDT, USDC and other tokens': '波场链,TRX、USDT、USDC及其他代币', 87 | 'Dogecoin donation': '狗狗币捐赠', 88 | '%s copied!': '%s 已复制!', 89 | 'Trigger immediately': '立即触发', 90 | 'TabBarView example': 'NestedScrollView + TabBarView示例', 91 | 'Paging': '分页', 92 | 'Paging example': '分页示例', 93 | 'No Data': '暂无数据', 94 | 'Theme switch': '主题切换', 95 | 'Theme switch example': '主题切换示例', 96 | 'Theme switch describe': '下拉显示切换面板,左右滑动选中主题色,释放进行切换。', 97 | 'Bubbles launch': '泡泡发射', 98 | }; 99 | -------------------------------------------------------------------------------- /example/lib/page/home.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/page/more/more_page.dart'; 2 | import 'package:example/page/sample/sample_page.dart'; 3 | import 'package:example/page/style/style_page.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | /// 主页面 8 | class HomePage extends StatefulWidget { 9 | const HomePage({super.key}); 10 | 11 | @override 12 | HomePageState createState() => HomePageState(); 13 | } 14 | 15 | class HomePageState extends State { 16 | // Page Controller. 17 | late PageController _pageController; 18 | // Current page. 19 | int _pageIndex = 0; 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | _pageController = PageController(); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _pageController.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | // Change page. 34 | void _onBottomNavigationBarTap(int index) { 35 | _pageController.animateToPage( 36 | index, 37 | duration: const Duration(milliseconds: 200), 38 | curve: Curves.linear, 39 | ); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return Scaffold( 45 | body: PageView( 46 | controller: _pageController, 47 | children: const [SamplePage(), StylePage(), MorePage()], 48 | onPageChanged: (index) { 49 | setState(() { 50 | _pageIndex = index; 51 | }); 52 | }, 53 | ), 54 | bottomNavigationBar: BottomNavigationBar( 55 | currentIndex: _pageIndex, 56 | type: BottomNavigationBarType.fixed, 57 | onTap: _onBottomNavigationBarTap, 58 | items: [ 59 | BottomNavigationBarItem( 60 | icon: const Icon(Icons.dashboard), 61 | label: 'Sample'.tr, 62 | ), 63 | BottomNavigationBarItem( 64 | icon: const Icon(Icons.style), 65 | label: 'Style'.tr, 66 | ), 67 | BottomNavigationBarItem( 68 | icon: const Icon(Icons.more_vert), 69 | label: 'More'.tr, 70 | ), 71 | ], 72 | ), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /example/lib/page/more/more_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/config/routes.dart'; 2 | import 'package:example/page/more/theme_page.dart'; 3 | import 'package:example/widget/list_item.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:get/get.dart'; 6 | import 'package:url_launcher/url_launcher.dart'; 7 | 8 | class MorePage extends StatefulWidget { 9 | const MorePage({super.key}); 10 | 11 | @override 12 | State createState() => _MorePageState(); 13 | } 14 | 15 | class _MorePageState extends State { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | body: CustomScrollView( 20 | slivers: [ 21 | SliverAppBar( 22 | expandedHeight: 120, 23 | pinned: true, 24 | flexibleSpace: FlexibleSpaceBar( 25 | title: Text( 26 | 'More'.tr, 27 | style: TextStyle( 28 | color: Theme.of(context).textTheme.titleLarge?.color), 29 | ), 30 | centerTitle: false, 31 | ), 32 | ), 33 | SliverList( 34 | delegate: SliverChildListDelegate([ 35 | Obx(() { 36 | return ListItem( 37 | title: 'Theme'.tr, 38 | subtitle: ThemeController.i.theme.value.tr, 39 | icon: Icons.palette, 40 | onTap: () => Get.toNamed(Routes.theme), 41 | ); 42 | }), 43 | ListItem( 44 | title: 'Join discussion'.tr, 45 | subtitle: 'Join the QQ group (554981921)'.tr, 46 | icon: Icons.group, 47 | onTap: () { 48 | launchUrl( 49 | Uri.parse( 50 | 'mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3DMNLtkvnn4n28UIB0gEgm2-WBmqmGWk0Q'), 51 | ); 52 | }, 53 | ), 54 | ListItem( 55 | title: 'Repository'.tr, 56 | subtitle: 'https://github.com/xuelongqy/flutter_easy_refresh', 57 | icon: Icons.http, 58 | onTap: () { 59 | launchUrl( 60 | Uri.parse( 61 | 'https://github.com/xuelongqy/flutter_easy_refresh'), 62 | ); 63 | }, 64 | ), 65 | ListItem( 66 | title: 'Support me'.tr, 67 | subtitle: 'Buy me a coffee ~'.tr, 68 | icon: Icons.coffee, 69 | onTap: () => Get.toNamed(Routes.supportMe), 70 | ), 71 | ]), 72 | ), 73 | ], 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /example/lib/page/style/bezier_circle_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/config/routes.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class BezierCirclePage extends StatefulWidget { 8 | const BezierCirclePage({super.key}); 9 | 10 | @override 11 | State createState() => _BezierCirclePageState(); 12 | } 13 | 14 | class _BezierCirclePageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | final themeData = Theme.of(context); 36 | return Scaffold( 37 | appBar: AppBar( 38 | backgroundColor: themeData.colorScheme.primary, 39 | foregroundColor: themeData.colorScheme.onPrimary, 40 | leading: BackButton( 41 | color: themeData.colorScheme.onPrimary, 42 | ), 43 | title: Text('Bezier circle'.tr), 44 | ), 45 | body: EasyRefresh( 46 | controller: _controller, 47 | header: BezierCircleHeader( 48 | foregroundColor: themeData.scaffoldBackgroundColor, 49 | backgroundColor: themeData.colorScheme.primary, 50 | ), 51 | onRefresh: () async { 52 | await Future.delayed(const Duration(seconds: 2)); 53 | if (!mounted) { 54 | return; 55 | } 56 | setState(() { 57 | _count = 10; 58 | }); 59 | _controller.finishRefresh(); 60 | _controller.resetFooter(); 61 | }, 62 | onLoad: () async { 63 | await Future.delayed(const Duration(seconds: 2)); 64 | if (!mounted) { 65 | return; 66 | } 67 | setState(() { 68 | _count += 5; 69 | }); 70 | _controller.finishLoad( 71 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 72 | }, 73 | child: ListView.builder( 74 | clipBehavior: Clip.none, 75 | padding: EdgeInsets.zero, 76 | itemCount: _count, 77 | itemBuilder: (ctx, index) { 78 | return const SkeletonItem(); 79 | }, 80 | ), 81 | ), 82 | floatingActionButton: FloatingActionButton.extended( 83 | label: Text('Theme'.tr), 84 | icon: const Icon(Icons.color_lens), 85 | onPressed: () => Get.toNamed(Routes.theme), 86 | ), 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/lib/page/style/bubbles_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_bubbles/easy_refresh_bubbles.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class BubblesPage extends StatefulWidget { 8 | const BubblesPage({super.key}); 9 | 10 | @override 11 | State createState() => _BubblesPageState(); 12 | } 13 | 14 | class _BubblesPageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: EasyRefresh( 37 | controller: _controller, 38 | header: const BubblesHeader( 39 | position: IndicatorPosition.locator, 40 | ), 41 | footer: const BubblesFooter( 42 | position: IndicatorPosition.locator, 43 | ), 44 | onRefresh: () async { 45 | await Future.delayed(const Duration(seconds: 4)); 46 | if (!mounted) { 47 | return; 48 | } 49 | setState(() { 50 | _count = 10; 51 | }); 52 | _controller.finishRefresh(); 53 | _controller.resetFooter(); 54 | }, 55 | onLoad: () async { 56 | await Future.delayed(const Duration(seconds: 4)); 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _count += 5; 62 | }); 63 | _controller.finishLoad( 64 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 65 | }, 66 | child: CustomScrollView( 67 | slivers: [ 68 | SliverAppBar( 69 | title: Text('Bubbles launch'.tr), 70 | pinned: true, 71 | ), 72 | const HeaderLocator.sliver(), 73 | SliverList( 74 | delegate: SliverChildBuilderDelegate( 75 | (context, index) { 76 | return const SkeletonItem(); 77 | }, 78 | childCount: _count, 79 | ), 80 | ), 81 | const FooterLocator.sliver(), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/lib/page/style/delivery_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/config/routes.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class DeliveryPage extends StatefulWidget { 8 | const DeliveryPage({super.key}); 9 | 10 | @override 11 | State createState() => _DeliveryPageState(); 12 | } 13 | 14 | class _DeliveryPageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | final themeData = Theme.of(context); 36 | return Scaffold( 37 | body: EasyRefresh( 38 | controller: _controller, 39 | header: const DeliveryHeader( 40 | position: IndicatorPosition.locator, 41 | ), 42 | footer: const DeliveryFooter( 43 | position: IndicatorPosition.locator, 44 | ), 45 | onRefresh: () async { 46 | await Future.delayed(const Duration(seconds: 4)); 47 | if (!mounted) { 48 | return; 49 | } 50 | setState(() { 51 | _count = 10; 52 | }); 53 | _controller.finishRefresh(); 54 | _controller.resetFooter(); 55 | }, 56 | onLoad: () async { 57 | await Future.delayed(const Duration(seconds: 4)); 58 | if (!mounted) { 59 | return; 60 | } 61 | setState(() { 62 | _count += 5; 63 | }); 64 | _controller.finishLoad( 65 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 66 | }, 67 | child: CustomScrollView( 68 | slivers: [ 69 | SliverAppBar( 70 | backgroundColor: themeData.scaffoldBackgroundColor, 71 | title: Text('Balloon delivery'.tr), 72 | pinned: true, 73 | ), 74 | const HeaderLocator.sliver(), 75 | SliverList( 76 | delegate: SliverChildBuilderDelegate( 77 | (context, index) { 78 | return const SkeletonItem(); 79 | }, 80 | childCount: _count, 81 | ), 82 | ), 83 | const FooterLocator.sliver(), 84 | ], 85 | ), 86 | ), 87 | floatingActionButton: FloatingActionButton.extended( 88 | label: Text('Theme'.tr), 89 | icon: const Icon(Icons.color_lens), 90 | onPressed: () => Get.toNamed(Routes.theme), 91 | ), 92 | ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /example/lib/page/style/halloween_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_halloween/easy_refresh_halloween.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class HalloweenPage extends StatefulWidget { 8 | const HalloweenPage({super.key}); 9 | 10 | @override 11 | State createState() => _HalloweenPageState(); 12 | } 13 | 14 | class _HalloweenPageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: EasyRefresh( 37 | controller: _controller, 38 | header: const HalloweenHeader( 39 | position: IndicatorPosition.locator, 40 | ), 41 | footer: const HalloweenFooter( 42 | position: IndicatorPosition.locator, 43 | ), 44 | onRefresh: () async { 45 | await Future.delayed(const Duration(seconds: 4)); 46 | if (!mounted) { 47 | return; 48 | } 49 | setState(() { 50 | _count = 10; 51 | }); 52 | _controller.finishRefresh(); 53 | _controller.resetFooter(); 54 | }, 55 | onLoad: () async { 56 | await Future.delayed(const Duration(seconds: 4)); 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _count += 5; 62 | }); 63 | _controller.finishLoad( 64 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 65 | }, 66 | child: CustomScrollView( 67 | slivers: [ 68 | SliverAppBar( 69 | title: Text('Halloween horror'.tr), 70 | pinned: true, 71 | ), 72 | const HeaderLocator.sliver(), 73 | SliverList( 74 | delegate: SliverChildBuilderDelegate( 75 | (context, index) { 76 | return const SkeletonItem(); 77 | }, 78 | childCount: _count, 79 | ), 80 | ), 81 | const FooterLocator.sliver(), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/lib/page/style/skating_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_skating/easy_refresh_skating.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class SkatingPage extends StatefulWidget { 8 | const SkatingPage({super.key}); 9 | 10 | @override 11 | State createState() => _SkatingPageState(); 12 | } 13 | 14 | class _SkatingPageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: EasyRefresh( 37 | controller: _controller, 38 | header: const SkatingHeader( 39 | position: IndicatorPosition.locator, 40 | ), 41 | footer: const SkatingFooter( 42 | position: IndicatorPosition.locator, 43 | ), 44 | onRefresh: () async { 45 | await Future.delayed(const Duration(seconds: 4)); 46 | if (!mounted) { 47 | return; 48 | } 49 | setState(() { 50 | _count = 10; 51 | }); 52 | _controller.finishRefresh(); 53 | _controller.resetFooter(); 54 | }, 55 | onLoad: () async { 56 | await Future.delayed(const Duration(seconds: 4)); 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _count += 5; 62 | }); 63 | _controller.finishLoad( 64 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 65 | }, 66 | child: CustomScrollView( 67 | slivers: [ 68 | SliverAppBar( 69 | title: Text('Skating boy'.tr), 70 | pinned: true, 71 | ), 72 | const HeaderLocator.sliver(), 73 | SliverList( 74 | delegate: SliverChildBuilderDelegate( 75 | (context, index) { 76 | return const SkeletonItem(); 77 | }, 78 | childCount: _count, 79 | ), 80 | ), 81 | const FooterLocator.sliver(), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/lib/page/style/space_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_space/easy_refresh_space.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class SpacePage extends StatefulWidget { 8 | const SpacePage({super.key}); 9 | 10 | @override 11 | State createState() => _SpacePageState(); 12 | } 13 | 14 | class _SpacePageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: EasyRefresh( 37 | controller: _controller, 38 | header: const SpaceHeader( 39 | position: IndicatorPosition.locator, 40 | ), 41 | footer: const SpaceFooter( 42 | position: IndicatorPosition.locator, 43 | ), 44 | onRefresh: () async { 45 | await Future.delayed(const Duration(seconds: 4)); 46 | if (!mounted) { 47 | return; 48 | } 49 | setState(() { 50 | _count = 10; 51 | }); 52 | _controller.finishRefresh(); 53 | _controller.resetFooter(); 54 | }, 55 | onLoad: () async { 56 | await Future.delayed(const Duration(seconds: 4)); 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _count += 5; 62 | }); 63 | _controller.finishLoad( 64 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 65 | }, 66 | child: CustomScrollView( 67 | slivers: [ 68 | SliverAppBar( 69 | title: Text('Star track'.tr), 70 | pinned: true, 71 | ), 72 | const HeaderLocator.sliver(), 73 | SliverList( 74 | delegate: SliverChildBuilderDelegate( 75 | (context, index) { 76 | return const SkeletonItem(); 77 | }, 78 | childCount: _count, 79 | ), 80 | ), 81 | const FooterLocator.sliver(), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/lib/page/style/squats_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_squats/easy_refresh_squats.dart'; 2 | import 'package:example/widget/skeleton_item.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:easy_refresh/easy_refresh.dart'; 5 | import 'package:get/get.dart'; 6 | 7 | class SquatsPage extends StatefulWidget { 8 | const SquatsPage({super.key}); 9 | 10 | @override 11 | State createState() => _SquatsPageState(); 12 | } 13 | 14 | class _SquatsPageState extends State { 15 | int _count = 10; 16 | late EasyRefreshController _controller; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _controller = EasyRefreshController( 22 | controlFinishRefresh: true, 23 | controlFinishLoad: true, 24 | ); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | _controller.dispose(); 30 | super.dispose(); 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return Scaffold( 36 | body: EasyRefresh( 37 | controller: _controller, 38 | header: const SquatsHeader( 39 | position: IndicatorPosition.locator, 40 | ), 41 | footer: const SquatsFooter( 42 | position: IndicatorPosition.locator, 43 | ), 44 | onRefresh: () async { 45 | await Future.delayed(const Duration(seconds: 4)); 46 | if (!mounted) { 47 | return; 48 | } 49 | setState(() { 50 | _count = 10; 51 | }); 52 | _controller.finishRefresh(); 53 | _controller.resetFooter(); 54 | }, 55 | onLoad: () async { 56 | await Future.delayed(const Duration(seconds: 4)); 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _count += 5; 62 | }); 63 | _controller.finishLoad( 64 | _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); 65 | }, 66 | child: CustomScrollView( 67 | slivers: [ 68 | SliverAppBar( 69 | title: Text('Lumberjack Squats'.tr), 70 | pinned: true, 71 | ), 72 | const HeaderLocator.sliver(), 73 | SliverList( 74 | delegate: SliverChildBuilderDelegate( 75 | (context, index) { 76 | return const SkeletonItem(); 77 | }, 78 | childCount: _count, 79 | ), 80 | ), 81 | const FooterLocator.sliver(), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/lib/util/color_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:convert/convert.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ColorUtils { 5 | /// Generate background color from string. 6 | static Color backgroundColorWithString(String value) { 7 | final strHex = 8 | hex.encode('${value}color'.codeUnits.map((e) => e % 256).toList()); 9 | String colorStr = ''; 10 | const hexLength = 6; 11 | final spacing = strHex.length ~/ hexLength; 12 | for (int i = 0; i < hexLength; i++) { 13 | colorStr += String.fromCharCode(strHex.codeUnitAt(i * spacing + 1)); 14 | } 15 | return Color(int.parse('ff$colorStr', radix: 16)); 16 | } 17 | 18 | /// Generate foreground color from string. 19 | static Color foregroundColorWithString(String value) { 20 | final bgColor = backgroundColorWithString(value); 21 | return bgColor.red * 0.299 + bgColor.green * 0.587 + bgColor.blue * 0.114 > 22 | 186 23 | ? Colors.black 24 | : Colors.white; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/lib/widget/list_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/util/color_utils.dart'; 2 | import 'package:example/widget/paths_painter.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// List item. 6 | class ListItem extends StatelessWidget { 7 | const ListItem({ 8 | super.key, 9 | required this.title, 10 | this.subtitle, 11 | this.leading, 12 | this.icon, 13 | this.iconPaths, 14 | this.trailing, 15 | this.onTap, 16 | this.selected = false, 17 | this.divider = false, 18 | }); 19 | 20 | final String title; 21 | 22 | final String? subtitle; 23 | 24 | final Widget? leading; 25 | 26 | final IconData? icon; 27 | 28 | final List? iconPaths; 29 | 30 | final Widget? trailing; 31 | 32 | final bool selected; 33 | 34 | final VoidCallback? onTap; 35 | 36 | final bool divider; 37 | 38 | Widget? get _leading { 39 | if (leading != null) { 40 | return leading!; 41 | } 42 | if (icon != null) { 43 | return Container( 44 | height: 36, 45 | width: 36, 46 | decoration: BoxDecoration( 47 | color: ColorUtils.backgroundColorWithString(title), 48 | borderRadius: const BorderRadius.all(Radius.circular(18)), 49 | ), 50 | alignment: Alignment.center, 51 | child: Icon( 52 | icon!, 53 | color: ColorUtils.foregroundColorWithString(title), 54 | ), 55 | ); 56 | } 57 | if (iconPaths != null) { 58 | return Container( 59 | height: 36, 60 | width: 36, 61 | decoration: BoxDecoration( 62 | color: ColorUtils.backgroundColorWithString(title), 63 | borderRadius: const BorderRadius.all(Radius.circular(18)), 64 | ), 65 | alignment: Alignment.center, 66 | child: PathsPaint( 67 | paths: iconPaths!, 68 | colors: List.filled( 69 | iconPaths!.length, ColorUtils.foregroundColorWithString(title)), 70 | width: 24, 71 | ), 72 | ); 73 | } 74 | return null; 75 | } 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | return Column( 80 | children: [ 81 | ListTile( 82 | title: Text(title), 83 | subtitle: subtitle == null ? null : Text(subtitle!), 84 | leading: _leading, 85 | trailing: trailing, 86 | selected: selected, 87 | onTap: onTap, 88 | ), 89 | if (divider) 90 | Padding( 91 | padding: EdgeInsets.only( 92 | left: leading == null && icon == null ? 16 : 72, right: 16), 93 | child: const Divider( 94 | thickness: 1, 95 | height: 1, 96 | ), 97 | ), 98 | ], 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import rive_common 9 | import url_launcher_macos 10 | 11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 12 | RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) 13 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 14 | } 15 | -------------------------------------------------------------------------------- /example/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = flutterapp 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.knoyo.flutterapp 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2020 com.knoyo. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | void main() { 12 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 13 | // Verify that our counter starts at 0. 14 | expect(find.text('0'), findsOneWidget); 15 | expect(find.text('1'), findsNothing); 16 | 17 | // Tap the '+' icon and trigger a frame. 18 | await tester.tap(find.byIcon(Icons.add)); 19 | await tester.pump(); 20 | 21 | // Verify that our counter has incremented. 22 | expect(find.text('0'), findsNothing); 23 | expect(find.text('1'), findsOneWidget); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | EasyRefresh 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /example/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /example/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void RegisterPlugins(flutter::PluginRegistry* registry) { 13 | RivePluginRegisterWithRegistrar( 14 | registry->GetRegistrarForPlugin("RivePlugin")); 15 | UrlLauncherWindowsRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 17 | } 18 | -------------------------------------------------------------------------------- /example/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /example/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | rive_common 7 | url_launcher_windows 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /example/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /example/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /example/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /example/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"example", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /example/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /example/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/example/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /example/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length <= 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /example/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /lib/easy_paging.dart: -------------------------------------------------------------------------------- 1 | library easy_paging; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/physics.dart' as physics; 5 | 6 | import 'easy_refresh.dart'; 7 | 8 | part 'src/easy_paging.dart'; 9 | -------------------------------------------------------------------------------- /lib/easy_refresh.dart: -------------------------------------------------------------------------------- 1 | library easy_refresh; 2 | 3 | import 'dart:math' as math; 4 | import 'dart:async'; 5 | 6 | import 'package:flutter/cupertino.dart'; 7 | import 'package:flutter/foundation.dart'; 8 | import 'package:flutter/gestures.dart'; 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter/physics.dart' as physics; 11 | import 'package:flutter/rendering.dart'; 12 | import 'package:flutter/scheduler.dart'; 13 | import 'package:flutter/services.dart'; 14 | import 'package:easy_refresh/src/painter/paths_painter.dart'; 15 | 16 | part 'src/easy_refresh.dart'; 17 | part 'src/physics/scroll_physics.dart'; 18 | part 'src/notifier/indicator_notifier.dart'; 19 | part 'src/behavior/scroll_behavior.dart'; 20 | part 'src/indicator/indicator.dart'; 21 | part 'src/indicator/header/header.dart'; 22 | part 'src/indicator/header/header_locator.dart'; 23 | part 'src/indicator/footer/footer.dart'; 24 | part 'src/indicator/footer/footer_locator.dart'; 25 | part 'src/controller/controller.dart'; 26 | part 'src/styles/classic/header/classic_header.dart'; 27 | part 'src/styles/classic/footer/classic_footer.dart'; 28 | part 'src/styles/classic/classic_indicator.dart'; 29 | part 'src/styles/material/material_indicator.dart'; 30 | part 'src/styles/material/header/material_header.dart'; 31 | part 'src/styles/material/footer/material_footer.dart'; 32 | part 'src/styles/bezier/bezier_background.dart'; 33 | part 'src/styles/bezier/bezier_indicator.dart'; 34 | part 'src/styles/bezier/bezier_circle_indicator.dart'; 35 | part 'src/styles/bezier/spin/hour_glass.dart'; 36 | part 'src/styles/bezier/header/bezier_header.dart'; 37 | part 'src/styles/bezier/header/bezier_circle_header.dart'; 38 | part 'src/styles/bezier/footer/bezier_footer.dart'; 39 | part 'src/styles/phoenix/phoenix_indicator.dart'; 40 | part 'src/styles/phoenix/header/phoenix_header.dart'; 41 | part 'src/styles/phoenix/footer/phoenix_footer.dart'; 42 | part 'src/styles/taurus/taurus_indicator.dart'; 43 | part 'src/styles/taurus/header/taurus_header.dart'; 44 | part 'src/styles/taurus/footer/taurus_footer.dart'; 45 | part 'src/styles/delivery/delivery_indicator.dart'; 46 | part 'src/styles/delivery/header/delivery_header.dart'; 47 | part 'src/styles/delivery/footer/delivery_footer.dart'; 48 | part 'src/styles/cupertino/cupertino_indicator.dart'; 49 | part 'src/styles/cupertino/cupertino_activity_indicator.dart'; 50 | part 'src/styles/cupertino/header/cupertino_header.dart'; 51 | part 'src/styles/cupertino/footer/cupertino_footer.dart'; 52 | -------------------------------------------------------------------------------- /lib/src/behavior/scroll_behavior.dart: -------------------------------------------------------------------------------- 1 | part of '../../easy_refresh.dart'; 2 | 3 | /// Define [ScrollBehavior] in the scope of EasyRefresh. 4 | /// Add support for web and PC. 5 | class ERScrollBehavior extends ScrollBehavior { 6 | static final Set _kDragDevices = 7 | PointerDeviceKind.values.toSet(); 8 | 9 | final ScrollPhysics? _physics; 10 | 11 | const ERScrollBehavior([this._physics]); 12 | 13 | @override 14 | ScrollPhysics getScrollPhysics(BuildContext context) { 15 | return _physics ?? super.getScrollPhysics(context); 16 | } 17 | 18 | @override 19 | Widget buildOverscrollIndicator( 20 | BuildContext context, Widget child, ScrollableDetails details) { 21 | return child; 22 | } 23 | 24 | @override 25 | Widget buildScrollbar( 26 | BuildContext context, Widget child, ScrollableDetails details) { 27 | switch (getPlatform(context)) { 28 | case TargetPlatform.linux: 29 | case TargetPlatform.macOS: 30 | case TargetPlatform.windows: 31 | assert(details.controller != null); 32 | if (details.controller!.positions.length > 1 || 33 | details.controller!.debugLabel == 'inner') { 34 | return child; 35 | } 36 | return Scrollbar( 37 | controller: details.controller, 38 | child: child, 39 | ); 40 | case TargetPlatform.android: 41 | case TargetPlatform.fuchsia: 42 | case TargetPlatform.iOS: 43 | return child; 44 | default: 45 | return child; 46 | } 47 | } 48 | 49 | @override 50 | Set get dragDevices => _kDragDevices; 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/styles/bezier/footer/bezier_footer.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Bezier footer. 4 | class BezierFooter extends Footer { 5 | final Key? key; 6 | 7 | /// Show the ball during the pull. 8 | final bool showBalls; 9 | 10 | /// Spin widget. 11 | final Widget? spinWidget; 12 | 13 | /// No more widget. 14 | final Widget? noMoreWidget; 15 | 16 | /// Spin widget builder. 17 | final BezierSpinBuilder? spinBuilder; 18 | 19 | /// Foreground color. 20 | final Color? foregroundColor; 21 | 22 | /// Background color. 23 | final Color? backgroundColor; 24 | 25 | /// Whether the spin widget is in the center. 26 | final bool spinInCenter; 27 | 28 | /// Only display the spin. 29 | /// When true, the balls are no longer displayed. 30 | final bool onlySpin; 31 | 32 | const BezierFooter({ 33 | this.key, 34 | super.triggerOffset = 100, 35 | super.clamping = false, 36 | super.position, 37 | super.processedDuration = kBezierBackgroundDisappearDuration, 38 | super.spring, 39 | SpringBuilder super.readySpringBuilder = kBezierSpringBuilder, 40 | super.springRebound = false, 41 | FrictionFactor super.frictionFactor = kBezierFrictionFactor, 42 | super.safeArea, 43 | super.infiniteOffset = null, 44 | super.hitOver, 45 | super.infiniteHitOver, 46 | super.hapticFeedback, 47 | this.showBalls = true, 48 | this.spinInCenter = true, 49 | this.onlySpin = false, 50 | this.spinWidget, 51 | this.noMoreWidget, 52 | this.spinBuilder, 53 | this.foregroundColor, 54 | this.backgroundColor, 55 | }); 56 | 57 | @override 58 | Widget build(BuildContext context, IndicatorState state) { 59 | return _BezierIndicator( 60 | key: key, 61 | state: state, 62 | reverse: !state.reverse, 63 | processedDuration: processedDuration, 64 | showBalls: showBalls, 65 | spinInCenter: spinInCenter, 66 | onlySpin: onlySpin, 67 | spinWidget: spinWidget, 68 | noMoreWidget: noMoreWidget, 69 | spinBuilder: spinBuilder, 70 | foregroundColor: foregroundColor, 71 | backgroundColor: backgroundColor, 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/src/styles/bezier/header/bezier_circle_header.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Bezier circle footer. 4 | /// https://dribbble.com/shots/1797373-Pull-Down-To-Refresh 5 | class BezierCircleHeader extends Header { 6 | final Key? key; 7 | 8 | /// Foreground color. 9 | final Color? foregroundColor; 10 | 11 | /// Background color. 12 | final Color? backgroundColor; 13 | 14 | const BezierCircleHeader({ 15 | this.key, 16 | super.triggerOffset = 100, 17 | super.clamping = false, 18 | super.position, 19 | super.spring, 20 | SpringBuilder super.readySpringBuilder = kBezierSpringBuilder, 21 | super.springRebound = false, 22 | FrictionFactor super.frictionFactor = kBezierFrictionFactor, 23 | super.safeArea, 24 | super.infiniteOffset, 25 | super.hitOver, 26 | super.infiniteHitOver, 27 | super.hapticFeedback, 28 | this.foregroundColor, 29 | this.backgroundColor, 30 | }) : super( 31 | processedDuration: kBezierCircleDisappearDuration, 32 | ); 33 | 34 | @override 35 | Widget build(BuildContext context, IndicatorState state) { 36 | assert(state.axis == Axis.vertical, 37 | 'BezierCircleHeader does not support horizontal scrolling.'); 38 | assert(!state.reverse, 'BezierCircleHeader does not support reverse.'); 39 | return _BezierCircleIndicator( 40 | key: key, 41 | state: state, 42 | foregroundColor: foregroundColor, 43 | backgroundColor: backgroundColor, 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/styles/bezier/header/bezier_header.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Bezier header. 4 | class BezierHeader extends Header { 5 | final Key? key; 6 | 7 | /// Show the ball during the pull. 8 | final bool showBalls; 9 | 10 | /// Spin widget. 11 | final Widget? spinWidget; 12 | 13 | /// No more widget. 14 | final Widget? noMoreWidget; 15 | 16 | /// Spin widget builder. 17 | final BezierSpinBuilder? spinBuilder; 18 | 19 | /// Foreground color. 20 | final Color? foregroundColor; 21 | 22 | /// Background color. 23 | final Color? backgroundColor; 24 | 25 | /// Whether the spin widget is in the center. 26 | final bool spinInCenter; 27 | 28 | /// Only display the spin. 29 | /// When true, the balls are no longer displayed. 30 | final bool onlySpin; 31 | 32 | const BezierHeader({ 33 | this.key, 34 | super.triggerOffset = 100, 35 | super.clamping = false, 36 | super.position, 37 | super.processedDuration = kBezierBackgroundDisappearDuration, 38 | super.spring, 39 | SpringBuilder super.readySpringBuilder = kBezierSpringBuilder, 40 | super.springRebound = false, 41 | FrictionFactor super.frictionFactor = kBezierFrictionFactor, 42 | super.safeArea, 43 | super.infiniteOffset, 44 | super.hitOver, 45 | super.infiniteHitOver, 46 | super.hapticFeedback, 47 | this.showBalls = true, 48 | this.spinInCenter = true, 49 | this.onlySpin = false, 50 | this.spinWidget, 51 | this.noMoreWidget, 52 | this.spinBuilder, 53 | this.foregroundColor, 54 | this.backgroundColor, 55 | }); 56 | 57 | @override 58 | Widget build(BuildContext context, IndicatorState state) { 59 | return _BezierIndicator( 60 | key: key, 61 | state: state, 62 | reverse: state.reverse, 63 | processedDuration: processedDuration, 64 | showBalls: showBalls, 65 | spinInCenter: spinInCenter, 66 | onlySpin: onlySpin, 67 | spinWidget: spinWidget, 68 | noMoreWidget: noMoreWidget, 69 | spinBuilder: spinBuilder, 70 | foregroundColor: foregroundColor, 71 | backgroundColor: backgroundColor, 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/src/styles/bezier/spin/hour_glass.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Code from [https://github.com/jogboms/flutter_spinkit]. 4 | /// flutter_spinkit LICENSE [https://github.com/jogboms/flutter_spinkit/blob/master/LICENSE]. 5 | class _SpinKitHourGlass extends StatefulWidget { 6 | const _SpinKitHourGlass({ 7 | super.key, 8 | required this.color, 9 | this.size = 50.0, 10 | }); 11 | 12 | final Color color; 13 | final double size; 14 | 15 | @override 16 | _SpinKitHourGlassState createState() => _SpinKitHourGlassState(); 17 | } 18 | 19 | class _SpinKitHourGlassState extends State<_SpinKitHourGlass> 20 | with SingleTickerProviderStateMixin { 21 | late AnimationController _controller; 22 | late Animation _animation; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | 28 | _controller = AnimationController( 29 | vsync: this, duration: const Duration(milliseconds: 1200)) 30 | ..addListener(() => setState(() {})) 31 | ..repeat(); 32 | _animation = Tween(begin: 0.0, end: 8.0).animate(CurvedAnimation( 33 | parent: _controller, 34 | curve: const Interval(0.0, 1.0, curve: Curves.easeOut))); 35 | } 36 | 37 | @override 38 | void dispose() { 39 | _controller.dispose(); 40 | super.dispose(); 41 | } 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | return Center( 46 | child: Transform( 47 | transform: Matrix4.identity()..rotateZ((_animation.value) * math.pi), 48 | alignment: FractionalOffset.center, 49 | child: CustomPaint( 50 | painter: _HourGlassPainter(weight: 90, color: widget.color), 51 | child: SizedBox.fromSize(size: Size.square(widget.size)), 52 | ), 53 | ), 54 | ); 55 | } 56 | } 57 | 58 | class _HourGlassPainter extends CustomPainter { 59 | _HourGlassPainter({required this.weight, required Color color}) 60 | : _paint = Paint() 61 | ..color = color 62 | ..strokeWidth = 1.0; 63 | 64 | final Paint _paint; 65 | final double weight; 66 | 67 | @override 68 | void paint(Canvas canvas, Size size) { 69 | final rect = Rect.fromPoints(Offset.zero, Offset(size.width, size.height)); 70 | canvas.drawArc(rect, 0.0, getRadian(weight), true, _paint); 71 | canvas.drawArc(rect, getRadian(180.0), getRadian(weight), true, _paint); 72 | } 73 | 74 | @override 75 | bool shouldRepaint(CustomPainter oldDelegate) => true; 76 | 77 | double getRadian(double angle) => math.pi / 180 * angle; 78 | } 79 | -------------------------------------------------------------------------------- /lib/src/styles/cupertino/footer/cupertino_footer.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Cupertino footer. 4 | /// https://github.com/THEONE10211024/WaterDropListView 5 | class CupertinoFooter extends Footer { 6 | final Key? key; 7 | 8 | /// Indicator foreground color. 9 | final Color? foregroundColor; 10 | 11 | /// Use WaterDrop style. 12 | final bool userWaterDrop; 13 | 14 | /// WaterDrop background color. 15 | final Color? backgroundColor; 16 | 17 | /// Empty widget. 18 | /// When result is [IndicatorResult.noMore]. 19 | final Widget? emptyWidget; 20 | 21 | const CupertinoFooter({ 22 | this.key, 23 | super.triggerOffset = 60, 24 | super.clamping = false, 25 | super.position = IndicatorPosition.behind, 26 | super.processedDuration = Duration.zero, 27 | super.spring, 28 | super.readySpringBuilder, 29 | super.springRebound, 30 | FrictionFactor? frictionFactor, 31 | super.safeArea, 32 | super.infiniteOffset = 60, 33 | super.hitOver, 34 | super.infiniteHitOver, 35 | super.hapticFeedback, 36 | super.triggerWhenRelease, 37 | super.maxOverOffset, 38 | this.foregroundColor, 39 | this.userWaterDrop = false, 40 | this.backgroundColor, 41 | this.emptyWidget, 42 | }) : super( 43 | frictionFactor: frictionFactor ?? 44 | (userWaterDrop && infiniteOffset == null 45 | ? kCupertinoFrictionFactor 46 | : null), 47 | horizontalFrictionFactor: kCupertinoHorizontalFrictionFactor, 48 | ); 49 | 50 | @override 51 | Widget build(BuildContext context, IndicatorState state) { 52 | return _CupertinoIndicator( 53 | key: key, 54 | state: state, 55 | reverse: state.reverse, 56 | foregroundColor: foregroundColor, 57 | userWaterDrop: userWaterDrop, 58 | backgroundColor: backgroundColor, 59 | emptyWidget: emptyWidget, 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/src/styles/cupertino/header/cupertino_header.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Cupertino header. 4 | /// https://github.com/THEONE10211024/WaterDropListView 5 | class CupertinoHeader extends Header { 6 | final Key? key; 7 | 8 | /// Indicator foreground color. 9 | final Color? foregroundColor; 10 | 11 | /// Use WaterDrop style. 12 | final bool userWaterDrop; 13 | 14 | /// WaterDrop background color. 15 | final Color? backgroundColor; 16 | 17 | /// Empty widget. 18 | /// When result is [IndicatorResult.noMore]. 19 | final Widget? emptyWidget; 20 | 21 | const CupertinoHeader({ 22 | this.key, 23 | super.triggerOffset = 60, 24 | super.clamping = false, 25 | super.position = IndicatorPosition.behind, 26 | super.processedDuration = Duration.zero, 27 | super.spring, 28 | super.readySpringBuilder, 29 | super.springRebound = false, 30 | FrictionFactor? frictionFactor, 31 | super.safeArea, 32 | super.infiniteOffset, 33 | super.hitOver, 34 | super.infiniteHitOver, 35 | super.hapticFeedback, 36 | super.triggerWhenRelease, 37 | super.maxOverOffset, 38 | this.foregroundColor, 39 | this.userWaterDrop = true, 40 | this.backgroundColor, 41 | this.emptyWidget, 42 | }) : super( 43 | frictionFactor: frictionFactor ?? 44 | (userWaterDrop && infiniteOffset == null 45 | ? kCupertinoFrictionFactor 46 | : null), 47 | horizontalFrictionFactor: kCupertinoHorizontalFrictionFactor, 48 | ); 49 | 50 | @override 51 | Widget build(BuildContext context, IndicatorState state) { 52 | return _CupertinoIndicator( 53 | key: key, 54 | state: state, 55 | reverse: state.reverse, 56 | foregroundColor: foregroundColor, 57 | userWaterDrop: userWaterDrop, 58 | backgroundColor: backgroundColor, 59 | emptyWidget: emptyWidget, 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/src/styles/delivery/footer/delivery_footer.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Delivery footer. 4 | /// https://dribbble.com/shots/2753803-Refresh-your-delivery 5 | class DeliveryFooter extends Footer { 6 | final Key? key; 7 | 8 | /// Sky color. 9 | final Color? skyColor; 10 | 11 | const DeliveryFooter({ 12 | this.key, 13 | super.triggerOffset = kDeliveryTriggerOffset, 14 | super.clamping = false, 15 | super.position, 16 | super.spring, 17 | super.readySpringBuilder, 18 | super.springRebound = false, 19 | super.frictionFactor, 20 | super.infiniteOffset = null, 21 | super.hitOver, 22 | super.infiniteHitOver, 23 | super.hapticFeedback, 24 | this.skyColor, 25 | }) : super( 26 | processedDuration: const Duration(milliseconds: 100), 27 | safeArea: false, 28 | ); 29 | 30 | @override 31 | Widget build(BuildContext context, IndicatorState state) { 32 | assert(state.axis == Axis.vertical, 33 | 'DeliveryFooter does not support horizontal scrolling.'); 34 | return _DeliveryIndicator( 35 | key: key, 36 | state: state, 37 | reverse: state.reverse, 38 | skyColor: skyColor, 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/styles/delivery/header/delivery_header.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Delivery footer. 4 | /// https://dribbble.com/shots/2753803-Refresh-your-delivery 5 | class DeliveryHeader extends Header { 6 | final Key? key; 7 | 8 | /// Sky color. 9 | final Color? skyColor; 10 | 11 | const DeliveryHeader({ 12 | this.key, 13 | super.triggerOffset = kDeliveryTriggerOffset, 14 | super.clamping = false, 15 | super.position, 16 | super.spring, 17 | super.readySpringBuilder, 18 | super.springRebound = false, 19 | super.frictionFactor, 20 | super.infiniteOffset, 21 | super.hitOver, 22 | super.infiniteHitOver, 23 | super.hapticFeedback, 24 | this.skyColor, 25 | }) : super( 26 | processedDuration: const Duration(milliseconds: 100), 27 | safeArea: false, 28 | ); 29 | 30 | @override 31 | Widget build(BuildContext context, IndicatorState state) { 32 | assert(state.axis == Axis.vertical, 33 | 'DeliveryHeader does not support horizontal scrolling.'); 34 | return _DeliveryIndicator( 35 | key: key, 36 | state: state, 37 | reverse: state.reverse, 38 | skyColor: skyColor, 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/styles/phoenix/footer/phoenix_footer.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Phoenix footer. 4 | /// https://github.com/Yalantis/Phoenix 5 | class PhoenixFooter extends Footer { 6 | final Key? key; 7 | 8 | /// Sky color. 9 | final Color? skyColor; 10 | 11 | const PhoenixFooter({ 12 | this.key, 13 | super.triggerOffset = 100, 14 | super.clamping = false, 15 | super.position, 16 | super.processedDuration, 17 | super.spring, 18 | super.readySpringBuilder, 19 | super.springRebound = false, 20 | super.frictionFactor, 21 | super.safeArea, 22 | super.infiniteOffset = null, 23 | super.hitOver, 24 | super.infiniteHitOver, 25 | super.hapticFeedback, 26 | this.skyColor, 27 | }); 28 | 29 | @override 30 | Widget build(BuildContext context, IndicatorState state) { 31 | assert(state.axis == Axis.vertical, 32 | 'PhoenixFooter does not support horizontal scrolling.'); 33 | return _PhoenixIndicator( 34 | key: key, 35 | state: state, 36 | reverse: state.reverse, 37 | skyColor: skyColor, 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/styles/phoenix/header/phoenix_header.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Phoenix header. 4 | /// https://github.com/Yalantis/Phoenix 5 | class PhoenixHeader extends Header { 6 | final Key? key; 7 | 8 | /// Sky color. 9 | final Color? skyColor; 10 | 11 | const PhoenixHeader({ 12 | this.key, 13 | super.triggerOffset = 100, 14 | super.clamping = false, 15 | super.position, 16 | super.processedDuration, 17 | super.spring, 18 | super.readySpringBuilder, 19 | super.springRebound = false, 20 | super.frictionFactor, 21 | super.safeArea, 22 | super.infiniteOffset, 23 | super.hitOver, 24 | super.infiniteHitOver, 25 | super.hapticFeedback, 26 | this.skyColor, 27 | }); 28 | 29 | @override 30 | Widget build(BuildContext context, IndicatorState state) { 31 | assert(state.axis == Axis.vertical, 32 | 'PhoenixHeader does not support horizontal scrolling.'); 33 | return _PhoenixIndicator( 34 | key: key, 35 | state: state, 36 | reverse: state.reverse, 37 | skyColor: skyColor, 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/styles/taurus/footer/taurus_footer.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Taurus footer. 4 | /// https://github.com/Yalantis/Taurus 5 | class TaurusFooter extends Footer { 6 | final Key? key; 7 | 8 | /// Sky color. 9 | final Color? skyColor; 10 | 11 | const TaurusFooter({ 12 | this.key, 13 | super.triggerOffset = 100, 14 | super.clamping = false, 15 | super.position, 16 | super.spring, 17 | super.readySpringBuilder, 18 | super.springRebound = false, 19 | super.frictionFactor, 20 | super.safeArea, 21 | super.infiniteOffset = null, 22 | super.hitOver, 23 | super.infiniteHitOver, 24 | super.hapticFeedback, 25 | this.skyColor, 26 | }) : super( 27 | processedDuration: kTaurusDisappearDuration, 28 | ); 29 | 30 | @override 31 | Widget build(BuildContext context, IndicatorState state) { 32 | assert(state.axis == Axis.vertical, 33 | 'TaurusFooter does not support horizontal scrolling.'); 34 | return _TaurusIndicator( 35 | key: key, 36 | state: state, 37 | reverse: state.reverse, 38 | skyColor: skyColor, 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/styles/taurus/header/taurus_header.dart: -------------------------------------------------------------------------------- 1 | part of '../../../../easy_refresh.dart'; 2 | 3 | /// Taurus header. 4 | /// https://github.com/Yalantis/Taurus 5 | class TaurusHeader extends Header { 6 | final Key? key; 7 | 8 | /// Sky color. 9 | final Color? skyColor; 10 | 11 | const TaurusHeader({ 12 | this.key, 13 | super.triggerOffset = 100, 14 | super.clamping = false, 15 | super.position, 16 | super.spring, 17 | super.readySpringBuilder, 18 | super.springRebound = false, 19 | super.frictionFactor, 20 | super.safeArea, 21 | super.infiniteOffset, 22 | super.hitOver, 23 | super.infiniteHitOver, 24 | super.hapticFeedback, 25 | this.skyColor, 26 | }) : super( 27 | processedDuration: kTaurusDisappearDuration, 28 | ); 29 | 30 | @override 31 | Widget build(BuildContext context, IndicatorState state) { 32 | assert(state.axis == Axis.vertical, 33 | 'TaurusHeader does not support horizontal scrolling.'); 34 | return _TaurusIndicator( 35 | key: key, 36 | state: state, 37 | reverse: state.reverse, 38 | skyColor: skyColor, 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: easy_refresh 2 | description: A flutter widget that provides pull-down refresh and pull-up load. 3 | version: 3.4.0 4 | homepage: https://xuelongqy.github.io/flutter_easy_refresh 5 | repository: https://github.com/xuelongqy/flutter_easy_refresh 6 | issue_tracker: https://github.com/xuelongqy/flutter_easy_refresh/issues 7 | 8 | environment: 9 | sdk: ">=2.19.0 <4.0.0" 10 | flutter: ">=3.10.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | path_drawing: ^1.0.1 17 | 18 | dev_dependencies: 19 | flutter_lints: ^4.0.0 20 | flutter_test: 21 | sdk: flutter 22 | 23 | # For information on the generic Dart part of this file, see the 24 | # following page: https://www.dartlang.org/tools/pub/pubspec 25 | 26 | flutter: 27 | # The following line ensures that the Material Icons font is 28 | # included with your application, so that you can use the icons in 29 | # the material Icons class. 30 | uses-material-design: true 31 | 32 | # To add Flutter specific assets to your application, add an assets section, 33 | # like this: 34 | # assets: 35 | # - images/a_dot_burr.jpeg 36 | # - images/a_dot_ham.jpeg 37 | 38 | # An image asset can refer to one or more resolution-specific "variants", see 39 | # https://flutter.io/assets-and-images/#resolution-aware. 40 | 41 | # For details regarding adding assets from package dependencies, see 42 | # https://flutter.io/assets-and-images/#from-packages 43 | 44 | # To add Flutter specific custom fonts to your application, add a fonts 45 | # section here, in this "flutter" section. Each entry in this list should 46 | # have a "family" key with the font family name, and a "fonts" key with a 47 | # list giving the asset and other descriptors for the font. For 48 | # example: 49 | # fonts: 50 | # - family: Schyler 51 | # fonts: 52 | # - asset: fonts/Schyler-Regular.ttf 53 | # - asset: fonts/Schyler-Italic.ttf 54 | # style: italic 55 | # - family: Trajan Pro 56 | # fonts: 57 | # - asset: fonts/TrajanPro.ttf 58 | # - asset: fonts/TrajanPro_Bold.ttf 59 | # weight: 700 60 | # 61 | # For details regarding fonts from package dependencies, 62 | # see https://flutter.io/custom-fonts/#from-packages 63 | 64 | 65 | # This section identifies your Flutter project as a module meant for 66 | # embedding in a native host app. These identifiers should _not_ ordinarily 67 | # be changed after generation - they are used to ensure that the tooling can 68 | # maintain consistency when adding or modifying assets and plugins. 69 | # They also do not have any bearing on your native host application's 70 | # identifiers, which may be completely independent or the same as these. 71 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/.flutter-plugins: -------------------------------------------------------------------------------- 1 | # This is a generated file; do not edit or check into version control. 2 | rive_common=/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/ 3 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"rive_common","path":"/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/","native_build":true,"dependencies":[]}],"android":[{"name":"rive_common","path":"/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/","native_build":true,"dependencies":[]}],"macos":[{"name":"rive_common","path":"/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/","native_build":true,"dependencies":[]}],"linux":[{"name":"rive_common","path":"/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/","native_build":true,"dependencies":[]}],"windows":[{"name":"rive_common","path":"/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/","native_build":true,"dependencies":[]}],"web":[{"name":"rive_common","path":"/Users/xuelongqy/.pub-cache/hosted/pub.flutter-io.cn/rive_common-0.4.9/","dependencies":[]}]},"dependencyGraph":[{"name":"rive_common","dependencies":[]}],"date_created":"2024-06-30 14:12:47.562292","version":"3.22.2"} -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | - Bubbles Indicator on EasyRefresh. 3 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 xuelongqy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/README.md: -------------------------------------------------------------------------------- 1 | # Bubbles Indicator on EasyRefresh. 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](/LICENSE) 4 | [![Pub](https://img.shields.io/pub/v/easy_refresh_bubbles)](https://pub.flutter-io.cn/packages/easy_refresh_bubbles) 5 | 6 | ### [Online demo](https://xuelongqy.github.io/flutter_easy_refresh/#/style/bubbles) 7 | Animation from [Pull to Refresh](https://rive.app/community/3146-6725-pull-to-refresh/) 8 | 9 | ## Features 10 | 11 | BubblesHeader and BubblesFooter. 12 | 13 | ## Getting started 14 | 15 | ``` 16 | dependencies: 17 | flutter_easyre_fresh: version 18 | easy_refresh_bubbles: version 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```dart 24 | EasyRefresh( 25 | header: BubblesHeader(), 26 | footer: BubblesFooter(), 27 | onRefresh: () async {}, 28 | onLoad: () async {}, 29 | child: ListView(), 30 | ) 31 | ``` 32 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/assets/bubbles.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/styles/easy_refresh_bubbles/assets/bubbles.riv -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_bubbles/easy_refresh_bubbles.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:easy_refresh/easy_refresh.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const MaterialApp( 13 | title: 'Bubbles', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | const HomePage({Key? key}) : super(key: key); 21 | 22 | @override 23 | State createState() => _HomePageState(); 24 | } 25 | 26 | class _HomePageState extends State { 27 | int _count = 10; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: const Text('Bubbles'), 34 | ), 35 | body: EasyRefresh( 36 | header: const BubblesHeader(), 37 | footer: const BubblesFooter(), 38 | onRefresh: () async { 39 | await Future.delayed(const Duration(seconds: 4)); 40 | if (!mounted) { 41 | return; 42 | } 43 | setState(() { 44 | _count = 10; 45 | }); 46 | }, 47 | onLoad: () async { 48 | await Future.delayed(const Duration(seconds: 4)); 49 | if (!mounted) { 50 | return; 51 | } 52 | setState(() { 53 | _count += 5; 54 | }); 55 | }, 56 | child: ListView.builder( 57 | itemBuilder: (context, index) { 58 | return Card( 59 | child: Container( 60 | alignment: Alignment.center, 61 | height: 80, 62 | child: Text('${index + 1}'), 63 | ), 64 | ); 65 | }, 66 | itemCount: _count, 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/lib/easy_refresh_bubbles.dart: -------------------------------------------------------------------------------- 1 | library easy_refresh_bubbles; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/physics.dart' as physics; 5 | import 'package:easy_refresh/easy_refresh.dart'; 6 | import 'package:rive/rive.dart'; 7 | 8 | part 'src/bubbles_indicator.dart'; 9 | part 'src/bubbles_header.dart'; 10 | part 'src/bubbles_footer.dart'; 11 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/lib/src/bubbles_footer.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_bubbles; 2 | 3 | class BubblesFooter extends Footer { 4 | final Key? key; 5 | 6 | const BubblesFooter({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultBubblesTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | Duration processedDuration = _kBubblesProcessed, 12 | physics.SpringDescription? spring, 13 | SpringBuilder? readySpringBuilder, 14 | bool springRebound = false, 15 | FrictionFactor? frictionFactor, 16 | double? infiniteOffset, 17 | bool? hitOver, 18 | bool? infiniteHitOver, 19 | bool hapticFeedback = false, 20 | }) : super( 21 | triggerOffset: triggerOffset, 22 | clamping: clamping, 23 | processedDuration: processedDuration, 24 | spring: spring, 25 | readySpringBuilder: readySpringBuilder, 26 | springRebound: springRebound, 27 | frictionFactor: frictionFactor, 28 | safeArea: false, 29 | infiniteOffset: infiniteOffset, 30 | hitOver: hitOver, 31 | infiniteHitOver: infiniteHitOver, 32 | position: position, 33 | hapticFeedback: hapticFeedback, 34 | triggerWhenRelease: true, 35 | ); 36 | 37 | @override 38 | Widget build(BuildContext context, IndicatorState state) { 39 | assert(state.axis == Axis.vertical, 40 | 'BubblesFooter does not support horizontal scrolling.'); 41 | return _BubblesIndicator( 42 | key: key, 43 | state: state, 44 | reverse: state.reverse, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/lib/src/bubbles_header.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_bubbles; 2 | 3 | class BubblesHeader extends Header { 4 | final Key? key; 5 | 6 | const BubblesHeader({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultBubblesTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | Duration processedDuration = _kBubblesProcessed, 12 | physics.SpringDescription? spring, 13 | SpringBuilder? readySpringBuilder, 14 | bool springRebound = false, 15 | FrictionFactor? frictionFactor, 16 | double? infiniteOffset, 17 | bool? hitOver, 18 | bool? infiniteHitOver, 19 | bool hapticFeedback = false, 20 | }) : super( 21 | triggerOffset: triggerOffset, 22 | clamping: clamping, 23 | processedDuration: processedDuration, 24 | spring: spring, 25 | readySpringBuilder: readySpringBuilder, 26 | springRebound: springRebound, 27 | frictionFactor: frictionFactor, 28 | safeArea: false, 29 | infiniteOffset: infiniteOffset, 30 | hitOver: hitOver, 31 | infiniteHitOver: infiniteHitOver, 32 | position: position, 33 | hapticFeedback: hapticFeedback, 34 | triggerWhenRelease: true, 35 | ); 36 | 37 | @override 38 | Widget build(BuildContext context, IndicatorState state) { 39 | assert(state.axis == Axis.vertical, 40 | 'BubblesHeader does not support horizontal scrolling.'); 41 | return _BubblesIndicator( 42 | key: key, 43 | state: state, 44 | reverse: state.reverse, 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /styles/easy_refresh_bubbles/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: easy_refresh_bubbles 2 | description: Bubbles Indicator on EasyRefresh. Provides BubblesHeader and BubblesFooter. Animation with Rive. 3 | version: 1.0.0 4 | homepage: https://xuelongqy.github.io/flutter_easy_refresh/#/style/bubbles 5 | repository: https://github.com/xuelongqy/flutter_easy_refresh/tree/v3/styles/easy_refresh_bubbles 6 | issue_tracker: https://github.com/xuelongqy/flutter_easy_refresh/issues 7 | 8 | environment: 9 | sdk: ">=2.13.0 <3.0.0" 10 | flutter: ">=1.24.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | rive: any 16 | easy_refresh: 17 | path: ../../ 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^2.0.1 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://dart.dev/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter packages. 28 | flutter: 29 | 30 | # To add assets to your package, add an assets section, like this: 31 | assets: 32 | - assets/bubbles.riv 33 | # 34 | # For details regarding assets in packages, see 35 | # https://flutter.dev/assets-and-images/#from-packages 36 | # 37 | # An image asset can refer to one or more resolution-specific "variants", see 38 | # https://flutter.dev/assets-and-images/#resolution-aware 39 | 40 | # To add custom fonts to your package, add a fonts section here, 41 | # in this "flutter" section. Each entry in this list should have a 42 | # "family" key with the font family name, and a "fonts" key with a 43 | # list giving the asset and other descriptors for the font. For 44 | # example: 45 | # fonts: 46 | # - family: Schyler 47 | # fonts: 48 | # - asset: fonts/Schyler-Regular.ttf 49 | # - asset: fonts/Schyler-Italic.ttf 50 | # style: italic 51 | # - family: Trajan Pro 52 | # fonts: 53 | # - asset: fonts/TrajanPro.ttf 54 | # - asset: fonts/TrajanPro_Bold.ttf 55 | # weight: 700 56 | # 57 | # For details regarding fonts in packages, see 58 | # https://flutter.dev/custom-fonts/#from-packages 59 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 2 | - chore: update dependencies. 3 | 4 | ## 1.0.1 5 | - perf: Optimize animation loading. 6 | - fix: The animation does not stop when [IndicatorMode.ready] returns to [IndicatorMode.armed]. 7 | 8 | ## 1.0.0+1 9 | - fix: dart >=2.13.0. 10 | 11 | ## 1.0.0 12 | - Halloween Indicator on EasyRefresh. 13 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 xuelongqy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/README.md: -------------------------------------------------------------------------------- 1 | # Halloween Indicator on EasyRefresh. 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](/LICENSE) 4 | [![Pub](https://img.shields.io/pub/v/easy_refresh_halloween)](https://pub.flutter-io.cn/packages/easy_refresh_halloween) 5 | 6 | ### [Online demo](https://xuelongqy.github.io/flutter_easy_refresh/#/style/halloween) 7 | Animation from [Pull to refresh halloween](https://rive.app/community/68-95-pull-to-refresh-halloween) 8 | 9 | ## Features 10 | 11 | HalloweenHeader and HalloweenFooter. 12 | 13 | ## Getting started 14 | 15 | ``` 16 | dependencies: 17 | flutter_easyre_fresh: version 18 | easy_refresh_halloween: version 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```dart 24 | EasyRefresh( 25 | header: HalloweenHeader(), 26 | footer: HalloweenFooter(), 27 | onRefresh: () async {}, 28 | onLoad: () async {}, 29 | child: ListView(), 30 | ) 31 | ``` 32 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/assets/halloween.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/styles/easy_refresh_halloween/assets/halloween.riv -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_halloween/easy_refresh_halloween.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:easy_refresh/easy_refresh.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const MaterialApp( 13 | title: 'Halloween', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | const HomePage({Key? key}) : super(key: key); 21 | 22 | @override 23 | State createState() => _HomePageState(); 24 | } 25 | 26 | class _HomePageState extends State { 27 | int _count = 10; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: const Text('Halloween'), 34 | ), 35 | body: EasyRefresh( 36 | header: const HalloweenHeader(), 37 | footer: const HalloweenFooter(), 38 | onRefresh: () async { 39 | await Future.delayed(const Duration(seconds: 4)); 40 | if (!mounted) { 41 | return; 42 | } 43 | setState(() { 44 | _count = 10; 45 | }); 46 | }, 47 | onLoad: () async { 48 | await Future.delayed(const Duration(seconds: 4)); 49 | if (!mounted) { 50 | return; 51 | } 52 | setState(() { 53 | _count += 5; 54 | }); 55 | }, 56 | child: ListView.builder( 57 | itemBuilder: (context, index) { 58 | return Card( 59 | child: Container( 60 | alignment: Alignment.center, 61 | height: 80, 62 | child: Text('${index + 1}'), 63 | ), 64 | ); 65 | }, 66 | itemCount: _count, 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/lib/easy_refresh_halloween.dart: -------------------------------------------------------------------------------- 1 | library easy_refresh_halloween; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/physics.dart' as physics; 5 | import 'package:easy_refresh/easy_refresh.dart'; 6 | import 'package:rive/rive.dart'; 7 | 8 | part 'src/halloween_indicator.dart'; 9 | part 'src/halloween_header.dart'; 10 | part 'src/halloween_footer.dart'; 11 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/lib/src/halloween_footer.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_halloween; 2 | 3 | class HalloweenFooter extends Footer { 4 | final Key? key; 5 | 6 | const HalloweenFooter({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultHalloweenTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | Duration processedDuration = Duration.zero, 12 | physics.SpringDescription? spring, 13 | SpringBuilder? readySpringBuilder, 14 | bool springRebound = false, 15 | FrictionFactor? frictionFactor, 16 | double? infiniteOffset, 17 | bool? hitOver, 18 | bool? infiniteHitOver, 19 | bool hapticFeedback = false, 20 | }) : super( 21 | triggerOffset: triggerOffset, 22 | clamping: clamping, 23 | processedDuration: processedDuration, 24 | spring: spring, 25 | readySpringBuilder: readySpringBuilder, 26 | springRebound: springRebound, 27 | frictionFactor: frictionFactor, 28 | safeArea: false, 29 | infiniteOffset: infiniteOffset, 30 | hitOver: hitOver, 31 | infiniteHitOver: infiniteHitOver, 32 | position: position, 33 | hapticFeedback: hapticFeedback, 34 | ); 35 | 36 | @override 37 | Widget build(BuildContext context, IndicatorState state) { 38 | assert(state.axis == Axis.vertical, 39 | 'HalloweenFooter does not support horizontal scrolling.'); 40 | return _HalloweenIndicator( 41 | key: key, 42 | state: state, 43 | reverse: state.reverse, 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/lib/src/halloween_header.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_halloween; 2 | 3 | class HalloweenHeader extends Header { 4 | final Key? key; 5 | 6 | const HalloweenHeader({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultHalloweenTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | Duration processedDuration = Duration.zero, 12 | physics.SpringDescription? spring, 13 | SpringBuilder? readySpringBuilder, 14 | bool springRebound = false, 15 | FrictionFactor? frictionFactor, 16 | double? infiniteOffset, 17 | bool? hitOver, 18 | bool? infiniteHitOver, 19 | bool hapticFeedback = false, 20 | }) : super( 21 | triggerOffset: triggerOffset, 22 | clamping: clamping, 23 | processedDuration: processedDuration, 24 | spring: spring, 25 | readySpringBuilder: readySpringBuilder, 26 | springRebound: springRebound, 27 | frictionFactor: frictionFactor, 28 | safeArea: false, 29 | infiniteOffset: infiniteOffset, 30 | hitOver: hitOver, 31 | infiniteHitOver: infiniteHitOver, 32 | position: position, 33 | hapticFeedback: hapticFeedback, 34 | ); 35 | 36 | @override 37 | Widget build(BuildContext context, IndicatorState state) { 38 | assert(state.axis == Axis.vertical, 39 | 'HalloweenHeader does not support horizontal scrolling.'); 40 | return _HalloweenIndicator( 41 | key: key, 42 | state: state, 43 | reverse: state.reverse, 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /styles/easy_refresh_halloween/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: easy_refresh_halloween 2 | description: Halloween Indicator on EasyRefresh. Provides HalloweenHeader and HalloweenFooter. Animation with Rive. 3 | version: 1.0.2 4 | homepage: https://xuelongqy.github.io/flutter_easy_refresh/#/style/halloween 5 | repository: https://github.com/xuelongqy/flutter_easy_refresh/tree/v3/styles/easy_refresh_halloween 6 | issue_tracker: https://github.com/xuelongqy/flutter_easy_refresh/issues 7 | 8 | environment: 9 | sdk: ">=2.13.0 <3.0.0" 10 | flutter: ">=1.24.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | rive: any 16 | easy_refresh: 17 | path: ../../ 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^2.0.1 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://dart.dev/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter packages. 28 | flutter: 29 | 30 | # To add assets to your package, add an assets section, like this: 31 | assets: 32 | - assets/halloween.riv 33 | # 34 | # For details regarding assets in packages, see 35 | # https://flutter.dev/assets-and-images/#from-packages 36 | # 37 | # An image asset can refer to one or more resolution-specific "variants", see 38 | # https://flutter.dev/assets-and-images/#resolution-aware 39 | 40 | # To add custom fonts to your package, add a fonts section here, 41 | # in this "flutter" section. Each entry in this list should have a 42 | # "family" key with the font family name, and a "fonts" key with a 43 | # list giving the asset and other descriptors for the font. For 44 | # example: 45 | # fonts: 46 | # - family: Schyler 47 | # fonts: 48 | # - asset: fonts/Schyler-Regular.ttf 49 | # - asset: fonts/Schyler-Italic.ttf 50 | # style: italic 51 | # - family: Trajan Pro 52 | # fonts: 53 | # - asset: fonts/TrajanPro.ttf 54 | # - asset: fonts/TrajanPro_Bold.ttf 55 | # weight: 700 56 | # 57 | # For details regarding fonts in packages, see 58 | # https://flutter.dev/custom-fonts/#from-packages 59 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 2 | - chore: update dependencies. 3 | 4 | ## 1.0.1 5 | - perf: Optimize animation loading. 6 | 7 | ## 1.0.0+1 8 | - fix: dart >=2.13.0. 9 | 10 | ## 1.0.0 11 | - Skating Indicator on EasyRefresh. 12 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 xuelongqy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/README.md: -------------------------------------------------------------------------------- 1 | # Skating Indicator on EasyRefresh. 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](/LICENSE) 4 | [![Pub](https://img.shields.io/pub/v/easy_refresh_skating](https://pub.flutter-io.cn/packages/easy_refresh_skating) 5 | 6 | ### [Online demo](https://xuelongqy.github.io/flutter_easy_refresh/#/style/skating) 7 | Animation from [Pull-to-refresh Animation Example](https://rive.app/community/2233-4412-pull-to-refresh-animation-example) 8 | 9 | ## Features 10 | 11 | SkatingHeader and SkatingFooter. 12 | 13 | ## Getting started 14 | 15 | ``` 16 | dependencies: 17 | flutter_easyre_fresh: version 18 | easy_refresh_skating: version 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```dart 24 | EasyRefresh( 25 | header: SkatingHeader(), 26 | footer: SkatingFooter(), 27 | onRefresh: () async {}, 28 | onLoad: () async {}, 29 | child: ListView(), 30 | ) 31 | ``` 32 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/assets/skating.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/styles/easy_refresh_skating/assets/skating.riv -------------------------------------------------------------------------------- /styles/easy_refresh_skating/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_skating/easy_refresh_skating.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:easy_refresh/easy_refresh.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const MaterialApp( 13 | title: 'Skating', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | const HomePage({Key? key}) : super(key: key); 21 | 22 | @override 23 | State createState() => _HomePageState(); 24 | } 25 | 26 | class _HomePageState extends State { 27 | int _count = 10; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: const Text('Skating'), 34 | ), 35 | body: EasyRefresh( 36 | header: const SkatingHeader(), 37 | footer: const SkatingFooter(), 38 | onRefresh: () async { 39 | await Future.delayed(const Duration(seconds: 4)); 40 | if (!mounted) { 41 | return; 42 | } 43 | setState(() { 44 | _count = 10; 45 | }); 46 | }, 47 | onLoad: () async { 48 | await Future.delayed(const Duration(seconds: 4)); 49 | if (!mounted) { 50 | return; 51 | } 52 | setState(() { 53 | _count += 5; 54 | }); 55 | }, 56 | child: ListView.builder( 57 | itemBuilder: (context, index) { 58 | return Card( 59 | child: Container( 60 | alignment: Alignment.center, 61 | height: 80, 62 | child: Text('${index + 1}'), 63 | ), 64 | ); 65 | }, 66 | itemCount: _count, 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/lib/easy_refresh_skating.dart: -------------------------------------------------------------------------------- 1 | library easy_refresh_skating; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/physics.dart' as physics; 5 | import 'package:easy_refresh/easy_refresh.dart'; 6 | import 'package:rive/rive.dart'; 7 | 8 | part 'src/skating_indicator.dart'; 9 | part 'src/skating_header.dart'; 10 | part 'src/skating_footer.dart'; 11 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/lib/src/skating_footer.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_skating; 2 | 3 | class SkatingFooter extends Footer { 4 | final Key? key; 5 | 6 | const SkatingFooter({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultSkatingTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | physics.SpringDescription? spring, 12 | SpringBuilder? readySpringBuilder, 13 | bool springRebound = false, 14 | FrictionFactor? frictionFactor, 15 | double? infiniteOffset, 16 | bool? hitOver, 17 | bool? infiniteHitOver, 18 | bool hapticFeedback = false, 19 | }) : super( 20 | triggerOffset: triggerOffset, 21 | clamping: clamping, 22 | processedDuration: _kSkatingProcessed, 23 | spring: spring, 24 | readySpringBuilder: readySpringBuilder, 25 | springRebound: springRebound, 26 | frictionFactor: frictionFactor, 27 | safeArea: false, 28 | infiniteOffset: infiniteOffset, 29 | hitOver: hitOver, 30 | infiniteHitOver: infiniteHitOver, 31 | position: position, 32 | hapticFeedback: hapticFeedback, 33 | ); 34 | 35 | @override 36 | Widget build(BuildContext context, IndicatorState state) { 37 | assert(state.axis == Axis.vertical, 38 | 'SkatingFooter does not support horizontal scrolling.'); 39 | return _SkatingIndicator( 40 | key: key, 41 | state: state, 42 | reverse: state.reverse, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/lib/src/skating_header.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_skating; 2 | 3 | class SkatingHeader extends Header { 4 | final Key? key; 5 | 6 | const SkatingHeader({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultSkatingTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | physics.SpringDescription? spring, 12 | SpringBuilder? readySpringBuilder, 13 | bool springRebound = false, 14 | FrictionFactor? frictionFactor, 15 | double? infiniteOffset, 16 | bool? hitOver, 17 | bool? infiniteHitOver, 18 | bool hapticFeedback = false, 19 | }) : super( 20 | triggerOffset: triggerOffset, 21 | clamping: clamping, 22 | processedDuration: _kSkatingProcessed, 23 | spring: spring, 24 | readySpringBuilder: readySpringBuilder, 25 | springRebound: springRebound, 26 | frictionFactor: frictionFactor, 27 | safeArea: false, 28 | infiniteOffset: infiniteOffset, 29 | hitOver: hitOver, 30 | infiniteHitOver: infiniteHitOver, 31 | position: position, 32 | hapticFeedback: hapticFeedback, 33 | ); 34 | 35 | @override 36 | Widget build(BuildContext context, IndicatorState state) { 37 | assert(state.axis == Axis.vertical, 38 | 'SkatingHeader does not support horizontal scrolling.'); 39 | return _SkatingIndicator( 40 | key: key, 41 | state: state, 42 | reverse: state.reverse, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /styles/easy_refresh_skating/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: easy_refresh_skating 2 | description: Skating Indicator on EasyRefresh. Provides SkatingHeader and SkatingFooter. Animation with Rive. 3 | version: 1.0.2 4 | homepage: https://xuelongqy.github.io/flutter_easy_refresh/#/style/skating 5 | repository: https://github.com/xuelongqy/flutter_easy_refresh/tree/v3/styles/easy_refresh_skating 6 | issue_tracker: https://github.com/xuelongqy/flutter_easy_refresh/issues 7 | 8 | environment: 9 | sdk: ">=2.13.0 <3.0.0" 10 | flutter: ">=1.24.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | rive: any 16 | easy_refresh: 17 | path: ../../ 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^2.0.1 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://dart.dev/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter packages. 28 | flutter: 29 | 30 | # To add assets to your package, add an assets section, like this: 31 | assets: 32 | - assets/skating.riv 33 | # 34 | # For details regarding assets in packages, see 35 | # https://flutter.dev/assets-and-images/#from-packages 36 | # 37 | # An image asset can refer to one or more resolution-specific "variants", see 38 | # https://flutter.dev/assets-and-images/#resolution-aware 39 | 40 | # To add custom fonts to your package, add a fonts section here, 41 | # in this "flutter" section. Each entry in this list should have a 42 | # "family" key with the font family name, and a "fonts" key with a 43 | # list giving the asset and other descriptors for the font. For 44 | # example: 45 | # fonts: 46 | # - family: Schyler 47 | # fonts: 48 | # - asset: fonts/Schyler-Regular.ttf 49 | # - asset: fonts/Schyler-Italic.ttf 50 | # style: italic 51 | # - family: Trajan Pro 52 | # fonts: 53 | # - asset: fonts/TrajanPro.ttf 54 | # - asset: fonts/TrajanPro_Bold.ttf 55 | # weight: 700 56 | # 57 | # For details regarding fonts in packages, see 58 | # https://flutter.dev/custom-fonts/#from-packages 59 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 2 | - chore: update dependencies. 3 | 4 | ## 1.0.1 5 | - feat: Migrate to rive animation. 6 | 7 | ## 1.0.0+1 8 | - fix: dart >=2.13.0. 9 | 10 | ## 1.0.0 11 | - Space Indicator on EasyRefresh. 12 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 xuelongqy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/README.md: -------------------------------------------------------------------------------- 1 | # Space Indicator on EasyRefresh. 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](/LICENSE) 4 | [![Pub](https://img.shields.io/pub/v/easy_refresh_space)](https://pub.flutter-io.cn/packages/easy_refresh_space) 5 | 6 | ### [Online demo](https://xuelongqy.github.io/flutter_easy_refresh/#/style/space) 7 | Animation from [Flare-Flutter](https://github.com/2d-inc/Flare-Flutter) 8 | 9 | ## Features 10 | 11 | SpaceHeader and SpaceFooter. 12 | 13 | ## Getting started 14 | 15 | ``` 16 | dependencies: 17 | flutter_easyre_fresh: version 18 | easy_refresh_space: version 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```dart 24 | EasyRefresh( 25 | header: SpaceHeader(), 26 | footer: SpaceFooter(), 27 | onRefresh: () async {}, 28 | onLoad: () async {}, 29 | child: ListView(), 30 | ) 31 | ``` 32 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/assets/space_reload.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/styles/easy_refresh_space/assets/space_reload.riv -------------------------------------------------------------------------------- /styles/easy_refresh_space/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_space/easy_refresh_space.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:easy_refresh/easy_refresh.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const MaterialApp( 13 | title: 'Space', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | const HomePage({Key? key}) : super(key: key); 21 | 22 | @override 23 | State createState() => _HomePageState(); 24 | } 25 | 26 | class _HomePageState extends State { 27 | int _count = 10; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: const Text('Space'), 34 | ), 35 | body: EasyRefresh( 36 | header: const SpaceHeader(), 37 | footer: const SpaceFooter(), 38 | onRefresh: () async { 39 | await Future.delayed(const Duration(seconds: 4)); 40 | if (!mounted) { 41 | return; 42 | } 43 | setState(() { 44 | _count = 10; 45 | }); 46 | }, 47 | onLoad: () async { 48 | await Future.delayed(const Duration(seconds: 4)); 49 | if (!mounted) { 50 | return; 51 | } 52 | setState(() { 53 | _count += 5; 54 | }); 55 | }, 56 | child: ListView.builder( 57 | itemBuilder: (context, index) { 58 | return Card( 59 | child: Container( 60 | alignment: Alignment.center, 61 | height: 80, 62 | child: Text('${index + 1}'), 63 | ), 64 | ); 65 | }, 66 | itemCount: _count, 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/lib/easy_refresh_space.dart: -------------------------------------------------------------------------------- 1 | library easy_refresh_space; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/physics.dart' as physics; 5 | import 'package:easy_refresh/easy_refresh.dart'; 6 | import 'package:rive/rive.dart'; 7 | 8 | part 'src/space_indicator.dart'; 9 | part 'src/space_header.dart'; 10 | part 'src/space_footer.dart'; 11 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/lib/src/space_footer.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_space; 2 | 3 | class SpaceFooter extends Footer { 4 | final Key? key; 5 | 6 | const SpaceFooter({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultSpaceTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | Duration processedDuration = Duration.zero, 12 | physics.SpringDescription? spring, 13 | SpringBuilder? readySpringBuilder, 14 | bool springRebound = false, 15 | FrictionFactor? frictionFactor, 16 | double? infiniteOffset, 17 | bool? hitOver, 18 | bool? infiniteHitOver, 19 | bool hapticFeedback = false, 20 | }) : super( 21 | triggerOffset: triggerOffset, 22 | clamping: clamping, 23 | processedDuration: processedDuration, 24 | spring: spring, 25 | readySpringBuilder: readySpringBuilder, 26 | springRebound: springRebound, 27 | frictionFactor: frictionFactor, 28 | safeArea: false, 29 | infiniteOffset: infiniteOffset, 30 | hitOver: hitOver, 31 | infiniteHitOver: infiniteHitOver, 32 | position: position, 33 | hapticFeedback: hapticFeedback, 34 | ); 35 | 36 | @override 37 | Widget build(BuildContext context, IndicatorState state) { 38 | assert(state.axis == Axis.vertical, 39 | 'SpaceFooter does not support horizontal scrolling.'); 40 | return _SpaceIndicator( 41 | key: key, 42 | state: state, 43 | reverse: state.reverse, 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/lib/src/space_header.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_space; 2 | 3 | class SpaceHeader extends Header { 4 | final Key? key; 5 | 6 | const SpaceHeader({ 7 | this.key, 8 | bool clamping = false, 9 | double triggerOffset = _kDefaultSpaceTriggerOffset, 10 | IndicatorPosition position = IndicatorPosition.above, 11 | Duration processedDuration = Duration.zero, 12 | physics.SpringDescription? spring, 13 | SpringBuilder? readySpringBuilder, 14 | bool springRebound = false, 15 | FrictionFactor? frictionFactor, 16 | double? infiniteOffset, 17 | bool? hitOver, 18 | bool? infiniteHitOver, 19 | bool hapticFeedback = false, 20 | }) : super( 21 | triggerOffset: triggerOffset, 22 | clamping: clamping, 23 | processedDuration: processedDuration, 24 | spring: spring, 25 | readySpringBuilder: readySpringBuilder, 26 | springRebound: springRebound, 27 | frictionFactor: frictionFactor, 28 | safeArea: false, 29 | infiniteOffset: infiniteOffset, 30 | hitOver: hitOver, 31 | infiniteHitOver: infiniteHitOver, 32 | position: position, 33 | hapticFeedback: hapticFeedback, 34 | ); 35 | 36 | @override 37 | Widget build(BuildContext context, IndicatorState state) { 38 | assert(state.axis == Axis.vertical, 39 | 'SpaceHeader does not support horizontal scrolling.'); 40 | return _SpaceIndicator( 41 | key: key, 42 | state: state, 43 | reverse: state.reverse, 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /styles/easy_refresh_space/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: easy_refresh_space 2 | description: Space Indicator on EasyRefresh. Provides SpaceHeader and SpaceFooter. Animation with Rive. 3 | version: 1.0.2 4 | homepage: https://xuelongqy.github.io/flutter_easy_refresh/#/style/space 5 | repository: https://github.com/xuelongqy/flutter_easy_refresh/tree/v3/styles/easy_refresh_space 6 | issue_tracker: https://github.com/xuelongqy/flutter_easy_refresh/issues 7 | 8 | environment: 9 | sdk: ">=2.13.0 <3.0.0" 10 | flutter: ">=1.24.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | rive: any 16 | easy_refresh: 17 | path: ../../ 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^2.0.1 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://dart.dev/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter packages. 28 | flutter: 29 | 30 | # To add assets to your package, add an assets section, like this: 31 | assets: 32 | - assets/space_reload.riv 33 | # 34 | # For details regarding assets in packages, see 35 | # https://flutter.dev/assets-and-images/#from-packages 36 | # 37 | # An image asset can refer to one or more resolution-specific "variants", see 38 | # https://flutter.dev/assets-and-images/#resolution-aware 39 | 40 | # To add custom fonts to your package, add a fonts section here, 41 | # in this "flutter" section. Each entry in this list should have a 42 | # "family" key with the font family name, and a "fonts" key with a 43 | # list giving the asset and other descriptors for the font. For 44 | # example: 45 | # fonts: 46 | # - family: Schyler 47 | # fonts: 48 | # - asset: fonts/Schyler-Regular.ttf 49 | # - asset: fonts/Schyler-Italic.ttf 50 | # style: italic 51 | # - family: Trajan Pro 52 | # fonts: 53 | # - asset: fonts/TrajanPro.ttf 54 | # - asset: fonts/TrajanPro_Bold.ttf 55 | # weight: 700 56 | # 57 | # For details regarding fonts in packages, see 58 | # https://flutter.dev/custom-fonts/#from-packages 59 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2 2 | - chore: update dependencies. 3 | 4 | ## 1.0.1 5 | - docs: Update docs. 6 | 7 | ## 1.0.0+1 8 | - fix: dart >=2.13.0. 9 | 10 | ## 1.0.0 11 | - Squats Indicator on EasyRefresh. 12 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 xuelongqy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/README.md: -------------------------------------------------------------------------------- 1 | # Squats Indicator on EasyRefresh. 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](/LICENSE) 4 | [![Pub](https://img.shields.io/pub/v/easy_refresh_squats)](https://pub.flutter-io.cn/packages/easy_refresh_squats) 5 | 6 | ### [Online demo](https://xuelongqy.github.io/flutter_easy_refresh/#/style/squats) 7 | Animation from [Lumberjack Squats](https://rive.app/community/980-1894-lumberjack-squats) 8 | 9 | ## Features 10 | 11 | SquatsHeader and SquatsFooter. 12 | 13 | ## Getting started 14 | 15 | ``` 16 | dependencies: 17 | flutter_easyre_fresh: version 18 | easy_refresh_squats: version 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```dart 24 | EasyRefresh( 25 | header: SquatsHeader(), 26 | footer: SquatsFooter(), 27 | onRefresh: () async {}, 28 | onLoad: () async {}, 29 | child: ListView(), 30 | ) 31 | ``` 32 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/assets/lumberjack_squats.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuelongqy/flutter_easy_refresh/2a8a08ef29f890ba65c8f2f020e8b54943c1ae75/styles/easy_refresh_squats/assets/lumberjack_squats.riv -------------------------------------------------------------------------------- /styles/easy_refresh_squats/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:easy_refresh_squats/easy_refresh_squats.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:easy_refresh/easy_refresh.dart'; 4 | 5 | void main() => runApp(const MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | const MyApp({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return const MaterialApp( 13 | title: 'Squats', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | 19 | class HomePage extends StatefulWidget { 20 | const HomePage({Key? key}) : super(key: key); 21 | 22 | @override 23 | State createState() => _HomePageState(); 24 | } 25 | 26 | class _HomePageState extends State { 27 | int _count = 10; 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | appBar: AppBar( 33 | title: const Text('Squats'), 34 | ), 35 | body: EasyRefresh( 36 | header: const SquatsHeader(), 37 | footer: const SquatsFooter(), 38 | onRefresh: () async { 39 | await Future.delayed(const Duration(seconds: 4)); 40 | if (!mounted) { 41 | return; 42 | } 43 | setState(() { 44 | _count = 10; 45 | }); 46 | }, 47 | onLoad: () async { 48 | await Future.delayed(const Duration(seconds: 4)); 49 | if (!mounted) { 50 | return; 51 | } 52 | setState(() { 53 | _count += 5; 54 | }); 55 | }, 56 | child: ListView.builder( 57 | itemBuilder: (context, index) { 58 | return Card( 59 | child: Container( 60 | alignment: Alignment.center, 61 | height: 80, 62 | child: Text('${index + 1}'), 63 | ), 64 | ); 65 | }, 66 | itemCount: _count, 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/lib/easy_refresh_squats.dart: -------------------------------------------------------------------------------- 1 | library easy_refresh_squats; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/physics.dart' as physics; 5 | import 'package:easy_refresh/easy_refresh.dart'; 6 | import 'package:rive/rive.dart'; 7 | 8 | part 'src/squats_indicator.dart'; 9 | part 'src/squats_header.dart'; 10 | part 'src/squats_footer.dart'; 11 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/lib/src/squats_footer.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_squats; 2 | 3 | class SquatsFooter extends Footer { 4 | final Key? key; 5 | 6 | /// Background color. 7 | final Color? backgroundColor; 8 | 9 | const SquatsFooter({ 10 | this.key, 11 | bool clamping = false, 12 | double triggerOffset = _kDefaultSquatsTriggerOffset, 13 | IndicatorPosition position = IndicatorPosition.above, 14 | Duration processedDuration = Duration.zero, 15 | physics.SpringDescription? spring, 16 | SpringBuilder? readySpringBuilder, 17 | bool springRebound = false, 18 | FrictionFactor? frictionFactor, 19 | double? infiniteOffset, 20 | bool? hitOver, 21 | bool? infiniteHitOver, 22 | bool hapticFeedback = false, 23 | this.backgroundColor, 24 | }) : super( 25 | triggerOffset: triggerOffset, 26 | clamping: clamping, 27 | processedDuration: processedDuration, 28 | spring: spring, 29 | readySpringBuilder: readySpringBuilder, 30 | springRebound: springRebound, 31 | frictionFactor: frictionFactor, 32 | safeArea: false, 33 | infiniteOffset: infiniteOffset, 34 | hitOver: hitOver, 35 | infiniteHitOver: infiniteHitOver, 36 | position: position, 37 | hapticFeedback: hapticFeedback, 38 | ); 39 | 40 | @override 41 | Widget build(BuildContext context, IndicatorState state) { 42 | assert(state.axis == Axis.vertical, 43 | 'SquatsFooter does not support horizontal scrolling.'); 44 | return _SquatsIndicator( 45 | key: key, 46 | state: state, 47 | reverse: state.reverse, 48 | backgroundColor: backgroundColor, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/lib/src/squats_header.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_squats; 2 | 3 | class SquatsHeader extends Header { 4 | final Key? key; 5 | 6 | /// Background color. 7 | final Color? backgroundColor; 8 | 9 | const SquatsHeader({ 10 | this.key, 11 | bool clamping = false, 12 | double triggerOffset = _kDefaultSquatsTriggerOffset, 13 | IndicatorPosition position = IndicatorPosition.above, 14 | Duration processedDuration = Duration.zero, 15 | physics.SpringDescription? spring, 16 | SpringBuilder? readySpringBuilder, 17 | bool springRebound = false, 18 | FrictionFactor? frictionFactor, 19 | double? infiniteOffset, 20 | bool? hitOver, 21 | bool? infiniteHitOver, 22 | bool hapticFeedback = false, 23 | this.backgroundColor, 24 | }) : super( 25 | triggerOffset: triggerOffset, 26 | clamping: clamping, 27 | processedDuration: processedDuration, 28 | spring: spring, 29 | readySpringBuilder: readySpringBuilder, 30 | springRebound: springRebound, 31 | frictionFactor: frictionFactor, 32 | safeArea: false, 33 | infiniteOffset: infiniteOffset, 34 | hitOver: hitOver, 35 | infiniteHitOver: infiniteHitOver, 36 | position: position, 37 | hapticFeedback: hapticFeedback, 38 | ); 39 | 40 | @override 41 | Widget build(BuildContext context, IndicatorState state) { 42 | assert(state.axis == Axis.vertical, 43 | 'SquatsHeader does not support horizontal scrolling.'); 44 | return _SquatsIndicator( 45 | key: key, 46 | state: state, 47 | reverse: state.reverse, 48 | backgroundColor: backgroundColor, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/lib/src/squats_indicator.dart: -------------------------------------------------------------------------------- 1 | part of easy_refresh_squats; 2 | 3 | const _kDefaultSquatsTriggerOffset = 190.0; 4 | 5 | /// Squats indicator. 6 | /// Base widget for [SquatsHeader] and [SquatsFooter]. 7 | class _SquatsIndicator extends StatefulWidget { 8 | /// Indicator properties and state. 9 | final IndicatorState state; 10 | 11 | /// True for up and left. 12 | /// False for down and right. 13 | final bool reverse; 14 | 15 | /// Background color. 16 | final Color? backgroundColor; 17 | 18 | const _SquatsIndicator({ 19 | Key? key, 20 | required this.state, 21 | required this.reverse, 22 | this.backgroundColor, 23 | }) : super(key: key); 24 | 25 | @override 26 | State<_SquatsIndicator> createState() => _SquatsIndicatorState(); 27 | } 28 | 29 | class _SquatsIndicatorState extends State<_SquatsIndicator> { 30 | late SimpleAnimation _idleController; 31 | late SimpleAnimation _squatsController; 32 | 33 | double get _offset => widget.state.offset; 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | _idleController = SimpleAnimation('Idle'); 39 | _squatsController = SimpleAnimation('Demo'); 40 | widget.state.notifier.addModeChangeListener(_onModeChange); 41 | } 42 | 43 | @override 44 | void dispose() { 45 | widget.state.notifier.removeModeChangeListener(_onModeChange); 46 | _idleController.dispose(); 47 | _squatsController.dispose(); 48 | super.dispose(); 49 | } 50 | 51 | /// Mode change listener. 52 | void _onModeChange(IndicatorMode mode, double offset) { 53 | if (mode == IndicatorMode.processing || 54 | mode == IndicatorMode.processed || 55 | mode == IndicatorMode.done) { 56 | if (_idleController.isActive) { 57 | _idleController.isActive = false; 58 | _idleController.reset(); 59 | } 60 | if (!_squatsController.isActive) { 61 | _squatsController.isActive = true; 62 | } 63 | } else { 64 | if (_squatsController.isActive) { 65 | _squatsController.isActive = false; 66 | _squatsController.reset(); 67 | } 68 | if (!_idleController.isActive) { 69 | _idleController.isActive = true; 70 | } 71 | } 72 | } 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | return Container( 77 | alignment: Alignment.center, 78 | width: double.infinity, 79 | height: _offset, 80 | color: widget.backgroundColor, 81 | child: SizedBox( 82 | width: _offset > 214 ? null : 214, 83 | height: _offset, 84 | child: RiveAnimation.asset( 85 | 'packages/easy_refresh_squats/assets/lumberjack_squats.riv', 86 | controllers: [ 87 | _squatsController, 88 | _idleController, 89 | ], 90 | fit: _offset > 214 ? BoxFit.fitHeight : BoxFit.fitWidth, 91 | ), 92 | ), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /styles/easy_refresh_squats/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: easy_refresh_squats 2 | description: Squats Indicator on EasyRefresh. Provides SquatsHeader and SquatsFooter. Animation with Rive. 3 | version: 1.0.2 4 | homepage: https://xuelongqy.github.io/flutter_easy_refresh/#/style/squats 5 | repository: https://github.com/xuelongqy/flutter_easy_refresh/tree/v3/styles/easy_refresh_squats 6 | issue_tracker: https://github.com/xuelongqy/flutter_easy_refresh/issues 7 | 8 | environment: 9 | sdk: ">=2.13.0 <3.0.0" 10 | flutter: ">=1.24.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | rive: any 16 | easy_refresh: 17 | path: ../../ 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | flutter_lints: ^2.0.1 23 | 24 | # For information on the generic Dart part of this file, see the 25 | # following page: https://dart.dev/tools/pub/pubspec 26 | 27 | # The following section is specific to Flutter packages. 28 | flutter: 29 | 30 | # To add assets to your package, add an assets section, like this: 31 | assets: 32 | - assets/lumberjack_squats.riv 33 | # 34 | # For details regarding assets in packages, see 35 | # https://flutter.dev/assets-and-images/#from-packages 36 | # 37 | # An image asset can refer to one or more resolution-specific "variants", see 38 | # https://flutter.dev/assets-and-images/#resolution-aware 39 | 40 | # To add custom fonts to your package, add a fonts section here, 41 | # in this "flutter" section. Each entry in this list should have a 42 | # "family" key with the font family name, and a "fonts" key with a 43 | # list giving the asset and other descriptors for the font. For 44 | # example: 45 | # fonts: 46 | # - family: Schyler 47 | # fonts: 48 | # - asset: fonts/Schyler-Regular.ttf 49 | # - asset: fonts/Schyler-Italic.ttf 50 | # style: italic 51 | # - family: Trajan Pro 52 | # fonts: 53 | # - asset: fonts/TrajanPro.ttf 54 | # - asset: fonts/TrajanPro_Bold.ttf 55 | # weight: 700 56 | # 57 | # For details regarding fonts in packages, see 58 | # https://flutter.dev/custom-fonts/#from-packages 59 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | void main() { 12 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 13 | // Build our app and trigger a frame. 14 | 15 | // Verify that our counter starts at 0. 16 | expect(find.text('0'), findsOneWidget); 17 | expect(find.text('1'), findsNothing); 18 | 19 | // Tap the '+' icon and trigger a frame. 20 | await tester.tap(find.byIcon(Icons.add)); 21 | await tester.pump(); 22 | 23 | // Verify that our counter has incremented. 24 | expect(find.text('0'), findsNothing); 25 | expect(find.text('1'), findsOneWidget); 26 | }); 27 | } 28 | --------------------------------------------------------------------------------