├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── 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-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── project.pbxproj
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
└── Podfile
├── web
├── favicon.png
├── manifest.json
└── index.html
├── android
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── 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
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── nicomama
│ │ │ │ │ └── flutter_sample
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
└── build.gradle
├── macos
├── Runner
│ ├── Configs
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ ├── Warnings.xcconfig
│ │ └── AppInfo.xcconfig
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── app_icon_128.png
│ │ │ ├── app_icon_16.png
│ │ │ ├── app_icon_256.png
│ │ │ ├── app_icon_32.png
│ │ │ ├── app_icon_512.png
│ │ │ ├── app_icon_64.png
│ │ │ ├── app_icon_1024.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Release.entitlements
│ ├── DebugProfile.entitlements
│ ├── MainFlutterWindow.swift
│ ├── Info.plist
│ └── Base.lproj
│ │ └── MainMenu.xib
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Podfile.lock
└── Podfile
├── lib
├── provider
│ ├── post
│ │ ├── list
│ │ │ ├── post_item_notifier.dart
│ │ │ ├── post_item_widget.dart
│ │ │ ├── post_item_widget2.dart
│ │ │ ├── post_list_model.dart
│ │ │ └── post_list_widget.dart
│ │ ├── base
│ │ │ ├── eventbus_x.dart
│ │ │ ├── slide_page_route.dart
│ │ │ └── item_refresher.dart
│ │ ├── data
│ │ │ ├── post_bean.dart
│ │ │ └── post_server.dart
│ │ └── detail
│ │ │ ├── post_detail_model.dart
│ │ │ └── post_detail_widget.dart
│ ├── set_state_demo_widget.dart
│ ├── provider_demo_widget1.dart
│ ├── provider_demo_widget4.dart
│ ├── selector
│ │ └── selector_demo_widget.dart
│ ├── provider_demo_widget3.dart
│ └── provider_demo_widget2.dart
├── generated
│ └── json
│ │ └── base
│ │ └── json_filed.dart
├── stream
│ ├── main_stream.dart
│ ├── stream3_create_stream_by_streamcontroller.dart
│ ├── stream4_receving_stream_by_await_for.dart
│ ├── stream2_create_stream_by_future.dart
│ ├── stream5_two_kind_stream.dart
│ ├── stream1_simple_use.dart
│ ├── stream7_stream_to_stream.dart
│ ├── stream6_stream_to_future.dart
│ └── stream8_stream_transformer.dart
├── generated_plugin_registrant.dart
├── bottom_input
│ ├── input_dialog.dart
│ └── input_widget.dart
├── main_eventbus.dart
├── main_bottom_input.dart
├── main_provider.dart
├── main.dart
├── statemanager
│ ├── scoped_model_widget.dart
│ ├── provider_widget.dart
│ ├── bloc_widget.dart
│ ├── bloc_rxdart_widget.dart
│ ├── redux_widget.dart
│ ├── inherited_widget.dart
│ └── inherited_notifier_widget.dart
└── eventbus
│ ├── my_event_bus.dart
│ ├── eventbus_demo_widget1.dart
│ └── eventbus_demo_widget2.dart
├── .metadata
├── test
└── widget_test.dart
├── README.md
├── analysis_options.yaml
├── .gitignore
└── pubspec.yaml
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlvinScrp/flutter_sample/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/nicomama/flutter_sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nicomama.flutter_sample
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/provider/post/list/post_item_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter_sample/provider/post/data/post_bean.dart';
3 |
4 | class PostNotifier with ChangeNotifier {
5 | late int id;
6 | }
7 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 |
9 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
10 | }
11 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
7 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: c382b8e990b6976f610764179f94e0416d82c057
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/generated/json/base/json_filed.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: non_constant_identifier_names
2 | // ignore_for_file: camel_case_types
3 | // ignore_for_file: prefer_single_quotes
4 |
5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost.
6 |
7 | class JSONField {
8 | final String name;
9 |
10 | const JSONField(this.name);
11 | }
12 |
--------------------------------------------------------------------------------
/lib/stream/main_stream.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | main() {
4 | // ignore: close_sinks
5 | var _streamController = new StreamController();
6 | _streamController.stream.listen((event) => print("$event"));
7 | // _streamController.stream.listen((event) => print("$event"));
8 | _streamController.sink.add(100);
9 | _streamController.add("xxx");
10 | }
11 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/macos/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FlutterMacOS (1.0.0)
3 |
4 | DEPENDENCIES:
5 | - FlutterMacOS (from `Flutter/ephemeral`)
6 |
7 | EXTERNAL SOURCES:
8 | FlutterMacOS:
9 | :path: Flutter/ephemeral
10 |
11 | SPEC CHECKSUMS:
12 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
13 |
14 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
15 |
16 | COCOAPODS: 1.11.2
17 |
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/lib/provider/post/base/eventbus_x.dart:
--------------------------------------------------------------------------------
1 | import 'package:event_bus/event_bus.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | EventBus eventBus = EventBus();
5 |
6 | class BaseEvent {
7 | void fire() {
8 | eventBus.fire(this);
9 | }
10 | }
11 |
12 | class PostLikeEvent extends BaseEvent {
13 | int id;
14 | bool isLike;
15 |
16 | PostLikeEvent(this.id, this.isLike);
17 | }
18 |
--------------------------------------------------------------------------------
/lib/stream/stream3_create_stream_by_streamcontroller.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | main() {
4 | var controller = StreamController();
5 | controller.stream.listen(_onData, onDone: _onDone);
6 | controller.add(1);
7 | controller.add(2);
8 | controller.add(3);
9 | controller.close();
10 | }
11 |
12 | void _onData(int event) => print("$event");
13 |
14 | void _onDone() => print("onDone");
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/stream/stream4_receving_stream_by_await_for.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | Stream countStream(int to) async* {
4 | for (int i = 1; i < to; i++) yield i;
5 | }
6 |
7 | Future sumStream(Stream stream) async {
8 | var sum = 0;
9 | await for (var value in stream) {
10 | print("$value");
11 | sum += value;
12 | }
13 | return sum;
14 | }
15 |
16 | main() async {
17 | var sum = await sumStream(countStream(5));
18 | print("sum:$sum");
19 | }
20 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/generated_plugin_registrant.dart:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // ignore_for_file: directives_ordering
6 | // ignore_for_file: lines_longer_than_80_chars
7 |
8 | import 'package:video_player_web/video_player_web.dart';
9 |
10 | import 'package:flutter_web_plugins/flutter_web_plugins.dart';
11 |
12 | // ignore: public_member_api_docs
13 | void registerPlugins(Registrar registrar) {
14 | VideoPlayerPlugin.registerWith(registrar);
15 | registrar.registerMessageHandler();
16 | }
17 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/provider/post/data/post_bean.dart:
--------------------------------------------------------------------------------
1 | /// id : 1
2 | /// content : "sdsdsd"
3 | /// isLike : false
4 |
5 | class PostBean {
6 | int id = 0;
7 | String content = "";
8 | bool isLike = false;
9 |
10 | PostBean.value(this.id, this.isLike, this.content);
11 |
12 | PostBean(this.id, this.content, this.isLike);
13 |
14 | PostBean.map(dynamic obj) {
15 | id = obj["id"];
16 | content = obj["content"];
17 | isLike = obj["isLike"];
18 | }
19 |
20 | Map toMap() {
21 | var map = {};
22 | map["id"] = id;
23 | map["content"] = content;
24 | map["isLike"] = isLike;
25 | return map;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/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 = flutter_sample
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.nicomama.flutterSample
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2022 com.nicomama. All rights reserved.
15 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/lib/stream/stream2_create_stream_by_future.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | //创建一个Future,延迟毫秒数,返回整数i
4 | Future createFuture(int delayMilliseconds, int i) {
5 | return Future.delayed(Duration(milliseconds: delayMilliseconds))
6 | .then((value) => i);
7 | }
8 |
9 | Stream streamFromFutures(Iterable> futures) async* {
10 | for (var future in futures) {
11 | //请求future 并返回future的结果给Stream
12 | var result = await future;
13 | yield result;
14 | }
15 | }
16 |
17 | main() {
18 | List values = [0, 1, 2, 3, 4];
19 | List> futures =
20 | values.map((i) => createFuture(i * 200, i)).toList();
21 | Stream stream = streamFromFutures(futures);
22 | stream.listen(_onData, onDone: _onDone);
23 | }
24 |
25 | void _onData(int event) => print("$event");
26 |
27 | void _onDone() => print("onDone");
28 |
--------------------------------------------------------------------------------
/lib/stream/stream5_two_kind_stream.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | main() {
4 | broadcastStreamsTest();
5 | singleSubscriptionStreamsTest();
6 | }
7 |
8 | void broadcastStreamsTest() {
9 | //此时返回的是 _AsyncBroadcastStreamController,广播流
10 | var _streamController = StreamController.broadcast();
11 | _streamController.stream.listen((event) => print("$event"));
12 | _streamController.stream.listen((event) => print("$event"));
13 | _streamController.sink.add(100);
14 | _streamController.close();
15 | }
16 |
17 | void singleSubscriptionStreamsTest() {
18 | //此时返回的是 _AsyncStreamController,单订阅者流
19 | var _streamController = StreamController();
20 | _streamController.stream.listen((event) => print("$event"));
21 | _streamController.stream.listen((event) => print("$event"));
22 | _streamController.sink.add(100);
23 | _streamController.close();
24 | }
25 |
--------------------------------------------------------------------------------
/lib/stream/stream1_simple_use.dart:
--------------------------------------------------------------------------------
1 | //周期性发送整数Stream,当使用yield时,向Stream提交事件(一个整数)
2 | import 'dart:async';
3 |
4 | Stream timedCounter(Duration interval, [int maxCount = 0]) async* {
5 | int i = 0;
6 | while (true) {
7 | await Future.delayed(interval);
8 | yield i++;
9 | if (i == maxCount) break;
10 | }
11 | }
12 |
13 | main() {
14 | Stream stream = timedCounter(Duration(milliseconds: 200), 5);
15 | StreamSubscription subscription =
16 | stream.listen(_onData, onDone: _onDone);
17 | _delayCancel(subscription, milliseconds: 500);
18 | }
19 |
20 | void _onData(int event) => print("$event");
21 |
22 | void _onDone() => print("onDone");
23 |
24 | void _delayCancel(StreamSubscription subscription, {int milliseconds = 0}) {
25 | Future.delayed(Duration(milliseconds: milliseconds))
26 | .then((value) => subscription.cancel());
27 | }
28 |
--------------------------------------------------------------------------------
/lib/stream/stream7_stream_to_stream.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | Stream countStream(int to) async* {
4 | for (int i = 0; i < to; i++) yield i;
5 | }
6 |
7 | List countList(int to) {
8 | List list = List.empty(growable: true);
9 | for (int i = 0; i < to; i++) list.add(i);
10 | return list;
11 | }
12 |
13 | main() {
14 | map();
15 | }
16 |
17 | void map() async {
18 | Stream stream = countStream(5);
19 | Stream strStream = stream.map((event) => "index($event)");
20 | StringBuffer streamSb = new StringBuffer();
21 | await strStream.forEach((value) => streamSb.write("$value,"));
22 |
23 | List list = countList(5);
24 | StringBuffer listSb = new StringBuffer();
25 | var strList = list.map((e) => "index($e)").toList();
26 | strList.forEach((element) => listSb.write("$element,"));
27 | print("map stream:$streamSb list:$listSb");
28 | }
29 |
--------------------------------------------------------------------------------
/lib/provider/post/detail/post_detail_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_sample/provider/post/base/eventbus_x.dart';
3 | import 'package:flutter_sample/provider/post/data/post_bean.dart';
4 | import 'package:flutter_sample/provider/post/data/post_server.dart';
5 |
6 | class PostDetailModel with ChangeNotifier {
7 | PostBean? post;
8 |
9 | initPost(int id) {
10 | PostServer.instance().getPostDetail(id).then((json) {
11 | post = PostBean.map(json);
12 | notifyListeners();
13 | }).catchError((e) => print(e));
14 | }
15 |
16 | likePost(bool toLike) {
17 | PostServer.instance().like(post?.id??0, toLike).then((result) {
18 | if (result["success"]) {
19 | post?.isLike = toLike;
20 | PostLikeEvent(post?.id??0, toLike).fire();
21 | }
22 | notifyListeners();
23 | }).catchError((e) => print(e));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/provider/set_state_demo_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const String setStateDemoTitle = "setState示例";
4 |
5 | class SetStateDemoWidget extends StatefulWidget {
6 | SetStateDemoWidget({Key? key}) : super(key: key);
7 |
8 | @override
9 | _SetStateDemoWidgetState createState() => _SetStateDemoWidgetState();
10 | }
11 |
12 | class _SetStateDemoWidgetState extends State {
13 | int count = 0;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Scaffold(
18 | appBar: AppBar(
19 | title: Text(setStateDemoTitle),
20 | ),
21 | body: Center(
22 | child: Column(
23 | mainAxisAlignment: MainAxisAlignment.center,
24 | children: [
25 | Text("计数:$count"),
26 | ElevatedButton(
27 | child: Text("increment"),
28 | onPressed: () => setState(() => count++),
29 | )
30 | ],
31 | ),
32 | ),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flutter_sample",
3 | "short_name": "flutter_sample",
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 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/stream/stream6_stream_to_future.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | Stream countStream(int to) async* {
4 | for (int i = 0; i < to; i++) yield i;
5 | }
6 |
7 | List countList(int to) {
8 | List list = List.empty(growable: true);
9 | for (int i = 0; i < to; i++) list.add(i);
10 | return list;
11 | }
12 |
13 | main() {
14 | reduce();
15 | forEach();
16 | }
17 |
18 | void reduce() async {
19 | Stream stream = countStream(5);
20 | Future future = stream.reduce((previous, element) => previous + element);
21 | var futureSum = await future;
22 |
23 | List list = countList(5);
24 | var listSum = list.reduce((value, element) => value + element);
25 | print("reduce futureSum:$futureSum listSum:$listSum");
26 | }
27 |
28 | void forEach() async {
29 | Stream stream = countStream(5);
30 | StringBuffer streamSb = new StringBuffer();
31 | await stream.forEach((value) => streamSb.write("$value,"));
32 |
33 | List list = countList(5);
34 | StringBuffer listSb = new StringBuffer();
35 | list.forEach((value) => listSb.write("$value,"));
36 | print("stream forEach:$streamSb list forEach:$listSb");
37 | }
38 |
--------------------------------------------------------------------------------
/lib/provider/post/base/slide_page_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class SlidePageRoute extends PageRouteBuilder {
4 | final Widget widget;
5 |
6 | SlidePageRoute({required this.widget})
7 | : super(
8 | transitionDuration: const Duration(milliseconds: 300), //设置动画时长500毫秒
9 | pageBuilder: (BuildContext context, Animation animation1,
10 | Animation animation2) {
11 | return widget;
12 | },
13 | transitionsBuilder: (BuildContext context,
14 | Animation animation1,
15 | Animation animation2,
16 | Widget child) {
17 | //渐变过渡
18 | return SlideTransition(
19 | position: Tween(
20 | begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0))
21 | .animate(CurvedAnimation(
22 | parent: animation1, curve: Curves.fastOutSlowIn)),
23 | child: child,
24 | );
25 | //翻转缩放
26 | },
27 | maintainState: true,
28 | opaque: false);
29 | }
30 |
--------------------------------------------------------------------------------
/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 | import 'package:flutter_sample/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/provider/post/list/post_item_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_sample/provider/post/data/post_bean.dart';
3 |
4 | class PostItemWidget extends StatelessWidget {
5 | final PostBean? post;
6 |
7 | final void Function(BuildContext context, PostBean? post)? click;
8 |
9 | const PostItemWidget({Key? key, this.post, this.click}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return GestureDetector(
14 | onTap: () => click?.call(context, post),
15 | child: Container(
16 | height: 80,
17 | child: Row(
18 | children: [
19 | Expanded(
20 | child: Text(
21 | "${post?.content}",
22 | maxLines: 2,
23 | overflow: TextOverflow.ellipsis,
24 | ),
25 | ),
26 | Container(
27 | width: 50,
28 | child: Icon(
29 | Icons.favorite,
30 | color: (post?.isLike ?? false) ? Colors.red : Colors.grey,
31 | ),
32 | ),
33 | ],
34 | ),
35 | ));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/bottom_input/input_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | import 'input_widget.dart';
5 |
6 | class InputDialog {
7 | static Future show(BuildContext context) async {
8 | return Navigator.of(context).push(InputOverlay());
9 | }
10 | }
11 |
12 | class InputOverlay extends ModalRoute {
13 | @override
14 | Duration get transitionDuration => Duration(milliseconds: 200);
15 |
16 | @override
17 | bool get opaque => false;
18 |
19 | @override
20 | bool get barrierDismissible => true;
21 |
22 | @override
23 | Color get barrierColor => const Color(0x01000000);
24 |
25 | @override
26 | String get barrierLabel => "";
27 |
28 | @override
29 | bool get maintainState => true;
30 |
31 | @override
32 | Widget buildPage(
33 | BuildContext context,
34 | Animation animation,
35 | Animation secondaryAnimation,
36 | ) {
37 | return InputWidget();
38 | }
39 |
40 | @override
41 | Widget buildTransitions(BuildContext context, Animation animation,
42 | Animation secondaryAnimation, Widget child) {
43 | return FadeTransition(
44 | opacity: CurvedAnimation(
45 | parent: animation,
46 | curve: Curves.easeOut,
47 | ),
48 | child: child,
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flutter_sample
2 |
3 | 提供一些Flutter实用的案例代码
4 |
5 | ## 介绍链接
6 |
7 | - [输入框和键盘处理]( https://juejin.im/post/5e7c164ae51d455c7275d353 )
8 | 入口:main_bottom_input.dart
9 | - [Flutter视频库chewie的使用]( https://juejin.im/post/5e814fd9518825738e215f0f )
10 | 入口:main_video.dart
11 |
12 | - [Flutter状态管理Provider(一) 简易使用](https://juejin.im/post/5e859b39f265da47c06ebaf1)
13 | 入口:main_provider.dart
14 |
15 | - [Flutter状态管理Provider(二) 源码分析](https://juejin.im/post/5e89ad7a6fb9a03c4e64697d)
16 | 入口:main_provider.dart
17 |
18 | - [Flutter状态管理Provider(三)基于Provider的开发应用](https://juejin.im/post/5e931f41e51d4547153d174e)
19 | 入口:main_provider.dart
20 |
21 | - [Flutter状态管理Provider(四) Selector使用](https://juejin.im/post/5eabb46be51d454dbd1fd30a)
22 | 入口:main_provider.dart
23 |
24 | - [Flutter事件总线EventBus](https://juejin.im/post/5eb3973ae51d4525602d34ac)
25 | 入口:main_eventbus.dart
26 |
27 | - [Flutter之Stream(一)介绍](https://juejin.im/post/5eba0e9051882558dc24cadc)
28 | 入口:main_Stream.dart
29 |
30 |
31 | ## 待补充:
32 | - 自定义圆角widget y
33 | - 图片swiper组件 y
34 | - 模糊使用 y
35 | - OverScrollBehavior y
36 | - 自定义Route:SlidePageRoute,TransparentModalRoute... y
37 | - 横竖屏切换问题 m
38 | - 1.12.13 新的build aar m
39 | - 固定尺寸GirdItem SliverGridDelegateWithFixedSize m
40 | - Widget与Element关系 m
41 | - fish-redux 源码解析 m
42 | - stream 源码解析 m
43 | - 混合栈 flutter_thrio flutter_boost
44 |
45 |
46 |
--------------------------------------------------------------------------------
/lib/main_eventbus.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'eventbus/eventbus_demo_widget1.dart';
4 | import 'eventbus/eventbus_demo_widget2.dart';
5 |
6 | void main() => runApp(MaterialApp(
7 | home: Scaffold(
8 | appBar: AppBar(
9 | title: const Text("EventBus"),
10 | ),
11 | body: MainEventBusWidget(),
12 | ),
13 | ));
14 |
15 | class MainEventBusWidget extends StatefulWidget {
16 | const MainEventBusWidget({Key? key}) : super(key: key);
17 |
18 | @override
19 | _MainEventBusWidgetState createState() => _MainEventBusWidgetState();
20 | }
21 |
22 | class _MainEventBusWidgetState extends State {
23 | @override
24 | Widget build(BuildContext context) {
25 | return Center(
26 | child: Column(
27 | mainAxisAlignment: MainAxisAlignment.center,
28 | children: [
29 | _build(context, eventBusDemo1Title, EventBusDemoWidget1()),
30 | _build(context, eventBusDemo2Title, EventBusDemoWidget2()),
31 | ],
32 | ),
33 | );
34 | }
35 |
36 | Widget _build(BuildContext context, String text, Widget newRouteWidget) {
37 | return ElevatedButton(
38 | child: Text(text),
39 | onPressed: () => Navigator.of(context).push(MaterialPageRoute(
40 | builder: (context) => newRouteWidget,
41 | )),
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/main_bottom_input.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'bottom_input/input_dialog.dart';
3 |
4 | void main() => runApp(MaterialApp(home: InputHomeWidget()));
5 |
6 | class InputHomeWidget extends StatefulWidget {
7 | @override
8 | _InputHomeWidgetState createState() => _InputHomeWidgetState();
9 | }
10 |
11 | class _InputHomeWidgetState extends State {
12 | String _inputString = "";
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Scaffold(
17 | /**弹出键盘会导致bottomInset值变化,可以通过MediaQuery获取到各种值。
18 | resizeToAvoidBottomInset:true(默认值),
19 | 表示根据变化重新Build,页面会被顶到键盘上,当然也可以通过scollView处理 **/
20 | resizeToAvoidBottomInset: false,
21 | appBar: AppBar(
22 | title: Text("底部输入框"),
23 | ),
24 | body: Column(
25 | mainAxisSize: MainAxisSize.min,
26 | children: [
27 | FlatButton(
28 | color: Colors.yellow,
29 | onPressed: _input,
30 | child: Text("弹出底部输入框"),
31 | ),
32 | Expanded(child: Text("结果:$_inputString")),
33 | Text("底部文案"),
34 | Container(
35 | height: 100,
36 | width: 20,
37 | )
38 | ],
39 | ),
40 | );
41 | }
42 |
43 | void _input() {
44 | InputDialog.show(context).then((value) {
45 | setState(() {
46 | _inputString = value??"";
47 | });
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/stream/stream8_stream_transformer.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | //一个字母和空格流,空格分割的字母序列都是一个单词
4 | Stream buildLetterStream() async* {
5 | String s = "One World One Dream";
6 | for (int i = 0; i < s.length; i++) {
7 | String letter = s.substring(i, i + 1);
8 | yield letter;
9 | }
10 | }
11 |
12 | main() async {
13 | Stream letterStream = buildLetterStream();
14 | var wordSplitter = WordSplitter();
15 | //字母组成单词。字母序列-->单词序列
16 | Stream wordStream =
17 | letterStream.transform(wordSplitter.transformer());
18 | await wordStream.forEach((word) => print(word));
19 | }
20 |
21 | class WordSplitter {
22 | StreamTransformer? _transformer;
23 | StringBuffer _wordBuilder = new StringBuffer();
24 |
25 | StreamTransformer transformer() {
26 | _transformer = StreamTransformer.fromHandlers(
27 | handleData: _handleData, handleDone: _sinkWord);
28 | return _transformer!;
29 | }
30 |
31 | //One World One Dream
32 | void _handleData(String letter, EventSink sink) {
33 | //读到空格,则把累计的字母构成单词输出。
34 | if (letter == " ") {
35 | _sinkWord(sink);
36 | } else {
37 | //否则存储字母
38 | _wordBuilder.write(letter);
39 | }
40 | }
41 |
42 | //读完时,把剩余字母构成单词输出
43 | void _sinkWord(EventSink sink) {
44 | if (_wordBuilder.isNotEmpty) {
45 | sink.add(_wordBuilder.toString());
46 | _wordBuilder.clear();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.11'
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 |
--------------------------------------------------------------------------------
/lib/provider/post/base/item_refresher.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:provider/provider.dart';
3 | import 'package:provider/single_child_widget.dart';
4 |
5 | typedef ShouldRebuild = bool Function(A notifier, T value);
6 |
7 | class ItemRefresher extends SingleChildStatefulWidget {
8 | final ShouldRebuild _shouldRebuild;
9 | final T value;
10 |
11 | ItemRefresher({
12 | Key? key,
13 | required this.value,
14 | required ShouldRebuild shouldRebuild,
15 | required this.builder,
16 | Widget? child,
17 | }) : assert(builder != null),
18 | _shouldRebuild = shouldRebuild,
19 | super(key: key, child: child);
20 |
21 | final ValueWidgetBuilder builder;
22 |
23 | @override
24 | _ItemRefresherState createState() => _ItemRefresherState();
25 | }
26 |
27 | class _ItemRefresherState extends SingleChildState> {
28 | Widget? cache;
29 | Widget? oldWidget;
30 |
31 | @override
32 | Widget buildWithChild(BuildContext context, Widget? child) {
33 | A notifier = Provider.of(context);
34 | var shouldInvalidateCache = oldWidget != widget ||
35 | (widget._shouldRebuild != null &&
36 | notifier != null &&
37 | widget._shouldRebuild.call(notifier, widget.value));
38 | if (shouldInvalidateCache) {
39 | oldWidget = widget;
40 | cache = widget.builder(
41 | context,
42 | widget.value,
43 | child,
44 | );
45 | }
46 | return cache!;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | 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.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/provider/post/list/post_item_widget2.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_sample/provider/post/data/post_bean.dart';
3 | import 'package:flutter_sample/provider/post/list/post_item_notifier.dart';
4 | import 'package:provider/provider.dart';
5 |
6 | class PostItemWidget2 extends StatelessWidget {
7 | final PostBean? post;
8 |
9 | final void Function(BuildContext context, PostBean? post)? click;
10 |
11 | const PostItemWidget2({Key? key, this.post, this.click}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | print("PostItemWidget2:build");
16 | return GestureDetector(
17 | onTap: () => click?.call(context, post),
18 | child: Container(
19 | height: 80,
20 | child: Row(
21 | children: [
22 | Expanded(
23 | child: Text(
24 | "${post?.content}",
25 | maxLines: 2,
26 | overflow: TextOverflow.ellipsis,
27 | ),
28 | ),
29 | Container(
30 | width: 50,
31 | child: Selector(
32 | selector: (context, itemChange) => post?.isLike ?? false,
33 | shouldRebuild: (pre, next) => pre != next,
34 | builder: (context, isLike, child) {
35 | return Icon(
36 | Icons.favorite,
37 | color: (isLike) ? Colors.red : Colors.grey,
38 | );
39 | }),
40 | ),
41 | ],
42 | ),
43 | ));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_sample
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/lib/provider/provider_demo_widget1.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const String providerDemoTitle1 = "Provider示例1";
4 | const String providerDemoIntroduction1 = "\n\n用InheritedWidget保存数据\n以及访问InheritedWidget拿到数据";
5 |
6 | class ProviderDemoWidget1 extends StatefulWidget {
7 | const ProviderDemoWidget1({Key? key}) : super(key: key);
8 |
9 | @override
10 | _ProviderDemoWidget1State createState() => _ProviderDemoWidget1State();
11 | }
12 |
13 | class _ProviderDemoWidget1State extends State {
14 | int _count = 0;
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Scaffold(
19 | appBar: AppBar(
20 | title: const Text(providerDemoTitle1),
21 | ),
22 | body: CountProvider(
23 | count: _count,
24 | child: Center(
25 | child: Column(
26 | mainAxisAlignment: MainAxisAlignment.center,
27 | children: [
28 | Builder(
29 | builder: (context2) {
30 | /// 读取和显示计数
31 | CountProvider provider =
32 | (context2.getElementForInheritedWidgetOfExactType()?.widget) as CountProvider;
33 | return Text("计数:${provider.count}");
34 | },
35 | ),
36 | ElevatedButton(
37 | child: const Text("increment"),
38 | onPressed: () => setState(() => _count++),
39 | ),
40 | const Text(providerDemoIntroduction1),
41 | ],
42 | ),
43 | ),
44 | ),
45 | );
46 | }
47 | }
48 |
49 | class CountProvider extends InheritedWidget {
50 | final int count;
51 |
52 | const CountProvider({Key? key, required this.count, required Widget child}) : super(key: key, child: child);
53 |
54 | @override
55 | bool updateShouldNotify(CountProvider old) {
56 | return true;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/provider/provider_demo_widget4.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:provider/provider.dart';
3 |
4 | const String providerDemoTitle4 = "Provider示例4";
5 | const String providerDemoIntroduction4 = "\n\n"
6 | "使用第三方的Provider库。\n"
7 | "我们发现与上一个示例的简易版Provider上的使用方法是一致的。正如介绍所描述的非常简单。\n"
8 | "同时也补充一个Cosumer的使用\n"
9 | "当然了Provider库,可维护性,可测试性,可扩展性远比我们所写的强大。\n";
10 |
11 | class ProviderDemoWidget4 extends StatefulWidget {
12 | ProviderDemoWidget4({Key? key}) : super(key: key);
13 |
14 | @override
15 | _ProviderDemoWidget4State createState() => _ProviderDemoWidget4State();
16 | }
17 |
18 | class _ProviderDemoWidget4State extends State {
19 | final CountModel _countModel = CountModel(0);
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return Scaffold(
24 | appBar: AppBar(title: const Text(providerDemoTitle4)),
25 | body: ChangeNotifierProvider.value(
26 | value: _countModel,
27 | child: Center(
28 | child: Column(
29 | mainAxisAlignment: MainAxisAlignment.center,
30 | children: [
31 | Consumer(
32 | builder: (contextC, model, child) {
33 | return Text("计数:${model.count}(有依赖情况)");
34 | },
35 | ),
36 | Builder(builder: (context2) {
37 | return Text("计数:${Provider.of(context2, listen: false).count}(无依赖情况)");
38 | }),
39 | ElevatedButton(child: const Text("increment"), onPressed: () => _countModel.increment()),
40 | const Text(providerDemoIntroduction4),
41 | ],
42 | ),
43 | ),
44 | ),
45 | );
46 | }
47 | }
48 |
49 | class CountModel extends ChangeNotifier {
50 | int count;
51 |
52 | CountModel(this.count);
53 |
54 | void increment() {
55 | count++;
56 | notifyListeners();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/provider/post/list/post_list_model.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_sample/provider/post/base/eventbus_x.dart';
5 | import 'package:flutter_sample/provider/post/data/post_bean.dart';
6 | import 'package:flutter_sample/provider/post/data/post_server.dart';
7 | import 'package:flutter_sample/provider/post/list/post_item_notifier.dart';
8 | import 'package:pull_to_refresh/pull_to_refresh.dart';
9 | import 'package:collection/collection.dart';
10 |
11 | class PostListModel with ChangeNotifier {
12 | var posts = List.empty(growable: true);
13 |
14 | ///smartRefresher的刷新控制器
15 | RefreshController refreshController = RefreshController();
16 |
17 | ///解除事件监听方法
18 | late VoidCallback _eventDispose;
19 |
20 | /// 单个刷新的ChangeNotifier
21 | late PostNotifier itemChange;
22 |
23 | PostListModel() {
24 | itemChange = new PostNotifier();
25 | subscribePostLike();
26 | }
27 |
28 | ///订阅PostLikeEvent
29 | void subscribePostLike() {
30 | StreamSubscription subscription =
31 | eventBus.on().listen((event) {
32 | ///拿到event,更新下当前页面对应post的isLike状态
33 | var post = posts.firstWhereOrNull((post) => post.id == event.id);
34 | post?.isLike = event.isLike;
35 | itemChange.id = event.id;
36 | itemChange.notifyListeners();
37 | });
38 | _eventDispose = () => subscription.cancel();
39 | }
40 |
41 | ///加载数据
42 | void loadData({VoidCallback? callback}) {
43 | PostServer.instance().loadPosts().then((jsonList) {
44 | posts = jsonList.map((json) => PostBean.map(json)).toList();
45 | notifyListeners();
46 | callback?.call();
47 | }).catchError((e) => print(e));
48 | }
49 |
50 | ///下拉刷新,数据获取到后,通知smartRefresher
51 | void refresh() {
52 | loadData(callback: () => refreshController.refreshCompleted());
53 | }
54 |
55 | ///ChangeNotifier的 解除监听方法。
56 | @override
57 | void dispose() {
58 | super.dispose();
59 | _eventDispose.call();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/Flutter/flutter_export_environment.sh
65 | **/ios/ServiceDefinitions.json
66 | **/ios/Runner/GeneratedPluginRegistrant.*
67 |
68 | # Exceptions to above rules.
69 | !**/ios/**/default.mode1v3
70 | !**/ios/**/default.mode2v3
71 | !**/ios/**/default.pbxuser
72 | !**/ios/**/default.perspectivev3
73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
74 |
75 |
76 | *.pyc
77 | *sync/
78 | Icon?
79 | .tags*
80 |
81 | build/
82 | .android/
83 | .ios/
84 | .flutter-plugins
85 | .gradle/
86 |
87 |
88 | *.iml
89 | *.iml
90 |
91 | local.properties
92 | pubspec.lock
93 | local.properties
94 | flutter_page.iml
95 | .flutter-plugins-dependencies
96 | .vscode
--------------------------------------------------------------------------------
/lib/main_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_sample/provider/provider_demo_widget1.dart';
3 | import 'package:flutter_sample/provider/provider_demo_widget2.dart';
4 | import 'package:flutter_sample/provider/provider_demo_widget3.dart';
5 | import 'package:flutter_sample/provider/provider_demo_widget4.dart';
6 | import 'package:flutter_sample/provider/selector/selector_demo_widget.dart';
7 | import 'package:flutter_sample/provider/set_state_demo_widget.dart';
8 |
9 | import 'provider/post/list/post_list_widget.dart';
10 |
11 | ///
12 | ///Provider V3
13 | ///官方推荐库
14 | ///待优化
15 | ///
16 | void main() => runApp(MaterialApp(
17 | home: Scaffold(
18 | appBar: AppBar(
19 | title: const Text("Provider"),
20 | ),
21 | body: MainProviderWidget(),
22 | ),
23 | ));
24 |
25 | class MainProviderWidget extends StatefulWidget {
26 | @override
27 | _MainProviderWidgetState createState() => new _MainProviderWidgetState();
28 | }
29 |
30 | class _MainProviderWidgetState extends State {
31 | @override
32 | Widget build(BuildContext context) {
33 | return Center(
34 | child: Column(
35 | mainAxisAlignment: MainAxisAlignment.center,
36 | children: [
37 | _build(context, setStateDemoTitle, SetStateDemoWidget()),
38 | _build(context, providerDemoTitle1, const ProviderDemoWidget1()),
39 | _build(context, providerDemoTitle2, ProviderDemoWidget2()),
40 | _build(context, providerDemoTitle3, ProviderDemoWidget3()),
41 | _build(context, providerDemoTitle4, ProviderDemoWidget4()),
42 | _build(context, "代码应用(简易社区)", PostListWidget()),
43 | _build(context, "Selector使用", SelectorDemoWidget()),
44 | ],
45 | ),
46 | );
47 | }
48 |
49 | Widget _build(BuildContext context, String text, Widget newRouteWidget) {
50 | return ElevatedButton(
51 | child: Text(text),
52 | onPressed: () => Navigator.of(context).push(MaterialPageRoute(
53 | builder: (context) => newRouteWidget,
54 | )),
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'provider/post/list/post_list_widget.dart';
4 | import 'provider/provider_demo_widget1.dart';
5 | import 'provider/provider_demo_widget2.dart';
6 | import 'provider/provider_demo_widget3.dart';
7 | import 'provider/provider_demo_widget4.dart';
8 | import 'provider/selector/selector_demo_widget.dart';
9 | import 'provider/set_state_demo_widget.dart';
10 |
11 | void main() => runApp(MyApp());
12 |
13 | class MyApp extends StatelessWidget {
14 | // This widget is the root of your application.
15 | @override
16 | Widget build(BuildContext context) {
17 | return MaterialApp(
18 | title: 'Flutter Demo',
19 | home: MyHomePage(title: 'Flutter Demo Home Page'),
20 | );
21 | }
22 | }
23 |
24 | class MyHomePage extends StatefulWidget {
25 | MyHomePage({Key? key, required this.title}) : super(key: key);
26 | final String title;
27 |
28 | @override
29 | _MyHomePageState createState() => _MyHomePageState();
30 | }
31 |
32 | class _MyHomePageState extends State {
33 | @override
34 | Widget build(BuildContext context) {
35 | return Scaffold(
36 | appBar: AppBar(
37 | title: Text(widget.title),
38 | ),
39 | body: Column(
40 | children: [
41 | _build(context, setStateDemoTitle, SetStateDemoWidget()),
42 | _build(context, providerDemoTitle1, const ProviderDemoWidget1()),
43 | _build(context, providerDemoTitle2, ProviderDemoWidget2()),
44 | _build(context, providerDemoTitle3, ProviderDemoWidget3()),
45 | _build(context, providerDemoTitle4, ProviderDemoWidget4()),
46 | _build(context, "代码应用(简易社区)", PostListWidget()),
47 | _build(context, "Selector使用", SelectorDemoWidget()),
48 | ],
49 | ));
50 | }
51 |
52 | Widget _build(BuildContext context, String text, Widget newRouteWidget) {
53 | return ElevatedButton(
54 | child: Text(text),
55 | onPressed: () => Navigator.of(context).push(MaterialPageRoute(
56 | builder: (context) => newRouteWidget,
57 | )),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_sample
2 | description: A new Flutter application.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.15.1 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | #https://pub.dev/packages/provider
24 | provider: ^6.0.2
25 |
26 | # https://pub.dev/packages/scoped_model
27 | scoped_model: ^1.1.0
28 |
29 | #https://pub.dev/packages/redux
30 | #https://pub.dev/packages/flutter_redux
31 | redux: ^5.0.0
32 | flutter_redux: ^0.8.2
33 |
34 | # The following adds the Cupertino Icons font to your application.
35 | # Use with the CupertinoIcons class for iOS style icons.
36 | cupertino_icons: ^1.0.2
37 |
38 | #https://pub.dev/packages/rxdart
39 | rxdart: ^0.27.3
40 |
41 | dio: ^4.0.4
42 | video_player: ^2.2.14
43 | # chewie: ^0.9.8+1
44 | event_bus: ^2.0.0
45 | pull_to_refresh: ^2.0.0
46 |
47 | dev_dependencies:
48 | flutter_test:
49 | sdk: flutter
50 | flutter_lints: ^1.0.0
51 |
52 | # For information on the generic Dart part of this file, see the
53 | # following page: https://dart.dev/tools/pub/pubspec
54 |
55 | # The following section is specific to Flutter.
56 | flutter:
57 | # The following line ensures that the Material Icons font is
58 | # included with your application, so that you can use the icons in
59 | # the material Icons class.
60 | uses-material-design: true
61 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion flutter.compileSdkVersion
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | defaultConfig {
45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
46 | applicationId "com.nicomama.flutter_sample"
47 | minSdkVersion flutter.minSdkVersion
48 | targetSdkVersion flutter.targetSdkVersion
49 | versionCode flutterVersionCode.toInteger()
50 | versionName flutterVersionName
51 | }
52 |
53 | buildTypes {
54 | release {
55 | // TODO: Add your own signing config for the release build.
56 | // Signing with the debug keys for now, so `flutter run --release` works.
57 | signingConfig signingConfigs.debug
58 | }
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | }
69 |
--------------------------------------------------------------------------------
/lib/statemanager/scoped_model_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:scoped_model/scoped_model.dart';
3 |
4 | ///
5 | ///ScopedModel 原理等价于Provider
6 | ///
7 | void main() => runApp(MaterialApp(
8 | home: Scaffold(
9 | appBar: AppBar(
10 | title: Text("ProviderWidget"),
11 | ),
12 | body: ScopedModelWidget(),
13 | ),
14 | ));
15 |
16 | class ScopedModelWidget extends StatefulWidget {
17 | @override
18 | _ScopedModelWidgetState createState() => new _ScopedModelWidgetState();
19 | }
20 |
21 | class _ScopedModelWidgetState extends State {
22 | ShareModel _shareModel = new ShareModel(0);
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | print("_ProviderWidget build context:$context}");
27 | return Center(
28 | child: ScopedModel(
29 | model: _shareModel,
30 | child: Column(
31 | mainAxisAlignment: MainAxisAlignment.center,
32 | children: [
33 | ScopedModelDescendant(
34 | builder: (context2, child, model) {
35 | print("__TestWidgetState build context:$context2");
36 | return Text(
37 | model.count.toString(),
38 | style: TextStyle(fontSize: 40),
39 | );
40 | },
41 | ),
42 | Builder(
43 | builder: (context2) {
44 | print("__TestButtonState build context:$context2}");
45 | return ElevatedButton(
46 | child: Text(
47 | "Increment (current:${ScopedModel.of(context2, rebuildOnChange: true)?.count.toString()})"),
48 | // "Increment (current)"),
49 | onPressed: () {
50 | ScopedModel.of(context2,
51 | rebuildOnChange: false)
52 | .increment();
53 | });
54 | },
55 | ),
56 | ],
57 | ),
58 | ),
59 | );
60 | }
61 | }
62 |
63 |
64 |
65 | class ShareModel extends Model {
66 | int count;
67 |
68 | ShareModel(this.count);
69 |
70 | void increment() {
71 | count++;
72 | notifyListeners();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/provider/post/detail/post_detail_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_sample/provider/post/detail/post_detail_model.dart';
3 | import 'package:provider/provider.dart';
4 |
5 | class PostDetailWidget extends StatefulWidget {
6 | int id;
7 |
8 | PostDetailWidget({Key? key, required this.id}) : super(key: key);
9 |
10 | @override
11 | _PostDetailWidgetState createState() => _PostDetailWidgetState();
12 | }
13 |
14 | class _PostDetailWidgetState extends State {
15 | late PostDetailModel _detailModel;
16 |
17 | @override
18 | void initState() {
19 | super.initState();
20 | _detailModel = PostDetailModel()..initPost(widget.id);
21 | }
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return ChangeNotifierProvider.value(
26 | value: _detailModel,
27 | child: Scaffold(
28 | appBar: AppBar(
29 | title: Text("帖子详情"),
30 | actions: [
31 | Consumer(
32 | builder: (context, model, child) {
33 | var post = model.post;
34 | if (post == null) {
35 | return Container();
36 | }
37 | return GestureDetector(
38 | onTap: () =>
39 | model.likePost(!(model.post?.isLike ?? false)),
40 | child: Icon(
41 | Icons.favorite,
42 | color: post.isLike ? Colors.red : Colors.white,
43 | ));
44 | },
45 | ),
46 | Container(
47 | width: 30,
48 | )
49 | ],
50 | ),
51 | body: Container(
52 | padding: EdgeInsets.all(20),
53 | child: Consumer(
54 | builder: (context, model, child) {
55 | var post = model.post;
56 | if (post == null) {
57 | return Container();
58 | }
59 | return SingleChildScrollView(
60 | child: Text(
61 | "${post.content}",
62 | style: TextStyle(fontSize: 18, height: 1.4),
63 | ),
64 | );
65 | },
66 | ),
67 | )),
68 | );
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/provider/selector/selector_demo_widget.dart:
--------------------------------------------------------------------------------
1 | import 'dart:collection';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:provider/provider.dart';
5 |
6 | class SelectorDemoWidget extends StatefulWidget {
7 | SelectorDemoWidget({Key? key}) : super(key: key);
8 |
9 | @override
10 | _SelectorDemoWidgetState createState() => _SelectorDemoWidgetState();
11 | }
12 |
13 | class _SelectorDemoWidgetState extends State {
14 | CountModel _model = CountModel()..initData();
15 |
16 | @override
17 | void initState() {
18 | super.initState();
19 | _model = CountModel()..initData();
20 | }
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | List _children = _model.contentMap.keys
25 | .map((key) => CountItemWidget(content: key))
26 | .toList();
27 | return Scaffold(
28 | appBar: AppBar(
29 | title: Text("Selector示例"),
30 | ),
31 | body: ChangeNotifierProvider.value(
32 | value: _model,
33 | child: ListView(children: _children),
34 | ));
35 | }
36 | }
37 |
38 | class CountItemWidget extends StatelessWidget {
39 | final String content;
40 |
41 | CountItemWidget({required this.content});
42 |
43 | @override
44 | Widget build(BuildContext context) {
45 | print("CountItemWidget:build");
46 | return Container(
47 | height: 80,
48 | padding: EdgeInsets.all(15),
49 | alignment: Alignment.center,
50 | child: ElevatedButton(
51 | onPressed: () =>
52 | Provider.of(context, listen: false).increment(content),
53 | child: Selector(
54 | selector: (context, model) => model.contentMap[content]!,
55 | shouldRebuild: (preCount, nextCount) => preCount != nextCount,
56 | builder: (context, count, child) {
57 | print("$content Selector:builder");
58 | return Text("$content : $count");
59 | }),
60 | ),
61 | );
62 | }
63 | }
64 |
65 | class CountModel extends ChangeNotifier {
66 | Map contentMap = SplayTreeMap();
67 |
68 | initData() {
69 | contentMap["a"] = 0;
70 | contentMap["b"] = 0;
71 | contentMap["c"] = 0;
72 | }
73 |
74 | increment(String content) {
75 | if (contentMap.containsKey(content)) {
76 | contentMap[content] = contentMap[content]! + 1;
77 | notifyListeners();
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/statemanager/provider_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:provider/provider.dart';
3 |
4 | ///
5 | ///Provider V3
6 | ///官方推荐库
7 | ///待优化
8 | ///
9 | void main() => runApp(MaterialApp(
10 | home: Scaffold(
11 | appBar: AppBar(
12 | title: Text("ProviderWidget"),
13 | ),
14 | body: InheritedWidgetTestRoute(),
15 | ),
16 | ));
17 |
18 | class InheritedWidgetTestRoute extends StatefulWidget {
19 | const InheritedWidgetTestRoute({Key? key}) : super(key: key);
20 |
21 | @override
22 | _InheritedWidgetTestRouteState createState() =>
23 | _InheritedWidgetTestRouteState();
24 | }
25 |
26 | class _InheritedWidgetTestRouteState extends State {
27 | ShareModelWithNotifier _shareDataWithNotifier = ShareModelWithNotifier(0);
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | print("_ProviderWidget build context:$context}");
32 | return Center(
33 | child: ChangeNotifierProvider.value(
34 | value: _shareDataWithNotifier,
35 | child: Column(
36 | mainAxisAlignment: MainAxisAlignment.center,
37 | children: [
38 | Consumer(
39 | builder: (context2, model, child) {
40 | print("__TestWidgetState build context:$context2");
41 | return Text(
42 | model.count.toString(),
43 | style:const TextStyle(fontSize: 40),
44 | );
45 | },
46 | ),
47 | Builder(
48 | builder: (context2) {
49 | print("__TestButtonState build context:$context2}");
50 | return ElevatedButton(
51 | child: Text(
52 | "Increment (current:${Provider.of(context2, listen: true).count.toString()})"),
53 | // "Increment (current)"),
54 | onPressed: () {
55 | Provider.of(context2,
56 | listen: true)
57 | .increment();
58 | });
59 | },
60 | ),
61 | ],
62 | ),
63 | ),
64 | );
65 | }
66 | }
67 |
68 | class ShareModelWithNotifier with ChangeNotifier {
69 | int count;
70 |
71 | ShareModelWithNotifier(this.count);
72 |
73 | void increment() {
74 | count++;
75 | notifyListeners();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/lib/statemanager/bloc_widget.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | ///
6 | ///
7 | void main() => runApp(MaterialApp(
8 | home: Scaffold(
9 | appBar: AppBar(
10 | title: Text("BLocWidget"),
11 | ),
12 | body: BLocWidget(),
13 | ),
14 | ));
15 |
16 | class BLocWidget extends StatefulWidget {
17 | @override
18 | _BLocWidgetState createState() => new _BLocWidgetState();
19 | }
20 |
21 | class _BLocWidgetState extends State {
22 | final _bloc = ShareBLoC();
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | print("_BLocWidget build context:$context}");
27 | return Center(
28 | child: ShareProvider(
29 | shareBloc: _bloc,
30 | child: StreamBuilder(
31 | stream: _bloc.stream,
32 | initialData: 0,
33 | builder: (context2, snapshot) {
34 | return Column(
35 | mainAxisAlignment: MainAxisAlignment.center,
36 | children: [
37 | Text(
38 | "${snapshot.data}",
39 | style: TextStyle(fontSize: 40),
40 | ),
41 | ElevatedButton(
42 | child: Text("Increment (current:${snapshot.data})"),
43 | onPressed: () {
44 | ShareProvider.of(context2).increment();
45 | // _bloc.increment();
46 | }),
47 | ]);
48 | }),
49 | ));
50 | }
51 | }
52 |
53 | class ShareBLoC {
54 | late int _count ;
55 | late StreamController _countController;
56 |
57 | ShareBLoC() {
58 | _count = 0;
59 | _countController = StreamController();
60 | }
61 |
62 | Stream get stream => _countController.stream;
63 |
64 | increment() {
65 | _countController.sink.add(++_count);
66 | }
67 |
68 | dispose() {
69 | _countController.close();
70 | }
71 | }
72 |
73 | class ShareProvider extends InheritedWidget {
74 | final ShareBLoC shareBloc;
75 |
76 | ShareProvider({
77 | Key? key,
78 | ShareBLoC? shareBloc,
79 | required Widget child,
80 | }) : shareBloc = shareBloc ?? ShareBLoC(),
81 | super(key: key, child: child);
82 |
83 | @override
84 | bool updateShouldNotify(InheritedWidget oldWidget) => true;
85 |
86 | static ShareBLoC of(BuildContext context) =>
87 | (context.dependOnInheritedWidgetOfExactType(aspect:ShareProvider) as ShareProvider)
88 | .shareBloc;
89 | }
90 |
--------------------------------------------------------------------------------
/lib/statemanager/bloc_rxdart_widget.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:rxdart/rxdart.dart';
5 |
6 | ///
7 | ///
8 | void main() => runApp(MaterialApp(
9 | home: Scaffold(
10 | appBar: AppBar(
11 | title: Text("BLocRxDartWidget"),
12 | ),
13 | body: BLocRxDartWidget(),
14 | ),
15 | ));
16 |
17 | class BLocRxDartWidget extends StatefulWidget {
18 | @override
19 | _BLocRxDartWidgetState createState() => new _BLocRxDartWidgetState();
20 | }
21 |
22 | class _BLocRxDartWidgetState extends State {
23 | final _bloc = ShareBLoC();
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | print("_BLocWidget build context:$context}");
28 | return Center(
29 | child: ShareProvider(
30 | shareBloc: _bloc,
31 | child: StreamBuilder(
32 | stream: _bloc._countStream,
33 | initialData: 0,
34 | builder: (context2, snapshot) {
35 | return Column(
36 | mainAxisAlignment: MainAxisAlignment.center,
37 | children: [
38 | Text(
39 | "${snapshot.data}",
40 | style: TextStyle(fontSize: 40),
41 | ),
42 | ElevatedButton(
43 | child: Text("Increment (current:${snapshot.data})"),
44 | onPressed: () {
45 | ShareProvider.of(context2).increment();
46 | }),
47 | ]);
48 | }),
49 | ));
50 | }
51 | }
52 |
53 | class ShareBLoC {
54 | int _count = 0;
55 |
56 | final BehaviorSubject _countSubject = BehaviorSubject();
57 |
58 | Stream get _countStream => _countSubject.stream;
59 |
60 | ShareBLoC();
61 |
62 | void dispose() {
63 | _countSubject.close();
64 | }
65 |
66 | increment() {
67 | _countSubject.sink.add(++_count);
68 | }
69 | }
70 |
71 | class ShareProvider extends InheritedWidget {
72 | final ShareBLoC shareBloc;
73 |
74 | ShareProvider({
75 | Key? key,
76 | ShareBLoC? shareBloc,
77 | required Widget child,
78 | }) : shareBloc = shareBloc ?? ShareBLoC(),
79 | super(key: key, child: child);
80 |
81 | @override
82 | bool updateShouldNotify(InheritedWidget oldWidget) => true;
83 |
84 | static ShareBLoC of(BuildContext context) =>
85 | (context.dependOnInheritedWidgetOfExactType(aspect: ShareProvider)
86 | as ShareProvider)
87 | .shareBloc;
88 | }
89 |
--------------------------------------------------------------------------------
/lib/eventbus/my_event_bus.dart:
--------------------------------------------------------------------------------
1 | abstract class IPublisher {
2 | void post(T event);
3 | }
4 |
5 | typedef ISubscriber = void Function(T event);
6 |
7 | abstract class IEventBus extends IPublisher {
8 | void register(ISubscriber subscriber);
9 |
10 | void unregister(ISubscriber subscriber);
11 | }
12 |
13 | Type typeOf() => T;
14 |
15 | class MyEventBus1 implements IEventBus {
16 | Map> map = new Map();
17 |
18 | @override
19 | void register(ISubscriber subscriber) {
20 | Type type = typeOf();
21 | if (!map.containsKey(type)) {
22 | map[type] = List.empty(growable: true);
23 | }
24 | map[type]?.add(subscriber);
25 | }
26 |
27 | @override
28 | void unregister(ISubscriber subscriber) {
29 | Type type = typeOf();
30 | if (map.containsKey(type)) {
31 | map[type]?.remove(subscriber);
32 | }
33 | }
34 |
35 | @override
36 | void post(T event) {
37 | Type type = typeOf();
38 | if (map.containsKey(type)) {
39 | var subscribers = map[type];
40 | subscribers?.forEach((subscriber) => subscriber.call(event));
41 | }
42 | }
43 | }
44 |
45 | class MyEventBus2 implements IEventBus {
46 | List subscribers = List.empty(growable: true);
47 |
48 | @override
49 | register(ISubscriber subscriber) {
50 | if (!subscribers.contains(subscriber)) {
51 | subscribers.add(subscriber);
52 | }
53 | }
54 |
55 | @override
56 | unregister(ISubscriber subscriber) {
57 | if (subscribers.contains(subscriber)) {
58 | subscribers.remove(subscriber);
59 | }
60 | }
61 |
62 | @override
63 | post(T event) {
64 | var ints = subscribers.whereType>();
65 | for (var subscriber in ints) {
66 | subscriber.call(event);
67 | }
68 | }
69 | }
70 |
71 | class EventX {}
72 |
73 | class EventY {}
74 |
75 | //main() {
76 | // testEventBus(new MyEventBus1());
77 | // print("--------------------");
78 | // testEventBus(new MyEventBus2());
79 | //}
80 | //
81 | //void testEventBus(IEventBus eventBus) {
82 | // ISubscriber subscriber1 = (event) => print(event.toString());
83 | // ISubscriber subscriber2 = (event) => print(event.toString());
84 | // eventBus.register(subscriber1);
85 | // eventBus.register(subscriber2);
86 | // eventBus.unregister(subscriber1);
87 | //
88 | // ISubscriber subscriber3 = (event) => print(event.toString());
89 | // ISubscriber subscriber4 = (event) => print(event.toString());
90 | // eventBus.register(subscriber3);
91 | // eventBus.register(subscriber4);
92 | //
93 | // eventBus.post(new EventX());
94 | // eventBus.post(new EventY());
95 | //}
96 |
--------------------------------------------------------------------------------
/lib/statemanager/redux_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_redux/flutter_redux.dart';
3 | import 'package:provider/provider.dart';
4 | import 'package:redux/redux.dart';
5 |
6 | ///
7 | ///
8 | void main() => runApp(MaterialApp(
9 | home: Scaffold(
10 | appBar: AppBar(
11 | title: Text("ReduxWidget"),
12 | ),
13 | body: ReduxWidgetPage(),
14 | ),
15 | ));
16 |
17 | class ReduxWidgetPage extends StatefulWidget {
18 | @override
19 | _ReduxWidgetPageState createState() => new _ReduxWidgetPageState();
20 | }
21 |
22 | class _ReduxWidgetPageState extends State {
23 | final _store = Store(shareDataReducer, initialState: ShareData(0));
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | print("_ReduxWidget build context:$context}");
28 | return Center(
29 | child: StoreProvider(
30 | store: _store,
31 | child: Column(
32 | mainAxisAlignment: MainAxisAlignment.center,
33 | children: [
34 | StoreConnector(
35 | converter: (store) => store.state.count,
36 | builder: (context2, count) {
37 | print("__TestWidgetState build context:$context2");
38 | return Text(
39 | "$count",
40 | style: TextStyle(fontSize: 40),
41 | );
42 | },
43 | ),
44 | StoreConnector(
45 | converter: (store) =>
46 | (step) => store.dispatch(IncrementCountAction(step)),
47 | builder: (context2, calback) {
48 | print("__TestWidgetState build context:$context2");
49 | return ElevatedButton(
50 | child: Text(
51 | "Increment (current:${ StoreProvider.of(context2,listen: true).state.count})"),
52 | // "Increment (current)"),
53 | onPressed: () {
54 | calback(2);
55 | });
56 | },
57 | ),
58 | ],
59 | ),
60 | ),
61 | );
62 | }
63 | }
64 |
65 | class ShareData {
66 | int count = 0;
67 |
68 | ShareData(this.count);
69 |
70 | void increment(int step) {
71 | count = count + step;
72 | }
73 |
74 | ShareData.clone(ShareData state) {
75 | count = state.count;
76 | }
77 | }
78 |
79 | typedef incrementCallBack = void Function(int step);
80 |
81 | class IncrementCountAction {
82 | final int step;
83 |
84 | IncrementCountAction(this.step);
85 | }
86 |
87 | // The reducer, which takes the previous count and increments it in response
88 | // to an Increment action.
89 | ShareData shareDataReducer(ShareData state, dynamic action) {
90 | if (action is IncrementCountAction) {
91 | print('action increment count!');
92 | // Reducer always returns a state,never mutating the old
93 | return ShareData.clone(state)..increment(action.step);
94 | }
95 | return state;
96 | }
97 |
--------------------------------------------------------------------------------
/lib/eventbus/eventbus_demo_widget1.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_sample/eventbus/my_event_bus.dart';
3 | import 'package:flutter_sample/provider/post/base/eventbus_x.dart';
4 |
5 | final String eventBusDemo1Title = "自定义EventBus";
6 | MyEventBus1 _eventBus = new MyEventBus1();
7 |
8 | class EventBusDemoWidget1 extends StatefulWidget {
9 | EventBusDemoWidget1({Key? key}) : super(key: key);
10 |
11 | @override
12 | _EventBusDemoWidget1State createState() => _EventBusDemoWidget1State();
13 | }
14 |
15 | class _EventBusDemoWidget1State extends State {
16 | @override
17 | Widget build(BuildContext context) {
18 | return Scaffold(
19 | appBar: AppBar(
20 | title: Text(eventBusDemo1Title),
21 | ),
22 | body: Container(
23 | child: Column(
24 | children: [
25 | Row(
26 | children: [
27 | new ButtonWidget(event: new EventA()),
28 | new TextWidget(),
29 | new TextWidget()
30 | ],
31 | ),
32 | Divider(
33 | color: Colors.grey,
34 | ),
35 | Row(
36 | children: [
37 | new ButtonWidget(event: new EventB()),
38 | new TextWidget(),
39 | new TextWidget()
40 | ],
41 | )
42 | ],
43 | ),
44 | ),
45 | );
46 | }
47 | }
48 |
49 | class BaseEvent {
50 | int count = 0;
51 | }
52 |
53 | class EventA extends BaseEvent {}
54 |
55 | class EventB extends BaseEvent {}
56 |
57 | class ButtonWidget extends StatelessWidget {
58 | late T? event ;
59 |
60 | ButtonWidget({Key? key, this.event}) : super(key: key);
61 |
62 | @override
63 | Widget build(BuildContext context) {
64 | return ElevatedButton(
65 | child: Text("increment"),
66 | onPressed: _increment,
67 | );
68 | }
69 |
70 | void _increment() {
71 | if (event != null) {
72 | event?.count++;
73 | print(event?.count);
74 | _eventBus.post(event);
75 | }
76 | }
77 | }
78 |
79 | class TextWidget extends StatefulWidget {
80 | @override
81 | _TextWidgetState createState() {
82 | return _TextWidgetState();
83 | }
84 | }
85 |
86 | class _TextWidgetState extends State> {
87 | int _count = 0;
88 | late ISubscriber _subscriber;
89 |
90 | @override
91 | void initState() {
92 | super.initState();
93 |
94 | _subscriber =
95 | (event) => setState(() => _count = (event as BaseEvent).count);
96 | _eventBus.register(_subscriber);
97 | }
98 |
99 | @override
100 | Widget build(BuildContext context) {
101 | print(typeOf());
102 | return Text(
103 | " $_count ",
104 | style: TextStyle(fontSize: 18),
105 | );
106 | }
107 |
108 | @override
109 | void dispose() {
110 | super.dispose();
111 | _eventBus.unregister(_subscriber);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/provider/post/data/post_server.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_sample/provider/post/data/post_bean.dart';
2 | import 'package:collection/collection.dart';
3 |
4 | class PostServer {
5 | var posts = List.empty(growable: true);
6 | static PostServer? _instance;
7 |
8 | static PostServer instance() {
9 | _instance ??= PostServer._();
10 | return _instance!;
11 | }
12 |
13 | PostServer._() {
14 | posts = List.empty(growable: true);
15 | posts.add(PostBean.value(
16 | 0,
17 | true,
18 | """
19 | 水调歌头·明月几时有
20 | 明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间。(何似 一作:何时;又恐 一作:惟 / 唯恐)
21 | 转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。(长向 一作:偏向) """,
22 | ));
23 | posts.add(PostBean.value(
24 | 1,
25 | true,
26 | """
27 | 声声慢·寻寻觅觅
28 | 寻寻觅觅,冷冷清清,凄凄惨惨戚戚。乍暖还寒时候,最难将息。三杯两盏淡酒,怎敌他、晚来风急!雁过也,正伤心,却是旧时相识。
29 | 满地黄花堆积,憔悴损,如今有谁堪摘?守着窗儿,独自怎生得黑!梧桐更兼细雨,到黄昏、点点滴滴。这次第,怎一个愁字了得!(守着窗儿 一作:守著窗儿)
30 | """,
31 | ));
32 | posts.add(PostBean.value(
33 | 2,
34 | true,
35 | """
36 | 凤凰台上忆吹箫·香冷金猊
37 | 香冷金猊,被翻红浪,起来慵自梳头。任宝奁尘满,日上帘钩。生怕离怀别苦,多少事、欲说还休。新来瘦,非干病酒,不是悲秋。
38 | 休休,这回去也,千万遍《阳关》,也则难留。念武陵人远,烟锁秦楼。惟有楼前流水,应念我、终日凝眸。凝眸处,从今又添,一段新愁。(版本一)
39 |
40 | 香冷金猊,被翻红浪,起来人未梳头。任宝奁闲掩,日上帘钩。生怕闲愁暗恨,多少事、欲说还休。今年瘦,非干病酒,不是悲秋。
41 | 明朝,者回去也,千万遍阳关,也即难留。念武陵春晚,云锁重楼。记取楼前绿水,应念我、终日凝眸。凝眸处,从今更数,几段新愁。(版本二)
42 | """,
43 | ));
44 | posts.add(PostBean.value(
45 | 3,
46 | true,
47 | """
48 | 绮寮怨·上马人扶残醉
49 | 上马人扶残醉,晓风吹未醒。映水曲、翠瓦朱檐,垂杨里、乍见津亭。当时曾题败壁,蛛丝罩、淡墨苔晕青。念去来、岁月如流,徘徊久、叹息愁思盈。
50 | 去去倦寻路程。江陵旧事,何曾再问杨琼。旧曲凄清。敛愁黛、与谁听。尊前故人如在,想念我、最关情。何须渭城。歌声未尽处,先泪零。 """,
51 | ));
52 | posts.add(PostBean.value(
53 | 4,
54 | true,
55 | """
56 | 满江红·小院深深
57 | 小院深深,悄镇日、阴晴无据。春未足,闺愁难寄,琴心谁与?曲径穿花寻蛱蝶,虚阑傍日教鹦鹉。笑十三杨柳女儿腰,东风舞。
58 | 云外月,风前絮。情与恨,长如许。想绮窗今夜,为谁凝伫?洛浦梦回留佩客,秦楼声断吹箫侣。正黄昏时候杏花寒,廉纤雨。""",
59 | ));
60 | posts.add(PostBean.value(
61 | 5,
62 | true,
63 | """
64 | 花心动·春词
65 | 仙苑春浓,小桃开,枝枝已堪攀折。乍雨乍晴,轻暖轻寒,渐近赏花时节。柳摇台榭东风软,帘栊静,幽禽调舌。断魂远,闲寻翠径,顿成愁结。
66 | 此恨无人共说。还立尽黄昏,寸心空切。强整绣衾,独掩朱扉,枕簟为谁铺设。夜长更漏传声远,纱窗映、银缸明灭。梦回处,梅梢半笼残月。
67 | """,
68 | ));
69 | posts.add(PostBean.value(
70 | 6,
71 | true,
72 | """
73 | 安公子·远岸收残雨
74 | 远岸收残雨。雨残稍觉江天暮。拾翠汀洲人寂静,立双双鸥鹭。望几点、渔灯隐映蒹葭浦。停画桡、两两舟人语。道去程今夜,遥指前村烟树。
75 | 游宦成羁旅。短樯吟倚闲凝伫。万水千山迷远近,想乡关何处。自别后、风亭月榭孤欢聚。刚断肠、惹得离情苦。听杜宇声声,劝人不如归去。
76 | """,
77 | ));
78 | }
79 |
80 | Future>> loadPosts() async {
81 | await Future.delayed(const Duration(milliseconds: 300));
82 | return posts.map(((post) => post.toMap())).toList();
83 | }
84 |
85 | Future