├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── auto-assign.yml │ ├── flutter-example.yml │ ├── publish-github-release.yml │ └── rxdart-test.yml ├── .gitignore ├── AUTHORS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets └── logo.png ├── codecov.yml ├── examples ├── fibonacci │ ├── .gitignore │ ├── analysis_options.yaml │ ├── lib │ │ └── example.dart │ ├── pubspec.lock │ └── pubspec.yaml ├── flutter │ └── github_search │ │ ├── .gitignore │ │ ├── .metadata │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── github_search │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values-night │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ └── settings.gradle │ │ ├── fonts │ │ ├── hind │ │ │ ├── DESCRIPTION.en_us.html │ │ │ ├── Hind-Bold.ttf │ │ │ ├── Hind-Light.ttf │ │ │ ├── Hind-Medium.ttf │ │ │ ├── Hind-Regular.ttf │ │ │ ├── Hind-Semibold.ttf │ │ │ ├── METADATA.json │ │ │ └── OFL.txt │ │ └── montserrat │ │ │ ├── DESCRIPTION.en_us.html │ │ │ ├── METADATA.json │ │ │ ├── Montserrat-Black.ttf │ │ │ ├── Montserrat-Bold.ttf │ │ │ ├── Montserrat-Light.ttf │ │ │ ├── Montserrat-Regular.ttf │ │ │ ├── Montserrat-Thin.ttf │ │ │ └── OFL.txt │ │ ├── ios │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── Runner │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── Runner-Bridging-Header.h │ │ │ └── main.m │ │ ├── lib │ │ ├── api │ │ │ └── github_api.dart │ │ ├── bloc │ │ │ ├── search_bloc.dart │ │ │ └── search_state.dart │ │ ├── main.dart │ │ ├── search_screen.dart │ │ └── widget │ │ │ ├── empty_result_widget.dart │ │ │ ├── search_error_widget.dart │ │ │ ├── search_intro_widget.dart │ │ │ ├── search_loading_widget.dart │ │ │ └── search_result_widget.dart │ │ ├── linux │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── flutter │ │ │ ├── CMakeLists.txt │ │ │ ├── generated_plugin_registrant.cc │ │ │ ├── generated_plugin_registrant.h │ │ │ └── generated_plugins.cmake │ │ ├── main.cc │ │ ├── my_application.cc │ │ └── my_application.h │ │ ├── macos │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── Flutter-Debug.xcconfig │ │ │ ├── Flutter-Release.xcconfig │ │ │ └── GeneratedPluginRegistrant.swift │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ │ └── xcshareddata │ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── Runner │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── app_icon_1024.png │ │ │ │ │ ├── app_icon_128.png │ │ │ │ │ ├── app_icon_16.png │ │ │ │ │ ├── app_icon_256.png │ │ │ │ │ ├── app_icon_32.png │ │ │ │ │ ├── app_icon_512.png │ │ │ │ │ └── app_icon_64.png │ │ │ ├── Base.lproj │ │ │ │ └── MainMenu.xib │ │ │ ├── Configs │ │ │ │ ├── AppInfo.xcconfig │ │ │ │ ├── Debug.xcconfig │ │ │ │ ├── Release.xcconfig │ │ │ │ └── Warnings.xcconfig │ │ │ ├── DebugProfile.entitlements │ │ │ ├── Info.plist │ │ │ ├── MainFlutterWindow.swift │ │ │ └── Release.entitlements │ │ └── RunnerTests │ │ │ └── RunnerTests.swift │ │ ├── pubspec.lock │ │ ├── pubspec.yaml │ │ ├── test │ │ └── search_bloc_test.dart │ │ ├── web │ │ ├── favicon.png │ │ ├── icons │ │ │ ├── Icon-192.png │ │ │ ├── Icon-512.png │ │ │ ├── Icon-maskable-192.png │ │ │ └── Icon-maskable-512.png │ │ ├── index.html │ │ └── manifest.json │ │ └── windows │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── flutter │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ │ └── runner │ │ ├── CMakeLists.txt │ │ ├── Runner.rc │ │ ├── flutter_window.cpp │ │ ├── flutter_window.h │ │ ├── main.cpp │ │ ├── resource.h │ │ ├── resources │ │ └── app_icon.ico │ │ ├── runner.exe.manifest │ │ ├── utils.cpp │ │ ├── utils.h │ │ ├── win32_window.cpp │ │ └── win32_window.h └── web │ ├── .gitignore │ ├── analysis_options.yaml │ ├── build.yaml │ ├── pubspec.lock │ ├── pubspec.yaml │ └── web │ ├── dragdrop │ ├── dragdrop.dart │ └── dragdrop.html │ ├── index.html │ ├── konami │ ├── konamicode.dart │ └── konamicode.html │ └── search_github │ ├── search_github.dart │ └── search_github.html ├── melos.yaml ├── packages ├── rxdart │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ ├── rxdart.dart │ │ ├── src │ │ │ ├── rx.dart │ │ │ ├── streams │ │ │ │ ├── combine_latest.dart │ │ │ │ ├── concat.dart │ │ │ │ ├── concat_eager.dart │ │ │ │ ├── connectable_stream.dart │ │ │ │ ├── defer.dart │ │ │ │ ├── fork_join.dart │ │ │ │ ├── from_callable.dart │ │ │ │ ├── merge.dart │ │ │ │ ├── never.dart │ │ │ │ ├── race.dart │ │ │ │ ├── range.dart │ │ │ │ ├── repeat.dart │ │ │ │ ├── replay_stream.dart │ │ │ │ ├── retry.dart │ │ │ │ ├── retry_when.dart │ │ │ │ ├── sequence_equal.dart │ │ │ │ ├── switch_latest.dart │ │ │ │ ├── timer.dart │ │ │ │ ├── using.dart │ │ │ │ ├── value_stream.dart │ │ │ │ └── zip.dart │ │ │ ├── subjects │ │ │ │ ├── behavior_subject.dart │ │ │ │ ├── publish_subject.dart │ │ │ │ ├── replay_subject.dart │ │ │ │ └── subject.dart │ │ │ ├── transformers │ │ │ │ ├── backpressure │ │ │ │ │ ├── backpressure.dart │ │ │ │ │ ├── buffer.dart │ │ │ │ │ ├── debounce.dart │ │ │ │ │ ├── pairwise.dart │ │ │ │ │ ├── sample.dart │ │ │ │ │ ├── throttle.dart │ │ │ │ │ └── window.dart │ │ │ │ ├── default_if_empty.dart │ │ │ │ ├── delay.dart │ │ │ │ ├── delay_when.dart │ │ │ │ ├── dematerialize.dart │ │ │ │ ├── distinct_unique.dart │ │ │ │ ├── do.dart │ │ │ │ ├── end_with.dart │ │ │ │ ├── end_with_many.dart │ │ │ │ ├── exhaust_map.dart │ │ │ │ ├── flat_map.dart │ │ │ │ ├── group_by.dart │ │ │ │ ├── ignore_elements.dart │ │ │ │ ├── interval.dart │ │ │ │ ├── map_not_null.dart │ │ │ │ ├── map_to.dart │ │ │ │ ├── materialize.dart │ │ │ │ ├── max.dart │ │ │ │ ├── min.dart │ │ │ │ ├── on_error_resume.dart │ │ │ │ ├── scan.dart │ │ │ │ ├── skip_last.dart │ │ │ │ ├── skip_until.dart │ │ │ │ ├── start_with.dart │ │ │ │ ├── start_with_error.dart │ │ │ │ ├── start_with_many.dart │ │ │ │ ├── switch_if_empty.dart │ │ │ │ ├── switch_map.dart │ │ │ │ ├── take_last.dart │ │ │ │ ├── take_until.dart │ │ │ │ ├── take_while_inclusive.dart │ │ │ │ ├── time_interval.dart │ │ │ │ ├── timestamp.dart │ │ │ │ ├── where_not_null.dart │ │ │ │ ├── where_type.dart │ │ │ │ └── with_latest_from.dart │ │ │ └── utils │ │ │ │ ├── collection_extensions.dart │ │ │ │ ├── composite_subscription.dart │ │ │ │ ├── empty.dart │ │ │ │ ├── error_and_stacktrace.dart │ │ │ │ ├── forwarding_sink.dart │ │ │ │ ├── forwarding_stream.dart │ │ │ │ ├── future.dart │ │ │ │ ├── min_max.dart │ │ │ │ ├── notification.dart │ │ │ │ └── subscription.dart │ │ ├── streams.dart │ │ ├── subjects.dart │ │ ├── transformers.dart │ │ └── utils.dart │ ├── pubspec.yaml │ ├── screenshots │ │ └── logo.png │ └── test │ │ ├── rxdart_test.dart │ │ ├── streams │ │ ├── combine_latest_test.dart │ │ ├── concat_eager_test.dart │ │ ├── concat_test.dart │ │ ├── defer_test.dart │ │ ├── fork_join_test.dart │ │ ├── from_callable_test.dart │ │ ├── merge_test.dart │ │ ├── never_test.dart │ │ ├── publish_connectable_stream_test.dart │ │ ├── race_test.dart │ │ ├── range_test.dart │ │ ├── repeat_test.dart │ │ ├── replay_connectable_stream_test.dart │ │ ├── retry_test.dart │ │ ├── retry_when_test.dart │ │ ├── sequence_equals_test.dart │ │ ├── switch_latest_test.dart │ │ ├── timer_test.dart │ │ ├── using_test.dart │ │ ├── value_connectable_stream_test.dart │ │ └── zip_test.dart │ │ ├── subject │ │ ├── behavior_subject_test.dart │ │ ├── publish_subject_test.dart │ │ └── replay_subject_test.dart │ │ ├── transformers │ │ ├── backpressure │ │ │ ├── buffer_count_test.dart │ │ │ ├── buffer_test.dart │ │ │ ├── buffer_test_test.dart │ │ │ ├── buffer_time_test.dart │ │ │ ├── debounce_test.dart │ │ │ ├── debounce_time_test.dart │ │ │ ├── pairwise_test.dart │ │ │ ├── sample_test.dart │ │ │ ├── sample_time_test.dart │ │ │ ├── throttle_test.dart │ │ │ ├── throttle_time_test.dart │ │ │ ├── window_count_test.dart │ │ │ ├── window_test.dart │ │ │ ├── window_test_test.dart │ │ │ └── window_time_test.dart │ │ ├── concat_with_test.dart │ │ ├── default_if_empty_test.dart │ │ ├── delay_test.dart │ │ ├── delay_when_test.dart │ │ ├── dematerialize_test.dart │ │ ├── distinct_test.dart │ │ ├── distinct_unique_test.dart │ │ ├── do_test.dart │ │ ├── end_with_many_test.dart │ │ ├── end_with_test.dart │ │ ├── exhaust_map_test.dart │ │ ├── flat_map_iterable_test.dart │ │ ├── flat_map_test.dart │ │ ├── group_by_test.dart │ │ ├── ignore_elements_test.dart │ │ ├── interval_test.dart │ │ ├── join_test.dart │ │ ├── map_not_null_test.dart │ │ ├── map_to_test.dart │ │ ├── materialize_test.dart │ │ ├── max_test.dart │ │ ├── merge_with_test.dart │ │ ├── min_test.dart │ │ ├── on_error_resume_test.dart │ │ ├── on_error_return_test.dart │ │ ├── on_error_return_with_test.dart │ │ ├── scan_test.dart │ │ ├── skip_last_test.dart │ │ ├── skip_until_test.dart │ │ ├── start_with_error_test.dart │ │ ├── start_with_many_test.dart │ │ ├── start_with_test.dart │ │ ├── switch_if_empty_test.dart │ │ ├── switch_map_test.dart │ │ ├── take_last_test.dart │ │ ├── take_until_test.dart │ │ ├── take_while_inclusive_test.dart │ │ ├── time_interval_test.dart │ │ ├── timeout_test.dart │ │ ├── timestamp_test.dart │ │ ├── where_not_null_test.dart │ │ ├── where_type_test.dart │ │ ├── with_latest_from_test.dart │ │ └── zip_with_test.dart │ │ ├── utils.dart │ │ └── utils │ │ ├── composite_subscription_test.dart │ │ └── notification_test.dart └── rxdart_flutter │ ├── .gitignore │ ├── .metadata │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── example │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ └── main.dart │ ├── pubspec.lock │ └── pubspec.yaml │ ├── lib │ ├── rxdart_flutter.dart │ └── src │ │ ├── errors.dart │ │ ├── value_stream_builder.dart │ │ ├── value_stream_consumer.dart │ │ └── value_stream_listener.dart │ ├── pubspec.yaml │ ├── screenshots │ └── logo.png │ └── test │ └── src │ ├── not_replay_value_stream_builder_test.dart │ ├── not_replay_value_stream_consumer_test.dart │ ├── not_replay_value_stream_listener_test.dart │ ├── rxdart_ext │ └── value_subject.dart │ ├── value_stream_builder_test.dart │ ├── value_stream_consumer_test.dart │ └── value_stream_listener_test.dart ├── pubspec.lock └── pubspec.yaml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in 5 | # the repo. Unless a later match takes precedence, 6 | # @global-owner1 and @global-owner2 will be requested for 7 | # review when someone opens a pull request. 8 | * @hoc081098 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | enable-beta-ecosystems: true 3 | updates: 4 | - package-ecosystem: "pub" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | -------------------------------------------------------------------------------- /.github/workflows/auto-assign.yml: -------------------------------------------------------------------------------- 1 | name: Auto Assign 2 | on: 3 | issues: 4 | types: [opened] 5 | pull_request: 6 | types: [opened] 7 | jobs: 8 | run: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | steps: 14 | - name: 'Auto-assign issue' 15 | uses: pozil/auto-assign-issue@v1 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | assignees: hoc081098 19 | numOfAssignee: 1 20 | allowSelfAssign: true 21 | -------------------------------------------------------------------------------- /.github/workflows/flutter-example.yml: -------------------------------------------------------------------------------- 1 | name: Build Flutter example 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: [ '**.md' ] 7 | pull_request: 8 | branches: [ master ] 9 | paths-ignore: [ '**.md' ] 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | defaults: 15 | run: 16 | working-directory: ./examples/flutter/github_search 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - uses: actions/setup-java@v3 21 | with: 22 | distribution: 'zulu' 23 | java-version: '17' 24 | 25 | - uses: subosito/flutter-action@v2.18.0 26 | with: 27 | channel: 'stable' 28 | 29 | - name: Install melos 30 | run: dart pub global activate melos 31 | 32 | - name: Melos Boostrap 33 | run: melos bootstrap 34 | 35 | - name: Print Dart SDK version 36 | run: dart --version 37 | 38 | - name: Print Flutter SDK version 39 | run: flutter --version 40 | 41 | - name: Install dependencies 42 | run: flutter pub get 43 | 44 | - name: Format code 45 | run: dart format lib --set-exit-if-changed 46 | 47 | - name: Analyze 48 | run: flutter analyze lib 49 | 50 | - name: Build Debug APK 51 | run: flutter build apk --debug --no-shrink 52 | -------------------------------------------------------------------------------- /.github/workflows/publish-github-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish GitHub Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '**' 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | create-gh-release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 17 | 18 | - name: Extract release notes 19 | id: release_notes 20 | uses: ffurrer2/extract-release-notes@v2 21 | with: 22 | changelog_file: ${{ github.workspace }}/packages/rxdart/CHANGELOG.md 23 | 24 | - name: Create release 25 | uses: softprops/action-gh-release@v2 26 | with: 27 | body: ${{ steps.release_notes.outputs.release_notes }} 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.github/workflows/rxdart-test.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: [ '**.md', 'examples/**' ] 7 | pull_request: 8 | branches: [ master ] 9 | paths-ignore: [ '**.md', 'examples/**' ] 10 | schedule: 11 | # Runs at 00:00 UTC on the 1, 8, 15, 22 and 29th of every month. 12 | - cron: '0 0 */7 * *' 13 | workflow_dispatch: 14 | 15 | jobs: 16 | analyze-and-test: 17 | runs-on: ubuntu-latest 18 | 19 | strategy: 20 | matrix: 21 | # sdk: [ beta, stable, 2.17.0, 2.15.0, 2.12.0 ] 22 | flutter: [ beta, stable, 3.0.0, 2.8.0, 2.0.1 ] 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | - name: Setup Stable/Beta Flutter/Dart 28 | if: ${{ matrix.flutter == 'stable' || matrix.flutter == 'beta' }} 29 | uses: subosito/flutter-action@v2.18.0 30 | with: 31 | channel: ${{ matrix.flutter }} 32 | 33 | - name: Setup Older Flutter/Dart 34 | if: ${{ matrix.flutter != 'stable' && matrix.flutter != 'beta' }} 35 | uses: subosito/flutter-action@v2.18.0 36 | with: 37 | flutter-version: ${{ matrix.flutter }} 38 | 39 | - name: Install melos 40 | run: dart pub global activate melos 41 | 42 | - name: Print Dart SDK version 43 | run: dart --version 44 | 45 | - name: Print Flutter SDK version 46 | run: flutter --version 47 | 48 | - name: Install dependencies 49 | run: melos run pub-get-no-private 50 | 51 | - name: Analyze 52 | if: ${{ matrix.flutter == 'stable' }} 53 | run: melos run analyze-no-private 54 | 55 | - name: Format code 56 | if: ${{ matrix.flutter == 'stable' }} 57 | run: melos run format-no-private 58 | 59 | - name: Active coverage 60 | run: dart pub global activate coverage 61 | 62 | - name: Run rxdart tests 63 | run: melos run test-rxdart 64 | 65 | - uses: codecov/codecov-action@v3.1.6 66 | if: ${{ matrix.flutter == 'stable' }} 67 | 68 | - name: Run rxdart_flutter tests 69 | run: melos run test-rxdart-flutter 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don’t commit the following directories created by pub. 2 | .buildlog 3 | .dart_tool/ 4 | .pub/ 5 | build/ 6 | *.packages 7 | .idea/ 8 | web/experimental 9 | doc 10 | .dart_tool/ 11 | 12 | # Or the files created by dart2js. 13 | *.dart.js 14 | *.js_ 15 | *.js.deps 16 | *.js.map 17 | 18 | # Include when developing application packages. 19 | coverage* 20 | lcov.info 21 | 22 | # https://melos.invertase.dev/~melos-latest/getting-started#configure-the-workspace 23 | pubspec_overrides.yaml 24 | 25 | # Miscellaneous 26 | *.class 27 | *.log 28 | *.pyc 29 | *.swp 30 | .DS_Store 31 | .atom/ 32 | .buildlog/ 33 | .history 34 | .svn/ 35 | migrate_working_dir/ 36 | 37 | # IntelliJ related 38 | *.iml 39 | *.ipr 40 | *.iws 41 | .idea/ -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the list of rxdart's significant contributors. 2 | # 3 | # This does not necessarily list everyone who has contributed code. 4 | # To see the full list of contributors, see the revision history in 5 | # source control. 6 | Frank Pepermans 7 | Brian Egan 8 | Petrus Nguyen Thai Hoc -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to RxDart 2 | 3 | ## Create a new issue 4 | 5 | The easiest way to get involved is to create a [new issue](https://github.com/ReactiveX/rxdart/issues/new) when you spot a bug, if the documentation is incomplete or out of date, or if you identify an implementation problem. 6 | 7 | ## General coding guidlines 8 | 9 | If you'd like to add a feature or fix a bug, we're more than happy to accept pull requests! We only ask a few things: 10 | 11 | - Ensure your code contains no analyzer errors, e.g. 12 | - Code is strong-mode compliant 13 | - Code is free of lint errors 14 | - Format your code with `dart format` 15 | - Write tests for all new code paths, consider using the [Stream Matchers](https://pub.dartlang.org/packages/test#stream-matchers) available from the test package. 16 | - Write helpful documentation 17 | - If you would like to make a bigger / fundamental change to the codebase, please file a lightweight example PR / issue, or contact us in [Gitter](https://gitter.im/ReactiveX/rxdart) so we can discuss the issue. 18 | 19 | ## Advice when adding a new Stream 20 | 21 | - Extend from `Stream` 22 | - Add the new `Stream` to the exported `rx_streams` library 23 | - If the Stream is not a broadcast stream, ensure it properly enforces the single-subscription contract 24 | - Ensure the stream closes properly 25 | - Add new tests to `tests/rxdart_test.dart` 26 | 27 | ## Advice when adding a new operator 28 | 29 | - Extend from the `StreamTransformer` class so it can be used independently 30 | - Use the `StreamTransformer` in an `extension` method 31 | - Add the new `StreamTransformer` to the exported `rx_transformers` library 32 | - Ensure the `StreamTransformer` can be re-used 33 | - Add new tests to `tests/rxdart_test.dart` 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxDart 2 | 3 |

4 | build 5 |

6 | 7 |

8 | RxDart 9 |

10 | 11 | [![Build Status](https://github.com/ReactiveX/rxdart/workflows/Dart%20CI/badge.svg)](https://github.com/ReactiveX/rxdart/actions) 12 | [![codecov](https://codecov.io/gh/ReactiveX/rxdart/branch/master/graph/badge.svg)](https://codecov.io/gh/ReactiveX/rxdart) 13 | [![Pub](https://img.shields.io/pub/v/rxdart.svg)](https://pub.dartlang.org/packages/rxdart) 14 | [![Pub Version (including pre-releases)](https://img.shields.io/pub/v/rxdart?include_prereleases&color=%23A0147B)](https://pub.dartlang.org/packages/rxdart) 15 | [![Gitter](https://img.shields.io/gitter/room/ReactiveX/rxdart.svg)](https://gitter.im/ReactiveX/rxdart) 16 | [![Flutter website](https://img.shields.io/badge/flutter-website-deepskyblue.svg)](https://docs.flutter.dev/data-and-backend/state-mgmt/options#bloc--rx) 17 | [![Build Flutter example](https://github.com/ReactiveX/rxdart/actions/workflows/flutter-example.yml/badge.svg)](https://github.com/ReactiveX/rxdart/actions/workflows/flutter-example.yml) 18 | [![License](https://img.shields.io/github/license/ReactiveX/rxdart)](https://www.apache.org/licenses/LICENSE-2.0) 19 | [![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2FReactiveX%2Frxdart&count_bg=%23D71092&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com) 20 | 21 | RxDart is an implementation of the popular ReactiveX api for asynchronous 22 | programming, leveraging the native Dart Streams api. 23 | 24 | ## Packages 25 | 26 | | Package | Pub | 27 | |---------------------------------------------|-------------------------------------------------------------------------------------------------------------| 28 | | [`rxdart`](packages/rxdart) | [![Pub](https://img.shields.io/pub/v/rxdart.svg)](https://pub.dartlang.org/packages/rxdart) | 29 | | [`rxdart_flutter`](packages/rxdart_flutter) | [![Pub](https://img.shields.io/pub/v/rxdart_flutter.svg)](https://pub.dartlang.org/packages/rxdart_flutter) | 30 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/assets/logo.png -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "70...100" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | notify: 16 | gitter: 17 | default: 18 | url: "https://webhooks.gitter.im/e/13a7391e854a677bad98" 19 | threshold: 1% 20 | 21 | parsers: 22 | gcov: 23 | branch_detection: 24 | conditional: yes 25 | loop: yes 26 | method: no 27 | macro: no 28 | 29 | comment: 30 | layout: "header, diff" 31 | behavior: default 32 | require_changes: no -------------------------------------------------------------------------------- /examples/fibonacci/.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | *.mocks.dart 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | -------------------------------------------------------------------------------- /examples/fibonacci/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | 3 | analyzer: 4 | language: 5 | strict-casts: true 6 | strict-raw-types: true 7 | 8 | linter: 9 | rules: 10 | - always_declare_return_types # https://github.com/dart-lang/lints#migrating-from-packagepedantic 11 | - prefer_single_quotes # https://github.com/dart-lang/lints#migrating-from-packagepedantic 12 | - unawaited_futures # https://github.com/dart-lang/lints#migrating-from-packagepedantic 13 | -------------------------------------------------------------------------------- /examples/fibonacci/lib/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:rxdart/rxdart.dart'; 2 | 3 | /// generate n-amount of fibonacci numbers 4 | /// 5 | /// for example: dart fibonacci.dart 10 6 | /// outputs: 7 | /// 1: 1 8 | /// 2: 1 9 | /// 3: 2 10 | /// 4: 3 11 | /// 5: 5 12 | /// 6: 8 13 | /// 7: 13 14 | /// 8: 21 15 | /// 9: 34 16 | /// 10: 55 17 | /// done! 18 | void main(List arguments) { 19 | // read the command line argument, if none provided, default to 10 20 | var n = (arguments.length == 1) ? int.parse(arguments.first) : 10; 21 | 22 | // seed value: this value will be used as the 23 | // starting value for the [scan] method 24 | const seed = IndexedPair(1, 1, 0); 25 | 26 | Rx 27 | // amount of numbers to compute 28 | .range(1, n) 29 | // accumulator: computes a new accumulated 30 | // value each time a [Stream] event occurs 31 | // in this case, the accumulated value is always 32 | // the latest Fibonacci number 33 | .scan((IndexedPair seq, _, __) => IndexedPair.next(seq), seed) 34 | // finally, print the output 35 | .listen(print, onDone: () => print('done!')); 36 | } 37 | 38 | class IndexedPair { 39 | final int n1, n2, index; 40 | 41 | const IndexedPair(this.n1, this.n2, this.index); 42 | 43 | factory IndexedPair.next(IndexedPair prev) => IndexedPair( 44 | prev.n2, prev.index <= 1 ? prev.n1 : prev.n1 + prev.n2, prev.index + 1); 45 | 46 | @override 47 | String toString() => '$index: $n2'; 48 | } 49 | -------------------------------------------------------------------------------- /examples/fibonacci/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | lints: 5 | dependency: "direct dev" 6 | description: 7 | name: lints 8 | sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "4.0.0" 12 | rxdart: 13 | dependency: "direct main" 14 | description: 15 | path: "../../packages/rxdart" 16 | relative: true 17 | source: path 18 | version: "0.28.0" 19 | sdks: 20 | dart: ">=3.1.0 <4.0.0" 21 | -------------------------------------------------------------------------------- /examples/fibonacci/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart_fibonacci_example 2 | publish_to: none 3 | 4 | environment: 5 | sdk: '>=3.0.0 <4.0.0' 6 | 7 | dependencies: 8 | rxdart: 9 | path: ../../packages/rxdart 10 | 11 | dev_dependencies: 12 | lints: ^4.0.0 13 | -------------------------------------------------------------------------------- /examples/flutter/github_search/.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | *.mocks.dart 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | -------------------------------------------------------------------------------- /examples/flutter/github_search/.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. 5 | 6 | version: 7 | revision: 62bd79521d8d007524e351747471ba66696fc2d4 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 17 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 18 | - platform: android 19 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 20 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 21 | - platform: ios 22 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 23 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 24 | - platform: linux 25 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 26 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 27 | - platform: macos 28 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 29 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 30 | - platform: web 31 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 32 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 33 | - platform: windows 34 | create_revision: 62bd79521d8d007524e351747471ba66696fc2d4 35 | base_revision: 62bd79521d8d007524e351747471ba66696fc2d4 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /examples/flutter/github_search/README.md: -------------------------------------------------------------------------------- 1 | ## Flutter Github Search Example 2 | 3 | This example makes use of the bloc pattern [presented by Paolo Soares at DartConf](https://www.youtube.com/watch?v=PLHln7wHgPE). 4 | 5 | ### Run the example 6 | 7 | This example requires Dart 2 be enabled. To run the example: 8 | 9 | `flutter run --preview-dart-2` 10 | -------------------------------------------------------------------------------- /examples/flutter/github_search/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | analyzer: 4 | language: 5 | strict-casts: true 6 | strict-raw-types: true 7 | strict-inference: true 8 | 9 | linter: 10 | rules: 11 | - prefer_final_locals 12 | - prefer_relative_imports 13 | - always_declare_return_types # https://github.com/dart-lang/lints#migrating-from-packagepedantic 14 | - prefer_single_quotes # https://github.com/dart-lang/lints#migrating-from-packagepedantic 15 | - unawaited_futures # https://github.com/dart-lang/lints#migrating-from-packagepedantic 16 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | kotlin { 8 | jvmToolchain { 9 | languageVersion = JavaLanguageVersion.of(17) 10 | vendor = JvmVendorSpec.AZUL 11 | } 12 | } 13 | 14 | def localProperties = new Properties() 15 | def localPropertiesFile = rootProject.file('local.properties') 16 | if (localPropertiesFile.exists()) { 17 | localPropertiesFile.withReader('UTF-8') { reader -> 18 | localProperties.load(reader) 19 | } 20 | } 21 | 22 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 23 | if (flutterVersionCode == null) { 24 | flutterVersionCode = '1' 25 | } 26 | 27 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 28 | if (flutterVersionName == null) { 29 | flutterVersionName = '1.0' 30 | } 31 | 32 | android { 33 | compileSdkVersion flutter.compileSdkVersion 34 | namespace "com.example.github_search" 35 | 36 | compileOptions { 37 | sourceCompatibility JavaVersion.VERSION_1_8 38 | targetCompatibility JavaVersion.VERSION_1_8 39 | } 40 | 41 | kotlinOptions { 42 | jvmTarget = '1.8' 43 | } 44 | 45 | sourceSets { 46 | main.java.srcDirs += 'src/main/kotlin' 47 | } 48 | 49 | lintOptions { 50 | disable 'InvalidPackage' 51 | } 52 | 53 | defaultConfig { 54 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 55 | applicationId "com.example.github_search" 56 | minSdkVersion flutter.minSdkVersion 57 | targetSdkVersion flutter.targetSdkVersion 58 | versionCode flutterVersionCode.toInteger() 59 | versionName flutterVersionName 60 | } 61 | 62 | buildTypes { 63 | release { 64 | // TODO: Add your own signing config for the release build. 65 | // Signing with the debug keys for now, so `flutter run --release` works. 66 | signingConfig signingConfigs.debug 67 | } 68 | } 69 | } 70 | 71 | flutter { 72 | source '../..' 73 | } 74 | 75 | dependencies {} 76 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/kotlin/com/example/github_search/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.github_search 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } -------------------------------------------------------------------------------- /examples/flutter/github_search/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | android.enableR8=true 5 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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-8.10-bin.zip 7 | -------------------------------------------------------------------------------- /examples/flutter/github_search/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.5.2" apply false 22 | id "org.jetbrains.kotlin.android" version "2.0.20" apply false 23 | id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0") 24 | } 25 | 26 | rootProject.name = "github_search" 27 | include ":app" 28 | -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/DESCRIPTION.en_us.html: -------------------------------------------------------------------------------- 1 |

Hind is an Open Source typeface supporting the Devanagari and Latin scripts. Developed explicitly for use in User Interface design, the Hind font family includes five styles. Hind’s letterforms have a humanist-style construction, which is paired with seemingly monolinear strokes. Most of these strokes have flat endings: they either terminate with a horizontal or a vertical shear, rather than on a diagonal. This helps create clear-cut counter forms between the characters. In addition to this, Hind’s letterforms feature open apertures. The entire typeface family feels very legible when used to set text.

2 | 3 |

The Devanagari and Latin script components are scaled in relation to each other so that the Devanagari headline falls just below the Latin capital-height. In other words, the Devanagari base characters are 94% as tall as the Latin uppercase. Text set in the Devanagari script sits nicely alongside the Latin lowercase, too. Hind’s Devanagari vowel marks take forms that tends toward the traditional end of the design spectrum, while the knotted terminals, etc. inside of the base characters feature a treatment that appears more contemporary.

4 | 5 |

Each font in the Hind family has 1146 glyphs, which include hundreds of unique Devanagari conjuncts. These ensure full support for the major languages written with the Devanagari script. The Latin component’s character set is a basic western one, which enables typesetting in English and the other Western European languages. Hind is a solid choice for UI design, and a wise selection for electronic display embedding.

6 | 7 |

Manushi Parikh designed Hind for the Indian Type Foundry, who first published the fonts in 2014.

-------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/Hind-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/hind/Hind-Bold.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/Hind-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/hind/Hind-Light.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/Hind-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/hind/Hind-Medium.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/Hind-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/hind/Hind-Regular.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/Hind-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/hind/Hind-Semibold.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/hind/METADATA.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hind", 3 | "designer": "Indian Type Foundry", 4 | "license": "OFL", 5 | "visibility": "External", 6 | "category": "Sans Serif", 7 | "size": 79589, 8 | "fonts": [ 9 | { 10 | "name": "Hind", 11 | "style": "normal", 12 | "weight": 700, 13 | "filename": "Hind-Bold.ttf", 14 | "postScriptName": "Hind-Bold", 15 | "fullName": "Hind Bold", 16 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 17 | }, 18 | { 19 | "name": "Hind", 20 | "style": "normal", 21 | "weight": 300, 22 | "filename": "Hind-Light.ttf", 23 | "postScriptName": "Hind-Light", 24 | "fullName": "Hind Light", 25 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 26 | }, 27 | { 28 | "name": "Hind", 29 | "style": "normal", 30 | "weight": 500, 31 | "filename": "Hind-Medium.ttf", 32 | "postScriptName": "Hind-Medium", 33 | "fullName": "Hind Medium", 34 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 35 | }, 36 | { 37 | "name": "Hind", 38 | "style": "normal", 39 | "weight": 400, 40 | "filename": "Hind-Regular.ttf", 41 | "postScriptName": "Hind-Regular", 42 | "fullName": "Hind Regular", 43 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 44 | }, 45 | { 46 | "name": "Hind", 47 | "style": "normal", 48 | "weight": 600, 49 | "filename": "Hind-Semibold.ttf", 50 | "postScriptName": "Hind-Semibold", 51 | "fullName": "Hind Semibold", 52 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 53 | } 54 | ], 55 | "subsets": [ 56 | "latin", 57 | "latin-ext", 58 | "devanagari", 59 | "menu" 60 | ], 61 | "dateAdded": "2014-06-25" 62 | } 63 | -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/DESCRIPTION.en_us.html: -------------------------------------------------------------------------------- 1 |

The old posters and signs in the traditional neighborhood of Buenos Aires 2 | called Montserrat inspired me to design a typeface that rescues the beauty of 3 | urban typography from the first half of the twentieth century. The goal is to 4 | rescue what is in Montserrat and set it free, under a free, libre and open 5 | source license, the SIL Open Font License.

6 | 7 |

As urban development changes this place, it will never return to its 8 | original form and loses forever the designs that are so special and unique. To 9 | draw the letters, I rely on examples of lettering in the urban space. Each 10 | selected example produces its own variants in length, width and height 11 | proportions, each adding to the Montserrat family. The old typographies and 12 | canopies are irretrievable when they are replaced.

13 | 14 |

There are other revivals, but those do not stay close to the originals. The 15 | letters that inspired this project have work, dedication, care, color, 16 | contrast, light and life, day and night! These are the types that make the 17 | city look so beautiful.

18 | 19 |

This is the Regular family, and it has two sister families so far, 20 | Alternates and 21 | Subrayada 22 | families. Many of the letterforms are special in the Alternates family, 23 | while .

24 | 25 |

Updated in September 2012.

26 | 27 |

Updated in June 2014, with Thin, Light and Black weights.

28 | -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/METADATA.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Montserrat", 3 | "designer": "Julieta Ulanovsky", 4 | "license": "OFL", 5 | "visibility": "External", 6 | "category": "Sans Serif", 7 | "size": 14615, 8 | "fonts": [ 9 | { 10 | "name": "Montserrat", 11 | "style": "normal", 12 | "weight": 900, 13 | "filename": "Montserrat-Black.ttf", 14 | "postScriptName": "Montserrat-Black", 15 | "fullName": "Montserrat Black", 16 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 17 | }, 18 | { 19 | "name": "Montserrat", 20 | "style": "normal", 21 | "weight": 700, 22 | "filename": "Montserrat-Bold.ttf", 23 | "postScriptName": "Montserrat-Bold", 24 | "fullName": "Montserrat Bold", 25 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 26 | }, 27 | { 28 | "name": "Montserrat", 29 | "style": "normal", 30 | "weight": 300, 31 | "filename": "Montserrat-Light.ttf", 32 | "postScriptName": "Montserrat-Light", 33 | "fullName": "Montserrat Light", 34 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 35 | }, 36 | { 37 | "name": "Montserrat", 38 | "style": "normal", 39 | "weight": 400, 40 | "filename": "Montserrat-Regular.ttf", 41 | "postScriptName": "Montserrat-Regular", 42 | "fullName": "Montserrat", 43 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 44 | }, 45 | { 46 | "name": "Montserrat", 47 | "style": "normal", 48 | "weight": 100, 49 | "filename": "Montserrat-Thin.ttf", 50 | "postScriptName": "Montserrat-Hairline", 51 | "fullName": "Montserrat Hairline", 52 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 53 | } 54 | ], 55 | "subsets": [ 56 | "latin", 57 | "menu" 58 | ], 59 | "dateAdded": "2011-12-13" 60 | } 61 | -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/montserrat/Montserrat-Black.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/montserrat/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/montserrat/Montserrat-Light.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/montserrat/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/fonts/montserrat/Montserrat-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/fonts/montserrat/Montserrat-Thin.ttf -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /examples/flutter/github_search/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. -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | github_search 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 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 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /examples/flutter/github_search/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/api/github_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | 4 | import 'package:equatable/equatable.dart'; 5 | import 'package:http/http.dart' as http; 6 | 7 | class GithubApi { 8 | final String baseUrl; 9 | final Map cache; 10 | final http.Client client; 11 | 12 | GithubApi({ 13 | http.Client? client, 14 | Map? cache, 15 | this.baseUrl = 'https://api.github.com/search/repositories?q=', 16 | }) : client = client ?? http.Client(), 17 | cache = cache ?? {}; 18 | 19 | /// Search Github for repositories using the given term 20 | Future search(String term) async { 21 | final cached = cache[term]; 22 | if (cached != null) { 23 | return cached; 24 | } else { 25 | final result = await _fetchResults(term); 26 | 27 | cache[term] = result; 28 | 29 | return result; 30 | } 31 | } 32 | 33 | Future _fetchResults(String term) async { 34 | final response = await client.get(Uri.parse('$baseUrl$term')); 35 | final results = json.decode(response.body); 36 | final items = (results['items'] as List?) ?? []; 37 | 38 | return SearchResult.fromJson(items.cast>()); 39 | } 40 | } 41 | 42 | class SearchResult extends Equatable { 43 | final List items; 44 | 45 | const SearchResult(this.items); 46 | 47 | factory SearchResult.fromJson(List> json) { 48 | final items = json.map(SearchResultItem.fromJson).toList(growable: false); 49 | return SearchResult(items); 50 | } 51 | 52 | bool get isPopulated => items.isNotEmpty; 53 | 54 | bool get isEmpty => items.isEmpty; 55 | 56 | @override 57 | List get props => [items]; 58 | } 59 | 60 | class SearchResultItem extends Equatable { 61 | final String fullName; 62 | final String url; 63 | final String avatarUrl; 64 | 65 | const SearchResultItem(this.fullName, this.url, this.avatarUrl); 66 | 67 | factory SearchResultItem.fromJson(Map json) { 68 | return SearchResultItem( 69 | json['full_name'] as String, 70 | json['html_url'] as String, 71 | (json['owner'] as Map)['avatar_url'] as String, 72 | ); 73 | } 74 | 75 | @override 76 | List get props => [fullName, url, avatarUrl]; 77 | } 78 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/bloc/search_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart_ext/state_stream.dart'; 4 | 5 | import '../api/github_api.dart'; 6 | import 'search_state.dart'; 7 | 8 | class SearchBloc { 9 | final Sink onTextChanged; 10 | final StateStream state; 11 | 12 | final StreamSubscription _subscription; 13 | 14 | factory SearchBloc(GithubApi api) { 15 | final onTextChanged = PublishSubject(); 16 | 17 | final state = onTextChanged 18 | // If the text has not changed, do not perform a new search 19 | .distinct() 20 | // Wait for the user to stop typing for 250ms before running a search 21 | .debounceTime(const Duration(milliseconds: 250)) 22 | // Call the Github api with the given search term and convert it to a 23 | // State. If another search term is entered, switchMap will ensure 24 | // the previous search is discarded so we don't deliver stale results 25 | // to the View. 26 | .switchMap((String term) => _search(term, api)) 27 | // The initial state to deliver to the screen. 28 | .publishState(const SearchNoTerm()); 29 | 30 | final subscription = state.connect(); 31 | 32 | return SearchBloc._(onTextChanged, state, subscription); 33 | } 34 | 35 | SearchBloc._(this.onTextChanged, this.state, this._subscription); 36 | 37 | void dispose() { 38 | _subscription.cancel(); 39 | onTextChanged.close(); 40 | } 41 | 42 | static Stream _search(String term, GithubApi api) => term.isEmpty 43 | ? Stream.value(const SearchNoTerm()) 44 | : Rx.fromCallable(() => api.search(term)) 45 | .map((result) => 46 | result.isEmpty ? const SearchEmpty() : SearchPopulated(result)) 47 | .startWith(const SearchLoading()) 48 | .onErrorReturn(const SearchError()); 49 | } 50 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/bloc/search_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | import '../api/github_api.dart'; 5 | 6 | // The State represents the data the View requires. The View consumes a Stream 7 | // of States. The view rebuilds every time the Stream emits a new State! 8 | // 9 | // The State Stream will emit new States depending on the situation: The 10 | // initial state, loading states, the list of results, and any errors that 11 | // happen. 12 | // 13 | // The State Stream responds to input from the View by accepting a 14 | // Stream. We call this Stream the onTextChanged "intent". 15 | @immutable 16 | sealed class SearchState extends Equatable { 17 | const SearchState(); 18 | } 19 | 20 | class SearchLoading extends SearchState { 21 | const SearchLoading(); 22 | 23 | @override 24 | List get props => []; 25 | } 26 | 27 | class SearchError extends SearchState { 28 | const SearchError() : super(); 29 | 30 | @override 31 | List get props => []; 32 | } 33 | 34 | class SearchNoTerm extends SearchState { 35 | const SearchNoTerm(); 36 | 37 | @override 38 | List get props => []; 39 | } 40 | 41 | class SearchPopulated extends SearchState { 42 | final SearchResult result; 43 | 44 | const SearchPopulated(this.result); 45 | 46 | @override 47 | List get props => [result]; 48 | } 49 | 50 | class SearchEmpty extends SearchState { 51 | const SearchEmpty(); 52 | 53 | @override 54 | List get props => []; 55 | } 56 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'api/github_api.dart'; 4 | import 'search_screen.dart'; 5 | 6 | void main() => runApp(SearchApp(api: GithubApi())); 7 | 8 | class SearchApp extends StatelessWidget { 9 | final GithubApi api; 10 | 11 | const SearchApp({super.key, required this.api}); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return MaterialApp( 16 | title: 'RxDart Github Search', 17 | theme: ThemeData( 18 | brightness: Brightness.dark, 19 | primarySwatch: Colors.grey, 20 | ), 21 | home: SearchScreen(api: api), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/widget/empty_result_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class EmptyWidget extends StatelessWidget { 4 | const EmptyWidget({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | Icon( 14 | Icons.warning, 15 | color: Colors.yellow[200], 16 | size: 80.0, 17 | ), 18 | Container( 19 | padding: const EdgeInsets.only(top: 16.0), 20 | child: Text( 21 | 'No results', 22 | style: TextStyle(color: Colors.yellow[100]), 23 | ), 24 | ) 25 | ], 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/widget/search_error_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchErrorWidget extends StatelessWidget { 4 | const SearchErrorWidget({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | crossAxisAlignment: CrossAxisAlignment.center, 13 | children: [ 14 | Icon(Icons.error_outline, color: Colors.red[300], size: 80.0), 15 | Container( 16 | padding: const EdgeInsets.only(top: 16.0), 17 | child: Text( 18 | 'Rate limit exceeded', 19 | style: TextStyle( 20 | color: Colors.red[300], 21 | ), 22 | ), 23 | ) 24 | ], 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/widget/search_intro_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchIntro extends StatelessWidget { 4 | const SearchIntro({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | Icon(Icons.info, color: Colors.green[200], size: 80.0), 14 | Container( 15 | padding: const EdgeInsets.only(top: 16.0), 16 | child: Text( 17 | 'Enter a search term to begin', 18 | style: TextStyle( 19 | color: Colors.green[100], 20 | ), 21 | ), 22 | ) 23 | ], 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/flutter/github_search/lib/widget/search_loading_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_spinkit/flutter_spinkit.dart'; 3 | 4 | class LoadingWidget extends StatelessWidget { 5 | const LoadingWidget({super.key}); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Container( 10 | alignment: FractionalOffset.center, 11 | child: SpinKitCircle( 12 | color: Theme.of(context).colorScheme.secondary, 13 | ), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/flutter/github_search/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /examples/flutter/github_search/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void fl_register_plugins(FlPluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /examples/flutter/github_search/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /examples/flutter/github_search/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /examples/flutter/github_search/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /examples/flutter/github_search/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /examples/flutter/github_search/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 = github_search 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.githubSearch 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | com.apple.security.network.client 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/flutter/github_search/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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/flutter/github_search/macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /examples/flutter/github_search/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: github_search 2 | publish_to: 'none' 3 | description: Flutter GitHub Search RxDart Example. 4 | 5 | environment: 6 | sdk: ">=3.0.0 <4.0.0" 7 | flutter: ">=3.10.0 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | rxdart: 13 | path: ../../../packages/rxdart 14 | rxdart_flutter: 15 | path: ../../../packages/rxdart_flutter 16 | http: ^0.13.3 17 | flutter_spinkit: ^5.1.0 18 | rxdart_ext: ^0.3.0 19 | equatable: ^2.0.5 20 | 21 | dev_dependencies: 22 | flutter_lints: ^4.0.0 23 | test: ^1.17.10 24 | mockito: ^5.4.4 25 | build_runner: ^2.4.9 26 | flutter_test: 27 | sdk: flutter 28 | 29 | # For information on the generic Dart part of this file, see the 30 | # following page: https://www.dartlang.org/tools/pub/pubspec 31 | 32 | # The following section is specific to Flutter. 33 | flutter: 34 | 35 | # The following line ensures that the Material Icons font is 36 | # included with your application, so that you can use the icons in 37 | # the Icons class. 38 | uses-material-design: true 39 | 40 | # To add assets to your application, add an assets section here, in 41 | # this "flutter" section, as in: 42 | # assets: 43 | # - images/a_dot_burr.jpeg 44 | # - images/a_dot_ham.jpeg 45 | 46 | # To add custom fonts to your application, add a fonts section here, 47 | # in this "flutter" section. Each entry in this list should have a 48 | # "family" key with the font family name, and a "fonts" key with a 49 | # list giving the asset and other descriptors for the font. For 50 | # example: 51 | fonts: 52 | - family: Montserrat 53 | fonts: 54 | - asset: fonts/montserrat/Montserrat-Bold.ttf 55 | - asset: fonts/montserrat/Montserrat-Regular.ttf 56 | - family: Hind 57 | fonts: 58 | - asset: fonts/hind/Hind-Regular.ttf 59 | -------------------------------------------------------------------------------- /examples/flutter/github_search/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/web/favicon.png -------------------------------------------------------------------------------- /examples/flutter/github_search/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/web/icons/Icon-192.png -------------------------------------------------------------------------------- /examples/flutter/github_search/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/web/icons/Icon-512.png -------------------------------------------------------------------------------- /examples/flutter/github_search/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /examples/flutter/github_search/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /examples/flutter/github_search/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | github_search 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/flutter/github_search/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github_search", 3 | "short_name": "github_search", 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 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void RegisterPlugins(flutter::PluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | return true; 35 | } 36 | 37 | void FlutterWindow::OnDestroy() { 38 | if (flutter_controller_) { 39 | flutter_controller_ = nullptr; 40 | } 41 | 42 | Win32Window::OnDestroy(); 43 | } 44 | 45 | LRESULT 46 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 47 | WPARAM const wparam, 48 | LPARAM const lparam) noexcept { 49 | // Give Flutter, including plugins, an opportunity to handle window messages. 50 | if (flutter_controller_) { 51 | std::optional result = 52 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 53 | lparam); 54 | if (result) { 55 | return *result; 56 | } 57 | } 58 | 59 | switch (message) { 60 | case WM_FONTCHANGE: 61 | flutter_controller_->engine()->ReloadSystemFonts(); 62 | break; 63 | } 64 | 65 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 66 | } 67 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"github_search", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/examples/flutter/github_search/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | std::string utf8_string; 52 | if (target_length == 0 || target_length > utf8_string.max_size()) { 53 | return utf8_string; 54 | } 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /examples/flutter/github_search/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /examples/web/.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | *.mocks.dart 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | -------------------------------------------------------------------------------- /examples/web/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | 3 | analyzer: 4 | language: 5 | strict-casts: true 6 | strict-raw-types: true 7 | strict-inference: true 8 | 9 | linter: 10 | rules: 11 | - always_declare_return_types # https://github.com/dart-lang/lints#migrating-from-packagepedantic 12 | - prefer_single_quotes # https://github.com/dart-lang/lints#migrating-from-packagepedantic 13 | - unawaited_futures # https://github.com/dart-lang/lints#migrating-from-packagepedantic 14 | -------------------------------------------------------------------------------- /examples/web/build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | build_web_compilers:entrypoint: 5 | generate_for: 6 | - web/**.dart 7 | options: 8 | compiler: dartdevc 9 | -------------------------------------------------------------------------------- /examples/web/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart_web_example 2 | publish_to: none 3 | 4 | environment: 5 | sdk: '>=3.0.0 <4.0.0' 6 | 7 | dependencies: 8 | collection: ^1.18.0 9 | rxdart: 10 | path: ../../packages/rxdart 11 | 12 | dev_dependencies: 13 | lints: ^4.0.0 14 | build_runner: ^2.4.9 15 | build_web_compilers: ^4.0.10 16 | -------------------------------------------------------------------------------- /examples/web/web/dragdrop/dragdrop.dart: -------------------------------------------------------------------------------- 1 | import 'dart:html'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | 5 | // Side note: To maintain readability, this example was not formatted using dart_fmt. 6 | 7 | void main() { 8 | final dragTarget = querySelector('#dragTarget')!; 9 | final mouseUp = document.onMouseUp; 10 | final mouseMove = document.onMouseMove; 11 | final mouseDown = document.onMouseDown; 12 | 13 | mouseDown 14 | // Use map() to calculate the left and top properties on mouseDown 15 | .map((event) => Point(event.client.x - dragTarget.offset.left, 16 | event.client.y - dragTarget.offset.top)) 17 | // Use switchMap() to get the mouse position on each mouseMove 18 | .switchMap((startPosition) { 19 | return mouseMove 20 | // Use map() to calculate the left and top properties on each mouseMove 21 | .map((event) => Point( 22 | event.client.x - startPosition.x, event.client.y - startPosition.y)) 23 | // Use takeUntil() to stop calculations when a mouseUp occurs 24 | .takeUntil(mouseUp); 25 | }) 26 | // Use listen() to update the position of the dragTarget 27 | .listen((position) { 28 | dragTarget.style.left = '${position.x}px'; 29 | dragTarget.style.top = '${position.y}px'; 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /examples/web/web/dragdrop/dragdrop.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 |
17 | Drag Me! 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/web/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RxDart Web Examples 6 | 7 | 8 | 9 |

RxDart Web Examples

10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/web/web/konami/konamicode.dart: -------------------------------------------------------------------------------- 1 | import 'dart:html'; 2 | 3 | import 'package:collection/collection.dart'; 4 | import 'package:rxdart/rxdart.dart'; 5 | 6 | // Side note: To maintain readability, this example was not formatted using dart_fmt. 7 | 8 | void main() { 9 | const konamiKeyCodes = [ 10 | KeyCode.UP, 11 | KeyCode.UP, 12 | KeyCode.DOWN, 13 | KeyCode.DOWN, 14 | KeyCode.LEFT, 15 | KeyCode.RIGHT, 16 | KeyCode.LEFT, 17 | KeyCode.RIGHT, 18 | KeyCode.B, 19 | KeyCode.A 20 | ]; 21 | 22 | final result = querySelector('#result')!; 23 | 24 | document.onKeyUp 25 | // Use map() to get the keyCode 26 | .map((event) => event.keyCode) 27 | // Use bufferCount() to remember the last 10 keyCodes 28 | .bufferCount(10, 1) 29 | // Use where() to check for matching values 30 | .where((lastTenKeyCodes) => 31 | const IterableEquality().equals(lastTenKeyCodes, konamiKeyCodes)) 32 | // Use listen() to display the result 33 | .listen((_) => result.innerHtml = 'KONAMI!'); 34 | } 35 | -------------------------------------------------------------------------------- /examples/web/web/search_github/search_github.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RxDart -- Search Github 6 | 7 | 8 | 9 | 10 | 11 |

Search Github

12 | 13 |
    14 | 15 | 16 | -------------------------------------------------------------------------------- /melos.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart 2 | 3 | packages: 4 | - examples/** 5 | - packages/** 6 | 7 | scripts: 8 | analyze-no-private: 9 | run: melos exec --no-private -- dart analyze . 10 | analyze: 11 | run: melos exec -- dart analyze . 12 | format-no-private: 13 | run: melos exec --no-private -- dart format . --set-exit-if-changed 14 | format: 15 | run: melos exec -- dart format . --set-exit-if-changed 16 | pub-get-no-private: 17 | run: melos exec --no-private -- dart pub get 18 | test-rxdart: 19 | run: | 20 | cd \$MELOS_ROOT_PATH/packages/rxdart 21 | dart pub run test test/rxdart_test.dart --chain-stack-traces 22 | dart --disable-service-auth-codes --enable-vm-service=8111 --pause-isolates-on-exit --enable-asserts test/rxdart_test.dart & 23 | nohup dart pub global run coverage:collect_coverage --port=8111 --out=coverage.json --wait-paused --resume-isolates 24 | dart pub global run coverage:format_coverage --lcov --in=coverage.json --out=lcov.info --report-on=lib 25 | generate: 26 | run: melos exec --depends-on=build_runner -- "dart run build_runner build -d" 27 | description: Build all generated files for Dart & Flutter packages in this project. 28 | test-rxdart-flutter: 29 | run: | 30 | cd \$MELOS_ROOT_PATH/packages/rxdart_flutter 31 | flutter test --no-pub 32 | -------------------------------------------------------------------------------- /packages/rxdart/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | build/ 30 | coverage/ -------------------------------------------------------------------------------- /packages/rxdart/LICENSE: -------------------------------------------------------------------------------- 1 | ../../LICENSE -------------------------------------------------------------------------------- /packages/rxdart/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | 3 | analyzer: 4 | language: 5 | strict-casts: true 6 | strict-raw-types: true 7 | strict-inference: true 8 | 9 | linter: 10 | rules: 11 | - public_member_api_docs 12 | - always_declare_return_types # https://github.com/dart-lang/lints#migrating-from-packagepedantic 13 | - prefer_single_quotes # https://github.com/dart-lang/lints#migrating-from-packagepedantic 14 | - unawaited_futures # https://github.com/dart-lang/lints#migrating-from-packagepedantic 15 | -------------------------------------------------------------------------------- /packages/rxdart/lib/rxdart.dart: -------------------------------------------------------------------------------- 1 | library rx; 2 | 3 | export 'src/rx.dart'; 4 | export 'streams.dart'; 5 | export 'subjects.dart'; 6 | export 'transformers.dart'; 7 | export 'utils.dart'; 8 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/streams/defer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// The defer factory waits until a listener subscribes to it, and then it 4 | /// creates a Stream with the given factory function. 5 | /// 6 | /// In some circumstances, waiting until the last minute (that is, until 7 | /// subscription time) to generate the Stream can ensure that listeners 8 | /// receive the freshest data. 9 | /// 10 | /// By default, DeferStreams are single-subscription. However, it's possible 11 | /// to make them reusable. 12 | /// 13 | /// ### Example 14 | /// 15 | /// DeferStream(() => Stream.value(1)).listen(print); //prints 1 16 | class DeferStream extends Stream { 17 | final Stream Function() _factory; 18 | final bool _isReusable; 19 | 20 | @override 21 | bool get isBroadcast => _isReusable; 22 | 23 | /// Constructs a [Stream] lazily, at the moment of subscription, using 24 | /// the [streamFactory] 25 | DeferStream(Stream Function() streamFactory, {bool reusable = false}) 26 | : _isReusable = reusable, 27 | _factory = reusable 28 | ? streamFactory 29 | : (() { 30 | Stream? stream; 31 | return () => stream ??= streamFactory(); 32 | }()); 33 | 34 | @override 35 | StreamSubscription listen(void Function(T event)? onData, 36 | {Function? onError, void Function()? onDone, bool? cancelOnError}) { 37 | Stream stream; 38 | 39 | try { 40 | stream = _factory(); 41 | } catch (e, s) { 42 | return Stream.error(e, s).listen( 43 | onData, 44 | onError: onError, 45 | onDone: onDone, 46 | cancelOnError: cancelOnError, 47 | ); 48 | } 49 | 50 | return stream.listen( 51 | onData, 52 | onError: onError, 53 | onDone: onDone, 54 | cancelOnError: cancelOnError, 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/streams/from_callable.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// Returns a Stream that, when listening to it, calls a function you specify 4 | /// and then emits the value returned from that function. 5 | /// 6 | /// If result from invoking [callable] function: 7 | /// - Is a [Future]: when the future completes, this stream will fire one event, either 8 | /// data or error, and then close with a done-event. 9 | /// - Is a [T]: this stream emits a single data event and then completes with a done event. 10 | /// 11 | /// By default, a [FromCallableStream] is a single-subscription Stream. However, it's possible 12 | /// to make them reusable. 13 | /// This Stream is effectively equivalent to one created by 14 | /// `(() async* { yield await callable() }())` or `(() async* { yield callable(); }())`. 15 | /// 16 | /// [ReactiveX doc](http://reactivex.io/documentation/operators/from.html) 17 | /// 18 | /// ### Example 19 | /// 20 | /// FromCallableStream(() => 'Value').listen(print); // prints Value 21 | /// 22 | /// FromCallableStream(() async { 23 | /// await Future.delayed(const Duration(seconds: 1)); 24 | /// return 'Value'; 25 | /// }).listen(print); // prints Value 26 | class FromCallableStream extends Stream { 27 | Stream? _stream; 28 | 29 | /// A function will be called at subscription time. 30 | final FutureOr Function() callable; 31 | final bool _isReusable; 32 | 33 | /// Construct a Stream that, when listening to it, calls a function you specify 34 | /// and then emits the value returned from that function. 35 | /// [reusable] indicates whether this Stream can be listened to multiple times or not. 36 | FromCallableStream(this.callable, {bool reusable = false}) 37 | : _isReusable = reusable; 38 | 39 | @override 40 | bool get isBroadcast => _isReusable; 41 | 42 | @override 43 | StreamSubscription listen( 44 | void Function(T event)? onData, { 45 | Function? onError, 46 | void Function()? onDone, 47 | bool? cancelOnError, 48 | }) { 49 | if (_isReusable || _stream == null) { 50 | try { 51 | final value = callable(); 52 | 53 | _stream = 54 | value is Future ? Stream.fromFuture(value) : Stream.value(value); 55 | } catch (e, s) { 56 | _stream = Stream.error(e, s); 57 | } 58 | } 59 | 60 | return _stream!.listen( 61 | onData, 62 | onError: onError, 63 | onDone: onDone, 64 | cancelOnError: cancelOnError, 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/streams/never.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// Returns a non-terminating stream sequence, which can be used to denote 4 | /// an infinite duration. 5 | /// 6 | /// The never operator is one with very specific and limited behavior. These 7 | /// are useful for testing purposes, and sometimes also for combining with 8 | /// other Streams or as parameters to operators that expect other 9 | /// Streams as parameters. 10 | /// 11 | /// ### Example 12 | /// 13 | /// NeverStream().listen(print); // Neither prints nor terminates 14 | class NeverStream extends Stream { 15 | // ignore: close_sinks 16 | final _controller = StreamController(); 17 | 18 | /// Constructs a [Stream] which never emits an event and simply remains 19 | /// open until implicitly closed by the developer. 20 | NeverStream(); 21 | 22 | @override 23 | StreamSubscription listen(void Function(T event)? onData, 24 | {Function? onError, void Function()? onDone, bool? cancelOnError}) => 25 | _controller.stream.listen( 26 | onData, 27 | onError: onError, 28 | onDone: onDone, 29 | cancelOnError: cancelOnError, 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/streams/range.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// Returns a Stream that emits a sequence of Integers within a specified 4 | /// range. 5 | /// 6 | /// ### Examples 7 | /// 8 | /// RangeStream(1, 3).listen((i) => print(i)); // Prints 1, 2, 3 9 | /// 10 | /// RangeStream(3, 1).listen((i) => print(i)); // Prints 3, 2, 1 11 | class RangeStream extends Stream { 12 | var _isListened = false; 13 | final Stream _stream; 14 | 15 | /// Constructs a [Stream] which emits all integer values that exist 16 | /// within the range between [startInclusive] and [endInclusive]. 17 | RangeStream(int startInclusive, int endInclusive) 18 | : _stream = _buildStream(startInclusive, endInclusive); 19 | 20 | @override 21 | StreamSubscription listen(void Function(int event)? onData, 22 | {Function? onError, void Function()? onDone, bool? cancelOnError}) { 23 | if (_isListened) { 24 | throw StateError('Stream has already been listened to.'); 25 | } 26 | _isListened = true; 27 | 28 | return _stream.listen(onData, 29 | onError: onError, onDone: onDone, cancelOnError: cancelOnError); 30 | } 31 | 32 | static Stream _buildStream(int startInclusive, int endInclusive) { 33 | final length = (endInclusive - startInclusive).abs() + 1; 34 | 35 | int nextValue(int index) => startInclusive > endInclusive 36 | ? startInclusive - index 37 | : startInclusive + index; 38 | 39 | return Stream.fromIterable(Iterable.generate(length, nextValue)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/streams/replay_stream.dart: -------------------------------------------------------------------------------- 1 | import 'package:rxdart/src/utils/collection_extensions.dart'; 2 | import 'package:rxdart/src/utils/error_and_stacktrace.dart'; 3 | 4 | /// An [Stream] that provides synchronous access to the emitted values 5 | abstract class ReplayStream implements Stream { 6 | /// Synchronously get the values stored in Subject. May be empty. 7 | List get values; 8 | 9 | /// Synchronously get the errors and stack traces stored in Subject. May be empty. 10 | List get errors; 11 | 12 | /// Synchronously get the stack traces of errors stored in Subject. May be empty. 13 | List get stackTraces; 14 | } 15 | 16 | /// Extension method on [ReplayStream] to access the emitted [ErrorAndStackTrace]s. 17 | extension ErrorAndStackTracesReplayStreamExtension on ReplayStream { 18 | /// Returns the emitted [ErrorAndStackTrace]s. 19 | /// May be empty. 20 | List get errorAndStackTraces => 21 | errors.zipWith( 22 | stackTraces, 23 | (e, s) => ErrorAndStackTrace(e, s), 24 | growable: false, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/streams/timer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// Emits the given value after a specified amount of time. 4 | /// 5 | /// ### Example 6 | /// 7 | /// TimerStream('hi', Duration(minutes: 1)) 8 | /// .listen((i) => print(i)); // print 'hi' after 1 minute 9 | class TimerStream extends Stream { 10 | final StreamController _controller; 11 | 12 | /// Constructs a [Stream] which emits [value] after the specified [Duration]. 13 | TimerStream(T value, Duration duration) 14 | : _controller = _buildController(value, duration); 15 | 16 | @override 17 | StreamSubscription listen(void Function(T event)? onData, 18 | {Function? onError, void Function()? onDone, bool? cancelOnError}) { 19 | return _controller.stream.listen( 20 | onData, 21 | onError: onError, 22 | onDone: onDone, 23 | cancelOnError: cancelOnError, 24 | ); 25 | } 26 | 27 | static StreamController _buildController(T value, Duration duration) { 28 | final watch = Stopwatch(); 29 | Timer? timer; 30 | late StreamController controller; 31 | Duration? totalElapsed = Duration.zero; 32 | 33 | void onResume() { 34 | // Already cancelled or is not paused. 35 | if (totalElapsed == null || timer != null) return; 36 | 37 | totalElapsed = totalElapsed! + watch.elapsed; 38 | watch.start(); 39 | 40 | timer = Timer(duration - totalElapsed!, () { 41 | controller.add(value); 42 | controller.close(); 43 | }); 44 | } 45 | 46 | controller = StreamController( 47 | sync: true, 48 | onListen: () { 49 | watch.start(); 50 | timer = Timer(duration, () { 51 | controller.add(value); 52 | controller.close(); 53 | }); 54 | }, 55 | onPause: () { 56 | timer?.cancel(); 57 | timer = null; 58 | watch.stop(); 59 | }, 60 | onResume: onResume, 61 | onCancel: () { 62 | timer?.cancel(); 63 | timer = null; 64 | totalElapsed = null; 65 | }, 66 | ); 67 | return controller; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/subjects/publish_subject.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/subjects/subject.dart'; 4 | 5 | /// Exactly like a normal broadcast StreamController with one exception: 6 | /// this class is both a Stream and Sink. 7 | /// 8 | /// This Subject allows sending data, error and done events to the listener. 9 | /// 10 | /// PublishSubject is, by default, a broadcast (aka hot) controller, in order 11 | /// to fulfill the Rx Subject contract. This means the Subject's `stream` can 12 | /// be listened to multiple times. 13 | /// 14 | /// ### Example 15 | /// 16 | /// final subject = PublishSubject(); 17 | /// 18 | /// // observer1 will receive all data and done events 19 | /// subject.stream.listen(observer1); 20 | /// subject.add(1); 21 | /// subject.add(2); 22 | /// 23 | /// // observer2 will only receive 3 and done event 24 | /// subject.stream.listen(observer2); 25 | /// subject.add(3); 26 | /// subject.close(); 27 | class PublishSubject extends Subject { 28 | PublishSubject._(StreamController controller, Stream stream) 29 | : super(controller, stream); 30 | 31 | /// Constructs a [PublishSubject], optionally pass handlers for 32 | /// [onListen], [onCancel] and a flag to handle events [sync]. 33 | /// 34 | /// See also [StreamController.broadcast] 35 | factory PublishSubject( 36 | {void Function()? onListen, 37 | void Function()? onCancel, 38 | bool sync = false}) { 39 | // ignore: close_sinks 40 | final controller = StreamController.broadcast( 41 | onListen: onListen, 42 | onCancel: onCancel, 43 | sync: sync, 44 | ); 45 | 46 | return PublishSubject._( 47 | controller, 48 | controller.stream, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/backpressure/pairwise.dart: -------------------------------------------------------------------------------- 1 | import 'package:rxdart/src/streams/never.dart'; 2 | import 'package:rxdart/src/transformers/backpressure/backpressure.dart'; 3 | 4 | /// Emits the n-th and n-1th events as a pair. 5 | /// The first event won't be emitted until the second one arrives. 6 | /// 7 | /// ### Example 8 | /// 9 | /// Rx.range(1, 4) 10 | /// .pairwise() 11 | /// .listen(print); // prints [1, 2], [2, 3], [3, 4] 12 | class PairwiseStreamTransformer 13 | extends BackpressureStreamTransformer> { 14 | /// Constructs a [StreamTransformer] which buffers events into pairs as a [List]. 15 | PairwiseStreamTransformer() 16 | : super(WindowStrategy.firstEventOnly, (_) => NeverStream(), 17 | onWindowEnd: (queue) => queue, 18 | startBufferEvery: 1, 19 | closeWindowWhen: (queue) => queue.length == 2, 20 | dispatchOnClose: false); 21 | } 22 | 23 | /// Extends the Stream class with the ability to emit the nth and n-1th events 24 | /// as a pair 25 | extension PairwiseExtension on Stream { 26 | /// Emits the n-th and n-1th events as a pair. 27 | /// The first event won't be emitted until the second one arrives. 28 | /// 29 | /// ### Example 30 | /// 31 | /// RangeStream(1, 4) 32 | /// .pairwise() 33 | /// .listen(print); // prints [1, 2], [2, 3], [3, 4] 34 | Stream> pairwise() => PairwiseStreamTransformer().bind(this); 35 | } 36 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/backpressure/sample.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/transformers/backpressure/backpressure.dart'; 4 | 5 | /// A [StreamTransformer] that, when the specified window [Stream] emits 6 | /// an item or completes, emits the most recently emitted item (if any) 7 | /// emitted by the source [Stream] since the previous emission from 8 | /// the sample [Stream]. 9 | /// 10 | /// ### Example 11 | /// 12 | /// Stream.fromIterable([1, 2, 3]) 13 | /// .transform(SampleStreamTransformer(TimerStream(1, const Duration(seconds: 1))) 14 | /// .listen(print); // prints 3 15 | class SampleStreamTransformer extends BackpressureStreamTransformer { 16 | /// Constructs a [StreamTransformer] that, when the specified [window] emits 17 | /// an item or completes, emits the most recently emitted item (if any) 18 | /// emitted by the source [Stream] since the previous emission from 19 | /// the sample [Stream]. 20 | SampleStreamTransformer(Stream Function(T event) window) 21 | : super(WindowStrategy.firstEventOnly, window, 22 | onWindowEnd: (queue) => queue.last); 23 | } 24 | 25 | /// Extends the Stream class with the ability to sample events from the Stream 26 | extension SampleExtensions on Stream { 27 | /// Emits the most recently emitted item (if any) 28 | /// emitted by the source [Stream] since the previous emission from 29 | /// the [sampleStream]. 30 | /// 31 | /// ### Example 32 | /// 33 | /// Stream.fromIterable([1, 2, 3]) 34 | /// .sample(TimerStream(1, Duration(seconds: 1))) 35 | /// .listen(print); // prints 3 36 | Stream sample(Stream sampleStream) => 37 | SampleStreamTransformer((_) => sampleStream).bind(this); 38 | 39 | /// Emits the most recently emitted item (if any) emitted by the source 40 | /// [Stream] since the previous emission within the recurring time span, 41 | /// defined by [duration] 42 | /// 43 | /// ### Example 44 | /// 45 | /// Stream.fromIterable([1, 2, 3]) 46 | /// .sampleTime(Duration(seconds: 1)) 47 | /// .listen(print); // prints 3 48 | Stream sampleTime(Duration duration) => 49 | sample(Stream.periodic(duration)); 50 | } 51 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/default_if_empty.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _DefaultIfEmptyStreamSink implements EventSink { 4 | final S _defaultValue; 5 | final EventSink _outputSink; 6 | bool _isEmpty = true; 7 | 8 | _DefaultIfEmptyStreamSink(this._outputSink, this._defaultValue); 9 | 10 | @override 11 | void add(S data) { 12 | _isEmpty = false; 13 | _outputSink.add(data); 14 | } 15 | 16 | @override 17 | void addError(e, [st]) => _outputSink.addError(e, st); 18 | 19 | @override 20 | void close() { 21 | if (_isEmpty) { 22 | _outputSink.add(_defaultValue); 23 | } 24 | 25 | _outputSink.close(); 26 | } 27 | } 28 | 29 | /// Emit items from the source [Stream], or a single default item if the source 30 | /// Stream emits nothing. 31 | /// 32 | /// ### Example 33 | /// 34 | /// Stream.empty() 35 | /// .transform(DefaultIfEmptyStreamTransformer(10)) 36 | /// .listen(print); // prints 10 37 | class DefaultIfEmptyStreamTransformer extends StreamTransformerBase { 38 | /// The event that should be emitted if the source [Stream] is empty 39 | final S defaultValue; 40 | 41 | /// Constructs a [StreamTransformer] which either emits from the source [Stream], 42 | /// or just a [defaultValue] if the source [Stream] emits nothing. 43 | DefaultIfEmptyStreamTransformer(this.defaultValue); 44 | 45 | @override 46 | Stream bind(Stream stream) => Stream.eventTransformed( 47 | stream, (sink) => _DefaultIfEmptyStreamSink(sink, defaultValue)); 48 | } 49 | 50 | /// Extend the Stream class with the ability to emit a single default item if the 51 | /// source Stream emits nothing. 52 | extension DefaultIfEmptyExtension on Stream { 53 | /// Emit items from the source Stream, or a single default item if the source 54 | /// Stream emits nothing. 55 | /// 56 | /// ### Example 57 | /// 58 | /// Stream.empty().defaultIfEmpty(10).listen(print); // prints 10 59 | Stream defaultIfEmpty(T defaultValue) => 60 | DefaultIfEmptyStreamTransformer(defaultValue).bind(this); 61 | } 62 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/end_with.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _EndWithStreamSink implements EventSink { 4 | final S _endValue; 5 | final EventSink _outputSink; 6 | 7 | _EndWithStreamSink(this._outputSink, this._endValue); 8 | 9 | @override 10 | void add(S data) => _outputSink.add(data); 11 | 12 | @override 13 | void addError(e, [st]) => _outputSink.addError(e, st); 14 | 15 | @override 16 | void close() { 17 | _outputSink.add(_endValue); 18 | _outputSink.close(); 19 | } 20 | } 21 | 22 | /// Appends a value to the source [Stream] before closing. 23 | /// 24 | /// ### Example 25 | /// 26 | /// Stream.fromIterable([2]) 27 | /// .transform(EndWithStreamTransformer(1)) 28 | /// .listen(print); // prints 2, 1 29 | class EndWithStreamTransformer extends StreamTransformerBase { 30 | /// The ending event of this [Stream] 31 | final S endValue; 32 | 33 | /// Constructs a [StreamTransformer] which appends the source [Stream] 34 | /// with [endValue] just before it closes. 35 | EndWithStreamTransformer(this.endValue); 36 | 37 | @override 38 | Stream bind(Stream stream) => Stream.eventTransformed( 39 | stream, (sink) => _EndWithStreamSink(sink, endValue)); 40 | } 41 | 42 | /// Extends the [Stream] class with the ability to emit the given value as the 43 | /// final item before closing. 44 | extension EndWithExtension on Stream { 45 | /// Appends a value to the source [Stream] before closing. 46 | /// 47 | /// ### Example 48 | /// 49 | /// Stream.fromIterable([2]).endWith(1).listen(print); // prints 2, 1 50 | Stream endWith(T endValue) => 51 | EndWithStreamTransformer(endValue).bind(this); 52 | } 53 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/end_with_many.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _EndWithManyStreamSink implements EventSink { 4 | final Iterable _endValues; 5 | final EventSink _outputSink; 6 | 7 | _EndWithManyStreamSink(this._outputSink, this._endValues); 8 | 9 | @override 10 | void add(S data) => _outputSink.add(data); 11 | 12 | @override 13 | void addError(e, [st]) => _outputSink.addError(e, st); 14 | 15 | @override 16 | void close() { 17 | _endValues.forEach(_outputSink.add); 18 | _outputSink.close(); 19 | } 20 | } 21 | 22 | /// Appends a sequence of values to the source [Stream]. 23 | /// 24 | /// ### Example 25 | /// 26 | /// Stream.fromIterable([3]) 27 | /// .transform(EndWithManyStreamTransformer([1, 2])) 28 | /// .listen(print); // prints 3, 1, 2 29 | class EndWithManyStreamTransformer extends StreamTransformerBase { 30 | /// The ending events of this [Stream] 31 | final Iterable endValues; 32 | 33 | /// Constructs a [StreamTransformer] which appends the source [Stream] 34 | /// with [endValues] before closing. 35 | EndWithManyStreamTransformer(this.endValues); 36 | 37 | @override 38 | Stream bind(Stream stream) => Stream.eventTransformed( 39 | stream, (sink) => _EndWithManyStreamSink(sink, endValues)); 40 | } 41 | 42 | /// Extends the Stream class with the ability to emit the given value as the 43 | /// final item before closing. 44 | extension EndWithManyExtension on Stream { 45 | /// Appends a sequence of values as final events to the source [Stream] before closing. 46 | /// 47 | /// ### Example 48 | /// 49 | /// Stream.fromIterable([2]).endWithMany([1, 0]).listen(print); // prints 2, 1, 0 50 | Stream endWithMany(Iterable endValues) => 51 | EndWithManyStreamTransformer(endValues).bind(this); 52 | } 53 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/ignore_elements.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _IgnoreElementsStreamSink implements EventSink { 4 | final EventSink _outputSink; 5 | 6 | _IgnoreElementsStreamSink(this._outputSink); 7 | 8 | @override 9 | void add(S data) {} 10 | 11 | @override 12 | void addError(e, [st]) => _outputSink.addError(e, st); 13 | 14 | @override 15 | void close() => _outputSink.close(); 16 | } 17 | 18 | /// Creates a [Stream] where all emitted items are ignored, only the 19 | /// error / completed notifications are passed 20 | /// 21 | /// [ReactiveX doc](http://reactivex.io/documentation/operators/ignoreelements.html) 22 | /// [Interactive marble diagram](https://rxmarbles.com/#ignoreElements) 23 | /// 24 | /// ### Example 25 | /// 26 | /// MergeStream([ 27 | /// Stream.fromIterable([1]), 28 | /// ErrorStream(Exception()) 29 | /// ]) 30 | /// .transform(IgnoreElementsStreamTransformer()) 31 | /// .listen(print, onError: print); // prints Exception 32 | class IgnoreElementsStreamTransformer 33 | extends StreamTransformerBase { 34 | /// Constructs a [StreamTransformer] which simply ignores all events from 35 | /// the source [Stream], except for error or completed events. 36 | IgnoreElementsStreamTransformer(); 37 | 38 | @override 39 | Stream bind(Stream stream) => Stream.eventTransformed( 40 | stream, (sink) => _IgnoreElementsStreamSink(sink)); 41 | } 42 | 43 | /// Extends the Stream class with the ability to skip, or ignore, data events. 44 | extension IgnoreElementsExtension on Stream { 45 | /// Creates a Stream where all emitted items are ignored, only the error / 46 | /// completed notifications are passed 47 | /// 48 | /// [ReactiveX doc](http://reactivex.io/documentation/operators/ignoreelements.html) 49 | /// [Interactive marble diagram](https://rxmarbles.com/#ignoreElements) 50 | /// 51 | /// ### Example 52 | /// 53 | /// MergeStream([ 54 | /// Stream.fromIterable([1]), 55 | /// Stream.error(Exception()) 56 | /// ]) 57 | /// .ignoreElements() 58 | /// .listen(print, onError: print); // prints Exception 59 | Stream ignoreElements() => 60 | IgnoreElementsStreamTransformer().bind(this); 61 | } 62 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/map_to.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _MapToStreamSink implements EventSink { 4 | final T _value; 5 | final EventSink _outputSink; 6 | 7 | _MapToStreamSink(this._outputSink, this._value); 8 | 9 | @override 10 | void add(S data) => _outputSink.add(_value); 11 | 12 | @override 13 | void addError(e, [st]) => _outputSink.addError(e, st); 14 | 15 | @override 16 | void close() => _outputSink.close(); 17 | } 18 | 19 | /// Emits the given constant value on the output Stream every time the source 20 | /// Stream emits a value. 21 | /// 22 | /// ### Example 23 | /// 24 | /// Stream.fromIterable([1, 2, 3, 4]) 25 | /// .mapTo(true) 26 | /// .listen(print); // prints true, true, true, true 27 | class MapToStreamTransformer extends StreamTransformerBase { 28 | /// A constant [value] which will always be returned when using this transformer. 29 | final T value; 30 | 31 | /// Constructs a [StreamTransformer] which always maps every event from 32 | /// the source [Stream] to a constant [value]. 33 | MapToStreamTransformer(this.value); 34 | 35 | @override 36 | Stream bind(Stream stream) => Stream.eventTransformed( 37 | stream, (sink) => _MapToStreamSink(sink, value)); 38 | } 39 | 40 | /// Extends the Stream class with the ability to convert each item to the same 41 | /// value. 42 | extension MapToExtension on Stream { 43 | /// Emits the given constant value on the output Stream every time the source 44 | /// Stream emits a value. 45 | /// 46 | /// ### Example 47 | /// 48 | /// Stream.fromIterable([1, 2, 3, 4]) 49 | /// .mapTo(true) 50 | /// .listen(print); // prints true, true, true, true 51 | Stream mapTo(T value) => MapToStreamTransformer(value).bind(this); 52 | } 53 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/max.dart: -------------------------------------------------------------------------------- 1 | import 'package:rxdart/src/utils/min_max.dart'; 2 | 3 | /// Extends the Stream class with the ability to transform into a Future 4 | /// that completes with the largest item emitted by the Stream. 5 | extension MaxExtension on Stream { 6 | /// Converts a Stream into a Future that completes with the largest item 7 | /// emitted by the Stream. 8 | /// 9 | /// This is similar to finding the max value in a list, but the values are 10 | /// asynchronous. 11 | /// 12 | /// ### Example 13 | /// 14 | /// final max = await Stream.fromIterable([1, 2, 3]).max(); 15 | /// 16 | /// print(max); // prints 3 17 | /// 18 | /// ### Example with custom [Comparator] 19 | /// 20 | /// final stream = Stream.fromIterable(['short', 'looooooong']); 21 | /// final max = await stream.max((a, b) => a.length - b.length); 22 | /// 23 | /// print(max); // prints 'looooooong' 24 | Future max([Comparator? comparator]) => minMax(this, false, comparator); 25 | } 26 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/min.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/utils/min_max.dart'; 4 | 5 | /// Extends the Stream class with the ability to transform into a Future 6 | /// that completes with the smallest item emitted by the Stream. 7 | extension MinExtension on Stream { 8 | /// Converts a Stream into a Future that completes with the smallest item 9 | /// emitted by the Stream. 10 | /// 11 | /// This is similar to finding the min value in a list, but the values are 12 | /// asynchronous! 13 | /// 14 | /// ### Example 15 | /// 16 | /// final min = await Stream.fromIterable([1, 2, 3]).min(); 17 | /// 18 | /// print(min); // prints 1 19 | /// 20 | /// ### Example with custom [Comparator] 21 | /// 22 | /// final stream = Stream.fromIterable(['short', 'looooooong']); 23 | /// final min = await stream.min((a, b) => a.length - b.length); 24 | /// 25 | /// print(min); // prints 'short' 26 | Future min([Comparator? comparator]) => minMax(this, true, comparator); 27 | } 28 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/scan.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _ScanStreamSink implements EventSink { 4 | final T Function(T accumulated, S value, int index) _accumulator; 5 | final EventSink _outputSink; 6 | T _acc; 7 | var _index = 0; 8 | 9 | _ScanStreamSink(this._outputSink, this._accumulator, this._acc); 10 | 11 | @override 12 | void add(S data) => 13 | _outputSink.add(_acc = _accumulator(_acc, data, _index++)); 14 | 15 | @override 16 | void addError(e, [st]) => _outputSink.addError(e, st); 17 | 18 | @override 19 | void close() => _outputSink.close(); 20 | } 21 | 22 | /// Applies an accumulator function over an stream sequence and returns 23 | /// each intermediate result. The seed value is used as the initial 24 | /// accumulator value. 25 | /// 26 | /// ### Example 27 | /// 28 | /// Stream.fromIterable([1, 2, 3]) 29 | /// .transform(ScanStreamTransformer((acc, curr, i) => acc + curr, 0)) 30 | /// .listen(print); // prints 1, 3, 6 31 | class ScanStreamTransformer extends StreamTransformerBase { 32 | /// Method which accumulates incoming event into a single, accumulated object 33 | final T Function(T accumulated, S value, int index) accumulator; 34 | 35 | /// The initial value for the accumulated value in the [accumulator] 36 | final T seed; 37 | 38 | /// Constructs a [ScanStreamTransformer] which applies an accumulator Function 39 | /// over the source [Stream] and returns each intermediate result. 40 | /// The seed value is used as the initial accumulator value. 41 | ScanStreamTransformer(this.accumulator, this.seed); 42 | 43 | @override 44 | Stream bind(Stream stream) => Stream.eventTransformed( 45 | stream, (sink) => _ScanStreamSink(sink, accumulator, seed)); 46 | } 47 | 48 | /// Extends 49 | extension ScanExtension on Stream { 50 | /// Applies an accumulator function over a Stream sequence and returns each 51 | /// intermediate result. The seed value is used as the initial 52 | /// accumulator value. 53 | /// 54 | /// ### Example 55 | /// 56 | /// Stream.fromIterable([1, 2, 3]) 57 | /// .scan((acc, curr, i) => acc + curr, 0) 58 | /// .listen(print); // prints 1, 3, 6 59 | Stream scan( 60 | S Function(S accumulated, T value, int index) accumulator, S seed) => 61 | ScanStreamTransformer(accumulator, seed).bind(this); 62 | } 63 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/skip_last.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/utils/forwarding_sink.dart'; 4 | import 'package:rxdart/src/utils/forwarding_stream.dart'; 5 | 6 | class _SkipLastStreamSink extends ForwardingSink { 7 | _SkipLastStreamSink(this.count); 8 | 9 | final int count; 10 | final List queue = []; 11 | 12 | @override 13 | void onData(T data) { 14 | queue.add(data); 15 | } 16 | 17 | @override 18 | void onError(Object e, StackTrace st) => sink.addError(e, st); 19 | 20 | @override 21 | void onDone() { 22 | final limit = queue.length - count; 23 | if (limit > 0) { 24 | queue.sublist(0, limit).forEach(sink.add); 25 | } 26 | sink.close(); 27 | } 28 | 29 | @override 30 | FutureOr onCancel() { 31 | queue.clear(); 32 | } 33 | 34 | @override 35 | void onListen() {} 36 | 37 | @override 38 | void onPause() {} 39 | 40 | @override 41 | void onResume() {} 42 | } 43 | 44 | /// Skip the last [count] items emitted by the source [Stream] 45 | /// 46 | /// ### Example 47 | /// 48 | /// Stream.fromIterable([1, 2, 3, 4, 5]) 49 | /// .transform(SkipLastStreamTransformer(3)) 50 | /// .listen(print); // prints 1, 2 51 | class SkipLastStreamTransformer extends StreamTransformerBase { 52 | /// Constructs a [StreamTransformer] which skip the last [count] items 53 | /// emitted by the source [Stream] 54 | SkipLastStreamTransformer(this.count) { 55 | if (count < 0) throw ArgumentError.value(count, 'count'); 56 | } 57 | 58 | /// The [count] of final items to skip. 59 | final int count; 60 | 61 | @override 62 | Stream bind(Stream stream) => 63 | forwardStream(stream, () => _SkipLastStreamSink(count)); 64 | } 65 | 66 | /// Extends the Stream class with the ability to skip the last [count] items 67 | /// emitted by the source [Stream] 68 | extension SkipLastExtension on Stream { 69 | /// Starts emitting every items except last [count] items. 70 | /// This causes items to be delayed. 71 | /// 72 | /// ### Example 73 | /// 74 | /// Stream.fromIterable([1, 2, 3, 4, 5]) 75 | /// .skipLast(3) 76 | /// .listen(print); // prints 1, 2 77 | Stream skipLast(int count) => 78 | SkipLastStreamTransformer(count).bind(this); 79 | } 80 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/start_with.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/utils/forwarding_sink.dart'; 4 | import 'package:rxdart/src/utils/forwarding_stream.dart'; 5 | 6 | class _StartWithStreamSink extends ForwardingSink { 7 | final S _startValue; 8 | 9 | _StartWithStreamSink(this._startValue); 10 | 11 | @override 12 | void onData(S data) => sink.add(data); 13 | 14 | @override 15 | void onError(Object e, StackTrace st) => sink.addError(e, st); 16 | 17 | @override 18 | void onDone() => sink.close(); 19 | 20 | @override 21 | FutureOr onCancel() {} 22 | 23 | @override 24 | void onListen() { 25 | sink.add(_startValue); 26 | } 27 | 28 | @override 29 | void onPause() {} 30 | 31 | @override 32 | void onResume() {} 33 | } 34 | 35 | /// Prepends a value to the source [Stream]. 36 | /// 37 | /// ### Example 38 | /// 39 | /// Stream.fromIterable([2]) 40 | /// .transform(StartWithStreamTransformer(1)) 41 | /// .listen(print); // prints 1, 2 42 | class StartWithStreamTransformer extends StreamTransformerBase { 43 | /// The starting event of this [Stream] 44 | final S startValue; 45 | 46 | /// Constructs a [StreamTransformer] which prepends the source [Stream] 47 | /// with [startValue]. 48 | StartWithStreamTransformer(this.startValue); 49 | 50 | @override 51 | Stream bind(Stream stream) => 52 | forwardStream(stream, () => _StartWithStreamSink(startValue)); 53 | } 54 | 55 | /// Extends the [Stream] class with the ability to emit the given value as the 56 | /// first item. 57 | extension StartWithExtension on Stream { 58 | /// Prepends a value to the source [Stream]. 59 | /// 60 | /// ### Example 61 | /// 62 | /// Stream.fromIterable([2]).startWith(1).listen(print); // prints 1, 2 63 | Stream startWith(T startValue) => 64 | StartWithStreamTransformer(startValue).bind(this); 65 | } 66 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/start_with_error.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/utils/forwarding_sink.dart'; 4 | import 'package:rxdart/src/utils/forwarding_stream.dart'; 5 | 6 | class _StartWithErrorStreamSink extends ForwardingSink { 7 | final Object _e; 8 | final StackTrace? _st; 9 | 10 | _StartWithErrorStreamSink(this._e, this._st); 11 | 12 | @override 13 | void onData(S data) => sink.add(data); 14 | 15 | @override 16 | void onError(Object e, StackTrace st) => sink.addError(e, st); 17 | 18 | @override 19 | void onDone() => sink.close(); 20 | 21 | @override 22 | FutureOr onCancel() {} 23 | 24 | @override 25 | void onListen() { 26 | sink.addError(_e, _st); 27 | } 28 | 29 | @override 30 | void onPause() {} 31 | 32 | @override 33 | void onResume() {} 34 | } 35 | 36 | /// Prepends an error to the source [Stream]. 37 | /// 38 | /// ### Example 39 | /// 40 | /// Stream.fromIterable([2]) 41 | /// .transform(StartWithErrorStreamTransformer('error')) 42 | /// .listen(null, onError: (e) => print(e)); // prints 'error' 43 | class StartWithErrorStreamTransformer extends StreamTransformerBase { 44 | /// The starting error of this [Stream] 45 | final Object error; 46 | 47 | /// The starting stackTrace of this [Stream] 48 | final StackTrace? stackTrace; 49 | 50 | /// Constructs a [StreamTransformer] which starts with the provided [error] 51 | /// and then outputs all events from the source [Stream]. 52 | StartWithErrorStreamTransformer(this.error, [this.stackTrace]); 53 | 54 | @override 55 | Stream bind(Stream stream) => 56 | forwardStream(stream, () => _StartWithErrorStreamSink(error, stackTrace)); 57 | } 58 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/start_with_many.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/utils/forwarding_sink.dart'; 4 | import 'package:rxdart/src/utils/forwarding_stream.dart'; 5 | 6 | class _StartWithManyStreamSink extends ForwardingSink { 7 | final Iterable _startValues; 8 | 9 | _StartWithManyStreamSink(this._startValues); 10 | 11 | @override 12 | void onData(S data) => sink.add(data); 13 | 14 | @override 15 | void onError(Object e, StackTrace st) => sink.addError(e, st); 16 | 17 | @override 18 | void onDone() => sink.close(); 19 | 20 | @override 21 | FutureOr onCancel() {} 22 | 23 | @override 24 | void onListen() { 25 | _startValues.forEach(sink.add); 26 | } 27 | 28 | @override 29 | void onPause() {} 30 | 31 | @override 32 | void onResume() {} 33 | } 34 | 35 | /// Prepends a sequence of values to the source [Stream]. 36 | /// 37 | /// ### Example 38 | /// 39 | /// Stream.fromIterable([3]) 40 | /// .transform(StartWithManyStreamTransformer([1, 2])) 41 | /// .listen(print); // prints 1, 2, 3 42 | class StartWithManyStreamTransformer extends StreamTransformerBase { 43 | /// The starting events of this [Stream] 44 | final Iterable startValues; 45 | 46 | /// Constructs a [StreamTransformer] which prepends the source [Stream] 47 | /// with [startValues]. 48 | StartWithManyStreamTransformer(this.startValues); 49 | 50 | @override 51 | Stream bind(Stream stream) => 52 | forwardStream(stream, () => _StartWithManyStreamSink(startValues)); 53 | } 54 | 55 | /// Extends the [Stream] class with the ability to emit the given values as the 56 | /// first items. 57 | extension StartWithManyExtension on Stream { 58 | /// Prepends a sequence of values to the source [Stream]. 59 | /// 60 | /// ### Example 61 | /// 62 | /// Stream.fromIterable([3]).startWithMany([1, 2]) 63 | /// .listen(print); // prints 1, 2, 3 64 | Stream startWithMany(List startValues) => 65 | StartWithManyStreamTransformer(startValues).bind(this); 66 | } 67 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/take_last.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:collection'; 3 | 4 | import 'package:rxdart/src/utils/forwarding_sink.dart'; 5 | import 'package:rxdart/src/utils/forwarding_stream.dart'; 6 | 7 | class _TakeLastStreamSink extends ForwardingSink { 8 | _TakeLastStreamSink(this.count); 9 | 10 | final int count; 11 | final Queue queue = DoubleLinkedQueue(); 12 | 13 | @override 14 | void onData(T data) { 15 | if (count > 0) { 16 | queue.addLast(data); 17 | if (queue.length > count) { 18 | queue.removeFirst(); 19 | } 20 | } 21 | } 22 | 23 | @override 24 | void onError(Object e, StackTrace st) => sink.addError(e, st); 25 | 26 | @override 27 | void onDone() { 28 | if (queue.isNotEmpty) { 29 | queue.toList(growable: false).forEach(sink.add); 30 | } 31 | sink.close(); 32 | } 33 | 34 | @override 35 | FutureOr onCancel() { 36 | queue.clear(); 37 | } 38 | 39 | @override 40 | void onListen() {} 41 | 42 | @override 43 | void onPause() {} 44 | 45 | @override 46 | void onResume() {} 47 | } 48 | 49 | /// Emits only the final [count] values emitted by the source [Stream]. 50 | /// 51 | /// ### Example 52 | /// 53 | /// Stream.fromIterable([1, 2, 3, 4, 5]) 54 | /// .transform(TakeLastStreamTransformer(3)) 55 | /// .listen(print); // prints 3, 4, 5 56 | class TakeLastStreamTransformer extends StreamTransformerBase { 57 | /// Constructs a [StreamTransformer] which emits only the final [count] 58 | /// events from the source [Stream]. 59 | TakeLastStreamTransformer(this.count) { 60 | if (count < 0) throw ArgumentError.value(count, 'count'); 61 | } 62 | 63 | /// The [count] of final items emitted when the stream completes. 64 | final int count; 65 | 66 | @override 67 | Stream bind(Stream stream) => 68 | forwardStream(stream, () => _TakeLastStreamSink(count)); 69 | } 70 | 71 | /// Extends the [Stream] class with the ability receive only the final [count] 72 | /// events from the source [Stream]. 73 | extension TakeLastExtension on Stream { 74 | /// Emits only the final [count] values emitted by the source [Stream]. 75 | /// 76 | /// ### Example 77 | /// 78 | /// Stream.fromIterable([1, 2, 3, 4, 5]) 79 | /// .takeLast(3) 80 | /// .listen(print); // prints 3, 4, 5 81 | Stream takeLast(int count) => 82 | TakeLastStreamTransformer(count).bind(this); 83 | } 84 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/where_not_null.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _WhereNotNullStreamSink implements EventSink { 4 | final EventSink _outputSink; 5 | 6 | _WhereNotNullStreamSink(this._outputSink); 7 | 8 | @override 9 | void add(T? event) { 10 | if (event != null) { 11 | _outputSink.add(event); 12 | } 13 | } 14 | 15 | @override 16 | void addError(Object error, [StackTrace? stackTrace]) => 17 | _outputSink.addError(error, stackTrace); 18 | 19 | @override 20 | void close() => _outputSink.close(); 21 | } 22 | 23 | /// Create a Stream which emits all the non-`null` elements of the Stream, 24 | /// in their original emission order. 25 | /// 26 | /// ### Example 27 | /// 28 | /// Stream.fromIterable([1, 2, 3, null, 4, null]) 29 | /// .transform(WhereNotNullStreamTransformer()) 30 | /// .listen(print); // prints 1, 2, 3, 4 31 | /// 32 | /// // equivalent to: 33 | /// 34 | /// Stream.fromIterable([1, 2, 3, null, 4, null]) 35 | /// .transform(WhereTypeStreamTransformer()) 36 | /// .listen(print); // prints 1, 2, 3, 4 37 | class WhereNotNullStreamTransformer 38 | extends StreamTransformerBase { 39 | @override 40 | Stream bind(Stream stream) => Stream.eventTransformed( 41 | stream, (sink) => _WhereNotNullStreamSink(sink)); 42 | } 43 | 44 | /// Extends the Stream class with the ability to convert the source Stream 45 | /// to a Stream which emits all the non-`null` elements 46 | /// of this Stream, in their original emission order. 47 | extension WhereNotNullExtension on Stream { 48 | /// Returns a Stream which emits all the non-`null` elements 49 | /// of this Stream, in their original emission order. 50 | /// 51 | /// For a `Stream`, this method is equivalent to `.whereType()`. 52 | /// 53 | /// ### Example 54 | /// 55 | /// Stream.fromIterable([1, 2, 3, null, 4, null]) 56 | /// .whereNotNull() 57 | /// .listen(print); // prints 1, 2, 3, 4 58 | /// 59 | /// // equivalent to: 60 | /// 61 | /// Stream.fromIterable([1, 2, 3, null, 4, null]) 62 | /// .whereType() 63 | /// .listen(print); // prints 1, 2, 3, 4 64 | Stream whereNotNull() => WhereNotNullStreamTransformer().bind(this); 65 | } 66 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/transformers/where_type.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | class _WhereTypeStreamSink implements EventSink { 4 | final EventSink _outputSink; 5 | 6 | _WhereTypeStreamSink(this._outputSink); 7 | 8 | @override 9 | void add(S data) { 10 | if (data is T) { 11 | _outputSink.add(data); 12 | } 13 | } 14 | 15 | @override 16 | void addError(e, [st]) => _outputSink.addError(e, st); 17 | 18 | @override 19 | void close() => _outputSink.close(); 20 | } 21 | 22 | /// This transformer is a shorthand for [Stream.where] followed by [Stream.cast]. 23 | /// 24 | /// Events that do not match [T] are filtered out, the resulting 25 | /// [Stream] will be of Type [T]. 26 | /// 27 | /// ### Example 28 | /// 29 | /// Stream.fromIterable([1, 'two', 3, 'four']) 30 | /// .whereType() 31 | /// .listen(print); // prints 1, 3 32 | /// 33 | /// // as opposed to: 34 | /// 35 | /// Stream.fromIterable([1, 'two', 3, 'four']) 36 | /// .where((event) => event is int) 37 | /// .cast() 38 | /// .listen(print); // prints 1, 3 39 | /// 40 | class WhereTypeStreamTransformer extends StreamTransformerBase { 41 | /// Constructs a [StreamTransformer] which combines [Stream.where] followed by [Stream.cast]. 42 | WhereTypeStreamTransformer(); 43 | 44 | @override 45 | Stream bind(Stream stream) => Stream.eventTransformed( 46 | stream, (sink) => _WhereTypeStreamSink(sink)); 47 | } 48 | 49 | /// Extends the Stream class with the ability to filter down events to only 50 | /// those of a specific type. 51 | extension WhereTypeExtension on Stream { 52 | /// This transformer is a shorthand for [Stream.where] followed by 53 | /// [Stream.cast]. 54 | /// 55 | /// Events that do not match [T] are filtered out, the resulting [Stream] will 56 | /// be of Type [T]. 57 | /// 58 | /// ### Example 59 | /// 60 | /// Stream.fromIterable([1, 'two', 3, 'four']) 61 | /// .whereType() 62 | /// .listen(print); // prints 1, 3 63 | /// 64 | /// #### as opposed to: 65 | /// 66 | /// Stream.fromIterable([1, 'two', 3, 'four']) 67 | /// .where((event) => event is int) 68 | /// .cast() 69 | /// .listen(print); // prints 1, 3 70 | Stream whereType() => WhereTypeStreamTransformer().bind(this); 71 | } 72 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/utils/collection_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:math'; 3 | 4 | /// @internal 5 | /// @nodoc 6 | /// Provides extension methods on [List]. 7 | extension ListExtensions on List { 8 | /// @internal 9 | /// Returns a list of values built from the elements of this list 10 | /// and the other list with the same index 11 | /// using the provided transform function applied to each pair of elements. 12 | /// The returned list has length of the shortest list. 13 | List zipWith( 14 | List other, 15 | R Function(T, S) transform, { 16 | bool growable = true, 17 | }) => 18 | List.generate( 19 | min(length, other.length), 20 | (index) => transform(this[index], other[index]), 21 | growable: growable, 22 | ); 23 | } 24 | 25 | /// @internal 26 | /// Provides extension methods on [Iterable]. 27 | extension IterableExtensions on Iterable { 28 | /// @internal 29 | /// The non-`null` results of calling [transform] on the elements of [this]. 30 | /// 31 | /// Returns a lazy iterable which calls [transform] 32 | /// on the elements of this iterable in iteration order, 33 | /// then emits only the non-`null` values. 34 | /// 35 | /// If [transform] throws, the iteration is terminated. 36 | Iterable mapNotNull(R? Function(T) transform) sync* { 37 | for (final e in this) { 38 | final v = transform(e); 39 | if (v != null) { 40 | yield v; 41 | } 42 | } 43 | } 44 | 45 | /// @internal 46 | /// Maps each element and its index to a new value. 47 | Iterable mapIndexed(R Function(int index, T element) transform) sync* { 48 | var index = 0; 49 | for (final e in this) { 50 | yield transform(index++, e); 51 | } 52 | } 53 | } 54 | 55 | /// @internal 56 | /// Provides [removeFirstElements] extension method on [Queue]. 57 | extension RemoveFirstElementsQueueExtension on Queue { 58 | /// @internal 59 | /// Removes the first [count] elements of this queue. 60 | void removeFirstElements(int count) { 61 | for (var i = 0; i < count; i++) { 62 | removeFirst(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/utils/empty.dart: -------------------------------------------------------------------------------- 1 | class _Empty { 2 | const _Empty(); 3 | 4 | @override 5 | String toString() => '<>'; 6 | } 7 | 8 | /// @internal 9 | /// Sentinel object used to represent a missing value (distinct from `null`). 10 | const Object? EMPTY = _Empty(); // ignore: constant_identifier_names 11 | 12 | /// @internal 13 | /// Returns `null` if [o] is [EMPTY], otherwise returns itself. 14 | T? unbox(Object? o) => identical(o, EMPTY) ? null : o as T; 15 | 16 | /// @internal 17 | /// Returns `true` if [o] is not [EMPTY]. 18 | bool isNotEmpty(Object? o) => !identical(o, EMPTY); 19 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/utils/error_and_stacktrace.dart: -------------------------------------------------------------------------------- 1 | /// An Object which acts as a tuple containing both an error and the 2 | /// corresponding stack trace. 3 | class ErrorAndStackTrace { 4 | /// A reference to the wrapped error object. 5 | final Object error; 6 | 7 | /// A reference to the wrapped [StackTrace] 8 | final StackTrace? stackTrace; 9 | 10 | /// Constructs an object containing both an [error] and the 11 | /// corresponding [stackTrace]. 12 | ErrorAndStackTrace(this.error, this.stackTrace); 13 | 14 | @override 15 | String toString() => 16 | 'ErrorAndStackTrace{error: $error, stackTrace: $stackTrace}'; 17 | 18 | @override 19 | bool operator ==(Object other) => 20 | identical(this, other) || 21 | other is ErrorAndStackTrace && 22 | runtimeType == other.runtimeType && 23 | error == other.error && 24 | stackTrace == other.stackTrace; 25 | 26 | @override 27 | int get hashCode => error.hashCode ^ stackTrace.hashCode; 28 | } 29 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/utils/future.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// @internal 4 | /// An optimized version of [Future.wait]. 5 | FutureOr waitTwoFutures(Future? f1, FutureOr f2) => f1 == null 6 | ? f2 7 | : f2 is Future 8 | ? Future.wait([f1, f2]).then(_ignore) 9 | : f1; 10 | 11 | /// @internal 12 | /// An optimized version of [Future.wait]. 13 | Future? waitFuturesList(List> futures) { 14 | switch (futures.length) { 15 | case 0: 16 | return null; 17 | case 1: 18 | return futures[0]; 19 | default: 20 | return Future.wait(futures).then(_ignore); 21 | } 22 | } 23 | 24 | /// Helper function to ignore future callback 25 | void _ignore(Object? _) {} 26 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/utils/min_max.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// @private 4 | /// Helper method which find max value or min value in a stream 5 | /// 6 | /// When the stream is done, the returned future is completed with 7 | /// the largest value or smallest value at that time. 8 | /// 9 | /// If the stream is empty, the returned future is completed with 10 | /// an error. 11 | /// If the stream emits an error, or the call to [comparator] throws, 12 | /// the returned future is completed with that error, 13 | /// and processing is stopped. 14 | Future minMax(Stream stream, bool findMin, Comparator? comparator) { 15 | var completer = Completer(); 16 | var seenFirst = false; 17 | 18 | late StreamSubscription subscription; 19 | late T accumulator; 20 | late Comparator comparatorNotNull; 21 | 22 | Future cancelAndCompleteError(Object e, StackTrace st) async { 23 | await subscription.cancel(); 24 | 25 | completer.completeError(e, st); 26 | } 27 | 28 | void onData(T element) async { 29 | if (seenFirst) { 30 | try { 31 | accumulator = findMin 32 | ? (comparatorNotNull(element, accumulator) < 0 33 | ? element 34 | : accumulator) 35 | : (comparatorNotNull(element, accumulator) > 0 36 | ? element 37 | : accumulator); 38 | } catch (e, st) { 39 | await cancelAndCompleteError(e, st); 40 | } 41 | return; 42 | } 43 | 44 | accumulator = element; 45 | seenFirst = true; 46 | try { 47 | comparatorNotNull = comparator ?? 48 | () { 49 | if (element is Comparable) { 50 | return Comparable.compare as Comparator; 51 | } else { 52 | throw StateError( 53 | 'Please provide a comparator for type $T, because it is not comparable'); 54 | } 55 | }(); 56 | } catch (e, st) { 57 | await cancelAndCompleteError(e, st); 58 | } 59 | } 60 | 61 | void onDone() { 62 | if (seenFirst) { 63 | completer.complete(accumulator); 64 | } else { 65 | completer.completeError(StateError('No element')); 66 | } 67 | } 68 | 69 | subscription = stream.listen( 70 | onData, 71 | onError: completer.completeError, 72 | onDone: onDone, 73 | cancelOnError: true, 74 | ); 75 | return completer.future; 76 | } 77 | -------------------------------------------------------------------------------- /packages/rxdart/lib/src/utils/subscription.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/src/utils/future.dart'; 4 | 5 | /// @internal 6 | /// Extensions for [Iterable] of [StreamSubscription]s. 7 | extension StreamSubscriptionsIterableExtensions 8 | on Iterable> { 9 | /// @internal 10 | /// Pause all subscriptions. 11 | void pauseAll([Future? resumeSignal]) { 12 | for (final s in this) { 13 | s.pause(resumeSignal); 14 | } 15 | } 16 | 17 | /// @internal 18 | /// Resume all subscriptions. 19 | void resumeAll() { 20 | for (final s in this) { 21 | s.resume(); 22 | } 23 | } 24 | } 25 | 26 | /// @internal 27 | /// Extensions for [Iterable] of [StreamSubscription]s. 28 | extension StreamSubscriptionsIterableExtension 29 | on Iterable> { 30 | /// @internal 31 | /// Cancel all subscriptions. 32 | Future? cancelAll() => 33 | waitFuturesList([for (final s in this) s.cancel()]); 34 | } 35 | -------------------------------------------------------------------------------- /packages/rxdart/lib/streams.dart: -------------------------------------------------------------------------------- 1 | library rx_streams; 2 | 3 | export 'src/streams/combine_latest.dart'; 4 | export 'src/streams/concat.dart'; 5 | export 'src/streams/concat_eager.dart'; 6 | export 'src/streams/connectable_stream.dart'; 7 | export 'src/streams/defer.dart'; 8 | export 'src/streams/fork_join.dart'; 9 | export 'src/streams/from_callable.dart'; 10 | export 'src/streams/merge.dart'; 11 | export 'src/streams/never.dart'; 12 | export 'src/streams/race.dart'; 13 | export 'src/streams/range.dart'; 14 | export 'src/streams/repeat.dart'; 15 | export 'src/streams/replay_stream.dart'; 16 | export 'src/streams/retry.dart'; 17 | export 'src/streams/retry_when.dart'; 18 | export 'src/streams/sequence_equal.dart'; 19 | export 'src/streams/switch_latest.dart'; 20 | export 'src/streams/timer.dart'; 21 | export 'src/streams/using.dart'; 22 | export 'src/streams/value_stream.dart'; 23 | export 'src/streams/zip.dart'; 24 | -------------------------------------------------------------------------------- /packages/rxdart/lib/subjects.dart: -------------------------------------------------------------------------------- 1 | library rx_subjects; 2 | 3 | export 'src/subjects/behavior_subject.dart'; 4 | export 'src/subjects/publish_subject.dart'; 5 | export 'src/subjects/replay_subject.dart'; 6 | export 'src/subjects/subject.dart'; 7 | -------------------------------------------------------------------------------- /packages/rxdart/lib/transformers.dart: -------------------------------------------------------------------------------- 1 | library rx_transformers; 2 | 3 | export 'src/transformers/backpressure/buffer.dart'; 4 | export 'src/transformers/backpressure/debounce.dart'; 5 | export 'src/transformers/backpressure/pairwise.dart'; 6 | export 'src/transformers/backpressure/sample.dart'; 7 | export 'src/transformers/backpressure/throttle.dart'; 8 | export 'src/transformers/backpressure/window.dart'; 9 | export 'src/transformers/default_if_empty.dart'; 10 | export 'src/transformers/delay.dart'; 11 | export 'src/transformers/delay_when.dart'; 12 | export 'src/transformers/dematerialize.dart'; 13 | export 'src/transformers/distinct_unique.dart'; 14 | export 'src/transformers/do.dart'; 15 | export 'src/transformers/end_with.dart'; 16 | export 'src/transformers/end_with_many.dart'; 17 | export 'src/transformers/exhaust_map.dart'; 18 | export 'src/transformers/flat_map.dart'; 19 | export 'src/transformers/group_by.dart'; 20 | export 'src/transformers/ignore_elements.dart'; 21 | export 'src/transformers/interval.dart'; 22 | export 'src/transformers/map_not_null.dart'; 23 | export 'src/transformers/map_to.dart'; 24 | export 'src/transformers/materialize.dart'; 25 | export 'src/transformers/max.dart'; 26 | export 'src/transformers/min.dart'; 27 | export 'src/transformers/on_error_resume.dart'; 28 | export 'src/transformers/scan.dart'; 29 | export 'src/transformers/skip_last.dart'; 30 | export 'src/transformers/skip_until.dart'; 31 | export 'src/transformers/start_with.dart'; 32 | export 'src/transformers/start_with_many.dart'; 33 | export 'src/transformers/switch_if_empty.dart'; 34 | export 'src/transformers/switch_map.dart'; 35 | export 'src/transformers/take_last.dart'; 36 | export 'src/transformers/take_until.dart'; 37 | export 'src/transformers/take_while_inclusive.dart'; 38 | export 'src/transformers/time_interval.dart'; 39 | export 'src/transformers/timestamp.dart'; 40 | export 'src/transformers/where_not_null.dart'; 41 | export 'src/transformers/where_type.dart'; 42 | export 'src/transformers/with_latest_from.dart'; 43 | -------------------------------------------------------------------------------- /packages/rxdart/lib/utils.dart: -------------------------------------------------------------------------------- 1 | library rx_utils; 2 | 3 | export 'src/utils/composite_subscription.dart'; 4 | export 'src/utils/error_and_stacktrace.dart'; 5 | export 'src/utils/notification.dart'; 6 | -------------------------------------------------------------------------------- /packages/rxdart/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart 2 | version: 0.28.0 3 | description: > 4 | RxDart is an implementation of the popular ReactiveX api for asynchronous 5 | programming, leveraging the native Dart Streams api. 6 | repository: https://github.com/ReactiveX/rxdart 7 | 8 | topics: 9 | - rxdart 10 | - reactive-programming 11 | - streams 12 | - observables 13 | - rx 14 | 15 | environment: 16 | sdk: '>=2.12.0 <4.0.0' 17 | 18 | dev_dependencies: 19 | lints: ^1.0.1 20 | stack_trace: ^1.10.0 21 | test: ^1.17.12 22 | 23 | screenshots: 24 | - description: The RxDart package logo. 25 | path: screenshots/logo.png 26 | -------------------------------------------------------------------------------- /packages/rxdart/screenshots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/packages/rxdart/screenshots/logo.png -------------------------------------------------------------------------------- /packages/rxdart/test/streams/never_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | test('NeverStream', () async { 8 | var onDataCalled = false, onDoneCalled = false, onErrorCalled = false; 9 | 10 | final stream = NeverStream(); 11 | 12 | final subscription = stream.listen( 13 | expectAsync1((_) { 14 | onDataCalled = true; 15 | }, count: 0), 16 | onError: expectAsync2((Exception e, StackTrace s) { 17 | onErrorCalled = false; 18 | }, count: 0), 19 | onDone: expectAsync0(() { 20 | onDataCalled = true; 21 | }, count: 0)); 22 | 23 | await Future.delayed(Duration(milliseconds: 10)); 24 | 25 | await subscription.cancel(); 26 | 27 | // We do not expect onData, onDone, nor onError to be called, as [never] 28 | // streams emit no items or errors, and they do not terminate 29 | await expectLater(onDataCalled, isFalse); 30 | await expectLater(onDoneCalled, isFalse); 31 | await expectLater(onErrorCalled, isFalse); 32 | }); 33 | 34 | test('NeverStream.single.subscription', () async { 35 | final stream = NeverStream(); 36 | 37 | stream.listen(null); 38 | await expectLater(() => stream.listen(null), throwsA(isStateError)); 39 | }); 40 | 41 | test('Rx.never', () async { 42 | var onDataCalled = false, onDoneCalled = false, onErrorCalled = false; 43 | 44 | final stream = Rx.never(); 45 | 46 | final subscription = stream.listen( 47 | expectAsync1((_) { 48 | onDataCalled = true; 49 | }, count: 0), 50 | onError: expectAsync2((Exception e, StackTrace s) { 51 | onErrorCalled = false; 52 | }, count: 0), 53 | onDone: expectAsync0(() { 54 | onDataCalled = true; 55 | }, count: 0)); 56 | 57 | await Future.delayed(Duration(milliseconds: 10)); 58 | 59 | await subscription.cancel(); 60 | 61 | // We do not expect onData, onDone, nor onError to be called, as [never] 62 | // streams emit no items or errors, and they do not terminate 63 | await expectLater(onDataCalled, isFalse); 64 | await expectLater(onDoneCalled, isFalse); 65 | await expectLater(onErrorCalled, isFalse); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /packages/rxdart/test/streams/range_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:rxdart/rxdart.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | test('RangeStream', () async { 6 | final expected = const [1, 2, 3]; 7 | var count = 0; 8 | 9 | final stream = RangeStream(1, 3); 10 | 11 | stream.listen(expectAsync1((actual) { 12 | expect(actual, expected[count++]); 13 | }, count: expected.length)); 14 | }); 15 | 16 | test('RangeStream.single.subscription', () async { 17 | final stream = RangeStream(1, 5); 18 | 19 | stream.listen(null); 20 | await expectLater(() => stream.listen(null), throwsA(isStateError)); 21 | }); 22 | 23 | test('RangeStream.single', () async { 24 | final stream = RangeStream(1, 1); 25 | 26 | stream.listen(expectAsync1((actual) { 27 | expect(actual, 1); 28 | }, count: 1)); 29 | }); 30 | 31 | test('RangeStream.reverse', () async { 32 | final expected = const [3, 2, 1]; 33 | var count = 0; 34 | 35 | final stream = RangeStream(3, 1); 36 | 37 | stream.listen(expectAsync1((actual) { 38 | expect(actual, expected[count++]); 39 | }, count: expected.length)); 40 | }); 41 | 42 | test('Rx.range', () async { 43 | final expected = const [1, 2, 3]; 44 | var count = 0; 45 | 46 | final stream = Rx.range(1, 3); 47 | 48 | stream.listen(expectAsync1((actual) { 49 | expect(actual, expected[count++]); 50 | }, count: expected.length)); 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/backpressure/buffer_test_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../../utils.dart'; 7 | 8 | void main() { 9 | test('Rx.bufferTest', () async { 10 | await expectLater( 11 | Rx.range(1, 4).bufferTest((i) => i % 2 == 0), 12 | emitsInOrder([ 13 | const [1, 2], 14 | const [3, 4], 15 | emitsDone 16 | ])); 17 | }); 18 | 19 | test('Rx.bufferTest.reusable', () async { 20 | final transformer = BufferTestStreamTransformer((i) => i % 2 == 0); 21 | 22 | await expectLater( 23 | Stream.fromIterable(const [1, 2, 3, 4]).transform(transformer), 24 | emitsInOrder([ 25 | const [1, 2], 26 | const [3, 4], 27 | emitsDone 28 | ])); 29 | 30 | await expectLater( 31 | Stream.fromIterable(const [1, 2, 3, 4]).transform(transformer), 32 | emitsInOrder([ 33 | const [1, 2], 34 | const [3, 4], 35 | emitsDone 36 | ])); 37 | }); 38 | 39 | test('Rx.bufferTest.asBroadcastStream', () async { 40 | final stream = Stream.fromIterable(const [1, 2, 3, 4]) 41 | .asBroadcastStream() 42 | .bufferTest((i) => i % 2 == 0); 43 | 44 | // listen twice on same stream 45 | await expectLater( 46 | stream, 47 | emitsInOrder([ 48 | const [1, 2], 49 | const [3, 4], 50 | emitsDone 51 | ])); 52 | 53 | await expectLater(stream, emitsDone); 54 | }); 55 | 56 | test('Rx.bufferTest.error.shouldThrowA', () async { 57 | await expectLater( 58 | Stream.error(Exception()).bufferTest((i) => i % 2 == 0), 59 | emitsError(isException)); 60 | }); 61 | 62 | test('Rx.bufferTest.nullable', () { 63 | nullableTest>( 64 | (s) => s.bufferTest((i) => true), 65 | ); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/backpressure/pairwise_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../../utils.dart'; 7 | 8 | void main() { 9 | test('Rx.pairwise', () async { 10 | const expectedOutput = [ 11 | [1, 2], 12 | [2, 3], 13 | [3, 4] 14 | ]; 15 | var count = 0; 16 | 17 | final stream = Rx.range(1, 4).pairwise(); 18 | 19 | stream.listen( 20 | expectAsync1((result) { 21 | // test to see if the combined output matches 22 | expect(result, expectedOutput[count++]); 23 | }, count: expectedOutput.length), 24 | onError: expectAsync2((Object e, StackTrace s) {}, count: 0), 25 | onDone: expectAsync0(() {}, count: 1), 26 | ); 27 | }); 28 | 29 | test('Rx.pairwise.empty', () { 30 | expect(Stream.empty().pairwise(), emitsDone); 31 | }); 32 | 33 | test('Rx.pairwise.single', () { 34 | expect(Stream.value(1).pairwise(), emitsDone); 35 | }); 36 | 37 | test('Rx.pairwise.compatible', () { 38 | expect( 39 | Stream.fromIterable([1, 2]).pairwise(), 40 | isA>>(), 41 | ); 42 | 43 | Stream> s = Stream.fromIterable([1, 2]).pairwise(); 44 | expect( 45 | s, 46 | emitsInOrder([ 47 | [1, 2], 48 | emitsDone 49 | ]), 50 | ); 51 | }); 52 | 53 | test('Rx.pairwise.asBroadcastStream', () async { 54 | final stream = 55 | Stream.fromIterable(const [1, 2, 3, 4]).asBroadcastStream().pairwise(); 56 | 57 | // listen twice on same stream 58 | stream.listen(null); 59 | stream.listen(null); 60 | // code should reach here 61 | await expectLater(true, true); 62 | }); 63 | 64 | test('Rx.pairwise.error.shouldThrow.onError', () async { 65 | final streamWithError = Stream.error(Exception()).pairwise(); 66 | 67 | streamWithError.listen(null, 68 | onError: expectAsync2((Exception e, StackTrace s) { 69 | expect(e, isException); 70 | })); 71 | }); 72 | 73 | test('Rx.pairwise.nullable', () { 74 | nullableTest>( 75 | (s) => s.pairwise(), 76 | ); 77 | }); 78 | } 79 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/backpressure/window_test_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../../utils.dart'; 7 | 8 | void main() { 9 | test('Rx.windowTest', () async { 10 | await expectLater( 11 | Rx.range(1, 4) 12 | .windowTest((i) => i % 2 == 0) 13 | .asyncMap((stream) => stream.toList()), 14 | emitsInOrder([ 15 | const [1, 2], 16 | const [3, 4], 17 | emitsDone 18 | ])); 19 | }); 20 | 21 | test('Rx.windowTest.reusable', () async { 22 | final transformer = WindowTestStreamTransformer((i) => i % 2 == 0); 23 | 24 | await expectLater( 25 | Stream.fromIterable(const [1, 2, 3, 4]) 26 | .transform(transformer) 27 | .asyncMap((stream) => stream.toList()), 28 | emitsInOrder([ 29 | const [1, 2], 30 | const [3, 4], 31 | emitsDone 32 | ])); 33 | 34 | await expectLater( 35 | Stream.fromIterable(const [1, 2, 3, 4]) 36 | .transform(transformer) 37 | .asyncMap((stream) => stream.toList()), 38 | emitsInOrder([ 39 | const [1, 2], 40 | const [3, 4], 41 | emitsDone 42 | ])); 43 | }); 44 | 45 | test('Rx.windowTest.asBroadcastStream', () async { 46 | final future = Stream.fromIterable(const [1, 2, 3, 4]) 47 | .asBroadcastStream() 48 | .windowTest((i) => i % 2 == 0) 49 | .drain(); 50 | 51 | // listen twice on same stream 52 | await expectLater(future, completes); 53 | await expectLater(future, completes); 54 | }); 55 | 56 | test('Rx.windowTest.error.shouldThrowA', () async { 57 | await expectLater( 58 | Stream.error(Exception()).windowTest((i) => i % 2 == 0), 59 | emitsError(isException)); 60 | }); 61 | 62 | test('Rx.windowTest.nullable', () { 63 | nullableTest>( 64 | (s) => s.windowTest((_) => true), 65 | ); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/concat_with_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | test('Rx.concatWith', () async { 8 | final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); 9 | final immediateStream = Stream.value(2); 10 | const expected = [1, 2]; 11 | var count = 0; 12 | 13 | delayedStream.concatWith([immediateStream]).listen(expectAsync1((result) { 14 | expect(result, expected[count++]); 15 | }, count: expected.length)); 16 | }); 17 | test('Rx.concatWith accidental broadcast', () async { 18 | final controller = StreamController(); 19 | 20 | final stream = controller.stream.concatWith([Stream.empty()]); 21 | 22 | stream.listen(null); 23 | expect(() => stream.listen(null), throwsStateError); 24 | 25 | controller.add(1); 26 | }); 27 | 28 | test('Rx.concatWith on broadcast stream should stay broadcast ', () async { 29 | final delayedStream = 30 | Rx.timer(1, Duration(milliseconds: 10)).asBroadcastStream(); 31 | final immediateStream = Stream.value(2); 32 | final expected = [1, 2, emitsDone]; 33 | 34 | final concatenatedStream = delayedStream.concatWith([immediateStream]); 35 | 36 | expect(concatenatedStream.isBroadcast, isTrue); 37 | expect(concatenatedStream, emitsInOrder(expected)); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/distinct_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | test('Rx.distinct', () async { 7 | const expected = 1; 8 | 9 | final stream = Stream.fromIterable(const [expected, expected]).distinct(); 10 | 11 | stream.listen(expectAsync1((actual) { 12 | expect(actual, expected); 13 | })); 14 | }); 15 | test('Rx.distinct accidental broadcast', () async { 16 | final controller = StreamController(); 17 | 18 | final stream = controller.stream.distinct(); 19 | 20 | stream.listen(null); 21 | expect(() => stream.listen(null), throwsStateError); 22 | 23 | controller.add(1); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/end_with_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../utils.dart'; 7 | 8 | Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); 9 | 10 | void main() { 11 | test('Rx.endWith', () async { 12 | const expectedOutput = [1, 2, 3, 4, 5]; 13 | 14 | await expectLater(_getStream().endWith(5), emitsInOrder(expectedOutput)); 15 | }); 16 | 17 | test('Rx.endWith.reusable', () async { 18 | final transformer = EndWithStreamTransformer(5); 19 | const expectedOutput = [1, 2, 3, 4, 5]; 20 | 21 | await expectLater( 22 | _getStream().transform(transformer), emitsInOrder(expectedOutput)); 23 | await expectLater( 24 | _getStream().transform(transformer), emitsInOrder(expectedOutput)); 25 | }); 26 | 27 | test('Rx.endWith.asBroadcastStream', () async { 28 | final stream = _getStream().asBroadcastStream().endWith(5); 29 | 30 | // listen twice on same stream 31 | stream.listen(null); 32 | stream.listen(null); 33 | // code should reach here 34 | await expectLater(true, true); 35 | }); 36 | 37 | test('Rx.endWith.error.shouldThrow', () async { 38 | final streamWithError = Stream.error(Exception()).endWith(5); 39 | 40 | await expectLater(streamWithError, emitsError(isException)); 41 | }); 42 | 43 | test('Rx.endWith.pause.resume', () async { 44 | const expectedOutput = [1, 2, 3, 4, 5]; 45 | var count = 0; 46 | 47 | late StreamSubscription subscription; 48 | subscription = _getStream().endWith(5).listen(expectAsync1((result) { 49 | expect(expectedOutput[count++], result); 50 | 51 | if (count == expectedOutput.length) { 52 | subscription.cancel(); 53 | } 54 | }, count: expectedOutput.length)); 55 | 56 | subscription.pause(); 57 | subscription.resume(); 58 | }); 59 | 60 | test('Rx.endWith accidental broadcast', () async { 61 | final controller = StreamController(); 62 | 63 | final stream = controller.stream.endWith(1); 64 | 65 | stream.listen(null); 66 | expect(() => stream.listen(null), throwsStateError); 67 | 68 | controller.add(1); 69 | }); 70 | 71 | test('Rx.endWith.nullable', () { 72 | nullableTest( 73 | (s) => s.endWith('String'), 74 | ); 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/flat_map_iterable_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../utils.dart'; 7 | 8 | void main() { 9 | group('Rx.flatMapIterable', () { 10 | test('transforms a Stream> into individual items', () { 11 | expect( 12 | Rx.range(1, 4) 13 | .flatMapIterable((int i) => Stream>.value([i])), 14 | emitsInOrder([1, 2, 3, 4, emitsDone])); 15 | }); 16 | 17 | test('accidental broadcast', () async { 18 | final controller = StreamController(); 19 | 20 | final stream = controller.stream 21 | .flatMapIterable((int i) => Stream>.value([i])); 22 | 23 | stream.listen(null); 24 | expect(() => stream.listen(null), throwsStateError); 25 | 26 | controller.add(1); 27 | }); 28 | 29 | test('nullable', () { 30 | nullableTest( 31 | (s) => s.flatMapIterable((v) => Stream.value([v])), 32 | ); 33 | }); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/join_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | test('Rx.join', () async { 7 | final joined = await Stream.fromIterable(const ['h', 'i']).join('+'); 8 | 9 | await expectLater(joined, 'h+i'); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/map_to_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../utils.dart'; 7 | 8 | void main() { 9 | test('Rx.mapTo', () async { 10 | await expectLater(Rx.range(1, 4).mapTo(true), 11 | emitsInOrder([true, true, true, true, emitsDone])); 12 | }); 13 | 14 | test('Rx.mapTo.shouldThrow', () async { 15 | await expectLater( 16 | Rx.range(1, 4).concatWith([Stream.error(Error())]).mapTo(true), 17 | emitsInOrder([ 18 | true, 19 | true, 20 | true, 21 | true, 22 | emitsError(TypeMatcher()), 23 | emitsDone 24 | ])); 25 | }); 26 | 27 | test('Rx.mapTo.reusable', () async { 28 | final transformer = MapToStreamTransformer(true); 29 | final stream = Rx.range(1, 4).asBroadcastStream(); 30 | 31 | stream.transform(transformer).listen(null); 32 | stream.transform(transformer).listen(null); 33 | 34 | await expectLater(true, true); 35 | }); 36 | 37 | test('Rx.mapTo.pause.resume', () async { 38 | late StreamSubscription subscription; 39 | final stream = Stream.value(1).mapTo(true); 40 | 41 | subscription = stream.listen(expectAsync1((value) { 42 | expect(value, isTrue); 43 | 44 | subscription.cancel(); 45 | }, count: 1)); 46 | 47 | subscription.pause(); 48 | subscription.resume(); 49 | }); 50 | 51 | test('Rx.mapTo accidental broadcast', () async { 52 | final controller = StreamController(); 53 | 54 | final stream = controller.stream.mapTo(1); 55 | 56 | stream.listen(null); 57 | expect(() => stream.listen(null), throwsStateError); 58 | 59 | controller.add(1); 60 | }); 61 | 62 | test('Rx.mapTo.nullable', () { 63 | nullableTest( 64 | (s) => s.mapTo('String'), 65 | ); 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/merge_with_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | test('Rx.mergeWith', () async { 8 | final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); 9 | final immediateStream = Stream.value(2); 10 | const expected = [2, 1]; 11 | var count = 0; 12 | 13 | delayedStream.mergeWith([immediateStream]).listen(expectAsync1((result) { 14 | expect(result, expected[count++]); 15 | }, count: expected.length)); 16 | }); 17 | 18 | test('Rx.mergeWith accidental broadcast', () async { 19 | final controller = StreamController(); 20 | 21 | final stream = controller.stream.mergeWith([Stream.empty()]); 22 | 23 | stream.listen(null); 24 | expect(() => stream.listen(null), throwsStateError); 25 | 26 | controller.add(1); 27 | }); 28 | 29 | test('Rx.mergeWith on single stream should stay single ', () async { 30 | final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); 31 | final immediateStream = Stream.value(2); 32 | final expected = [2, 1, emitsDone]; 33 | 34 | final concatenatedStream = delayedStream.mergeWith([immediateStream]); 35 | 36 | expect(concatenatedStream.isBroadcast, isFalse); 37 | expect(concatenatedStream, emitsInOrder(expected)); 38 | }); 39 | 40 | test('Rx.mergeWith on broadcast stream should stay broadcast ', () async { 41 | final delayedStream = 42 | Rx.timer(1, Duration(milliseconds: 10)).asBroadcastStream(); 43 | final immediateStream = Stream.value(2); 44 | final expected = [2, 1, emitsDone]; 45 | 46 | final concatenatedStream = delayedStream.mergeWith([immediateStream]); 47 | 48 | expect(concatenatedStream.isBroadcast, isTrue); 49 | expect(concatenatedStream, emitsInOrder(expected)); 50 | }); 51 | 52 | test('Rx.mergeWith multiple subscriptions on single ', () async { 53 | final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); 54 | final immediateStream = Stream.value(2); 55 | 56 | final concatenatedStream = delayedStream.mergeWith([immediateStream]); 57 | 58 | expect(() => concatenatedStream.listen(null), returnsNormally); 59 | expect(() => concatenatedStream.listen(null), 60 | throwsA(TypeMatcher())); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/on_error_return_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../utils.dart'; 7 | 8 | void main() { 9 | const num expected = 0; 10 | 11 | test('Rx.onErrorReturn', () async { 12 | Stream.error(Exception()) 13 | .onErrorReturn(0) 14 | .listen(expectAsync1((num result) { 15 | expect(result, expected); 16 | })); 17 | }); 18 | 19 | test('Rx.onErrorReturn.asBroadcastStream', () async { 20 | final stream = 21 | Stream.error(Exception()).onErrorReturn(0).asBroadcastStream(); 22 | 23 | await expectLater(stream.isBroadcast, isTrue); 24 | 25 | stream.listen(expectAsync1((num result) { 26 | expect(result, expected); 27 | })); 28 | 29 | stream.listen(expectAsync1((num result) { 30 | expect(result, expected); 31 | })); 32 | }); 33 | 34 | test('Rx.onErrorReturn.pause.resume', () async { 35 | late StreamSubscription subscription; 36 | 37 | subscription = Stream.error(Exception()) 38 | .onErrorReturn(0) 39 | .listen(expectAsync1((num result) { 40 | expect(result, expected); 41 | 42 | subscription.cancel(); 43 | })); 44 | 45 | subscription.pause(); 46 | subscription.resume(); 47 | }); 48 | 49 | test('Rx.onErrorReturn accidental broadcast', () async { 50 | final controller = StreamController(); 51 | 52 | final stream = controller.stream.onErrorReturn(1); 53 | 54 | stream.listen(null); 55 | expect(() => stream.listen(null), throwsStateError); 56 | 57 | controller.add(1); 58 | }); 59 | 60 | test('Rx.onErrorReturn still adds data when Stream emits an error: issue/616', 61 | () { 62 | final stream = Rx.concat([ 63 | Stream.value(1), 64 | Stream.error(Exception()), 65 | Stream.fromIterable([2, 3]), 66 | Stream.error(Exception()), 67 | Stream.value(4), 68 | ]).onErrorReturn(-1); 69 | expect( 70 | stream, 71 | emitsInOrder([1, -1, 2, 3, -1, 4, emitsDone]), 72 | ); 73 | }); 74 | 75 | test('Rx.onErrorReturn.nullable', () { 76 | nullableTest( 77 | (s) => s.onErrorReturn('String'), 78 | ); 79 | }); 80 | } 81 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/on_error_return_with_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../utils.dart'; 7 | 8 | void main() { 9 | const num expected = 0; 10 | 11 | test('Rx.onErrorReturnWith', () async { 12 | Stream.error(Exception()) 13 | .onErrorReturnWith((e, _) => e is StateError ? 1 : 0) 14 | .listen(expectAsync1((num result) { 15 | expect(result, expected); 16 | })); 17 | }); 18 | 19 | test('Rx.onErrorReturnWith.asBroadcastStream', () async { 20 | final stream = Stream.error(Exception()) 21 | .onErrorReturnWith((_, __) => 0) 22 | .asBroadcastStream(); 23 | 24 | await expectLater(stream.isBroadcast, isTrue); 25 | 26 | stream.listen(expectAsync1((num result) { 27 | expect(result, expected); 28 | })); 29 | 30 | stream.listen(expectAsync1((num result) { 31 | expect(result, expected); 32 | })); 33 | }); 34 | 35 | test('Rx.onErrorReturnWith.pause.resume', () async { 36 | late StreamSubscription subscription; 37 | 38 | subscription = Stream.error(Exception()) 39 | .onErrorReturnWith((_, __) => 0) 40 | .listen(expectAsync1((num result) { 41 | expect(result, expected); 42 | 43 | subscription.cancel(); 44 | })); 45 | 46 | subscription.pause(); 47 | subscription.resume(); 48 | }); 49 | 50 | test('Rx.onErrorReturnWith accidental broadcast', () async { 51 | final controller = StreamController(); 52 | 53 | final stream = controller.stream.onErrorReturnWith((_, __) => 1); 54 | 55 | stream.listen(null); 56 | expect(() => stream.listen(null), throwsStateError); 57 | 58 | controller.add(1); 59 | }); 60 | 61 | test( 62 | 'Rx.onErrorReturnWith still adds data when Stream emits an error: issue/616', 63 | () { 64 | final stream = Rx.concat([ 65 | Stream.value(1), 66 | Stream.error(Exception()), 67 | Stream.fromIterable([2, 3]), 68 | Stream.error(Exception()), 69 | Stream.value(4), 70 | ]).onErrorReturnWith((e, s) => -1); 71 | expect( 72 | stream, 73 | emitsInOrder([1, -1, 2, 3, -1, 4, emitsDone]), 74 | ); 75 | }); 76 | 77 | test('Rx.onErrorReturnWith.nullable', () { 78 | nullableTest( 79 | (s) => s.onErrorReturnWith((e, s) => 'String'), 80 | ); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/timeout_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | test('Rx.timeout', () async { 7 | late StreamSubscription subscription; 8 | 9 | final stream = Stream.fromFuture( 10 | Future.delayed(Duration(milliseconds: 30), () => 1)) 11 | .timeout(Duration(milliseconds: 1)); 12 | 13 | subscription = stream.listen((_) {}, 14 | onError: expectAsync2((Object e, StackTrace s) { 15 | expect(e is TimeoutException, isTrue); 16 | subscription.cancel(); 17 | }, count: 1)); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/where_not_null_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | import '../utils.dart'; 7 | 8 | void main() { 9 | test('Rx.whereNotNull', () { 10 | { 11 | final notNull = Stream.fromIterable([1, 2, 3, 4]).whereNotNull(); 12 | 13 | expect(notNull, isA>()); 14 | expect(notNull, emitsInOrder([1, 2, 3, 4])); 15 | } 16 | 17 | { 18 | final notNull = Stream.fromIterable([1, 2, null, 3, 4, null]) 19 | .transform(WhereNotNullStreamTransformer()); 20 | 21 | expect(notNull, isA>()); 22 | expect(notNull, emitsInOrder([1, 2, 3, 4])); 23 | } 24 | }); 25 | 26 | test('Rx.whereNotNull.shouldThrow', () { 27 | expect( 28 | Stream.error(Exception()).whereNotNull(), 29 | emitsError(isA()), 30 | ); 31 | 32 | expect( 33 | Rx.concat([ 34 | Stream.fromIterable([1, 2, null]), 35 | Stream.error(Exception()), 36 | Stream.value(3), 37 | ]).whereNotNull(), 38 | emitsInOrder([ 39 | 1, 40 | 2, 41 | emitsError(isException), 42 | 3, 43 | emitsDone, 44 | ]), 45 | ); 46 | }); 47 | 48 | test('Rx.whereNotNull.asBroadcastStream', () { 49 | final stream = 50 | Stream.fromIterable([1, 2, null]).whereNotNull().asBroadcastStream(); 51 | 52 | // listen twice on same stream 53 | stream.listen(null); 54 | stream.listen(null); 55 | 56 | // code should reach here 57 | expect(true, true); 58 | }); 59 | 60 | test('Rx.whereNotNull.singleSubscription', () { 61 | final stream = StreamController().stream.whereNotNull(); 62 | 63 | expect(stream.isBroadcast, isFalse); 64 | stream.listen(null); 65 | expect(() => stream.listen(null), throwsStateError); 66 | }); 67 | 68 | test('Rx.whereNotNull.pause.resume', () async { 69 | final subscription = Stream.fromIterable([null, 2, 3, null, 4, 5, 6]) 70 | .whereNotNull() 71 | .listen(null); 72 | 73 | subscription 74 | ..pause() 75 | ..onData(expectAsync1((data) { 76 | expect(data, 2); 77 | subscription.cancel(); 78 | })) 79 | ..resume(); 80 | }); 81 | 82 | test('Rx.whereNotNull.nullable', () { 83 | nullableTest( 84 | (s) => s.whereNotNull(), 85 | ); 86 | }); 87 | } 88 | -------------------------------------------------------------------------------- /packages/rxdart/test/transformers/zip_with_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:rxdart/rxdart.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | test('Rx.zipWith', () async { 8 | Stream.value(1) 9 | .zipWith(Stream.value(2), (int one, int two) => one + two) 10 | .listen(expectAsync1((int result) { 11 | expect(result, 3); 12 | }, count: 1)); 13 | }); 14 | 15 | test('Rx.zipWith accidental broadcast', () async { 16 | final controller = StreamController(); 17 | 18 | final stream = 19 | controller.stream.zipWith(Stream.empty(), (_, dynamic __) => true); 20 | 21 | stream.listen(null); 22 | expect(() => stream.listen(null), throwsStateError); 23 | 24 | controller.add(1); 25 | }); 26 | 27 | test('Rx.zipWith on single stream should stay single ', () async { 28 | final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); 29 | final immediateStream = Stream.value(2); 30 | final expected = [3, emitsDone]; 31 | 32 | final concatenatedStream = 33 | delayedStream.zipWith(immediateStream, (a, int b) => a + b); 34 | 35 | expect(concatenatedStream.isBroadcast, isFalse); 36 | expect(concatenatedStream, emitsInOrder(expected)); 37 | }); 38 | 39 | test('Rx.zipWith on broadcast stream should stay broadcast ', () async { 40 | final delayedStream = 41 | Rx.timer(1, Duration(milliseconds: 10)).asBroadcastStream(); 42 | final immediateStream = Stream.value(2); 43 | final expected = [3, emitsDone]; 44 | 45 | final concatenatedStream = 46 | delayedStream.zipWith(immediateStream, (a, int b) => a + b); 47 | 48 | expect(concatenatedStream.isBroadcast, isTrue); 49 | expect(concatenatedStream, emitsInOrder(expected)); 50 | }); 51 | 52 | test('Rx.zipWith multiple subscriptions on single ', () async { 53 | final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); 54 | final immediateStream = Stream.value(2); 55 | 56 | final concatenatedStream = 57 | delayedStream.zipWith(immediateStream, (a, int b) => a + b); 58 | 59 | expect(() => concatenatedStream.listen(null), returnsNormally); 60 | expect(() => concatenatedStream.listen(null), 61 | throwsA(TypeMatcher())); 62 | }); 63 | } 64 | -------------------------------------------------------------------------------- /packages/rxdart/test/utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// Explicitly ignores a future. 4 | /// 5 | /// Not all futures need to be awaited. 6 | /// The Dart linter has an optional ["unawaited futures" lint](https://dart-lang.github.io/linter/lints/unawaited_futures.html) 7 | /// which enforces that futures (expressions with a static type of [Future]) 8 | /// in asynchronous functions are handled *somehow*. 9 | /// If a particular future value doesn't need to be awaited, 10 | /// you can call `unawaited(...)` with it, which will avoid the lint, 11 | /// simply because the expression no longer has type [Future]. 12 | /// Using `unawaited` has no other effect. 13 | /// You should use `unawaited` to convey the *intention* of 14 | /// deliberately not waiting for the future. 15 | /// 16 | /// If the future completes with an error, 17 | /// it was likely a mistake to not await it. 18 | /// That error will still occur and will be considered unhandled 19 | /// unless the same future is awaited (or otherwise handled) elsewhere too. 20 | /// Because of that, `unawaited` should only be used for futures that 21 | /// are *expected* to complete with a value. 22 | void unawaited(Future future) {} 23 | 24 | void nullableTest(Stream Function(Stream s) transform) => 25 | transform(Stream.fromIterable(['1', '2', '3'])); 26 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/.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: "2f708eb8396e362e280fac22cf171c2cb467343c" 8 | channel: "stable" 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.2 (2025-03-10) 2 | 3 | - Fix `pubspec.yaml`. 4 | 5 | ## 0.0.1 (2025-02-15) 6 | 7 | Thanks to [@GiancarloCante](https://github.com/GiancarloCante) for the contribution to this release 8 | via PR [#782](https://github.com/ReactiveX/rxdart/pull/782). 9 | 10 | - Add new widgets: 11 | - `ValueStreamListener`: a widget that performs side effects when `ValueStream` values change. 12 | - `ValueStreamConsumer`: a widget combining both builder and listener capabilities for `ValueStream`s. 13 | - Update `ValueStreamBuilder`: add optional `child` parameter to `ValueStreamWidgetBuilder`. 14 | - Add tests, documentation and examples. 15 | 16 | ## 0.0.1-dev.1 17 | 18 | - Initial release. 19 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/LICENSE: -------------------------------------------------------------------------------- 1 | ../../LICENSE -------------------------------------------------------------------------------- /packages/rxdart_flutter/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | linter: 3 | rules: 4 | - prefer_final_locals 5 | - prefer_relative_imports 6 | - always_declare_return_types # https://github.com/dart-lang/lints#migrating-from-packagepedantic 7 | - prefer_single_quotes # https://github.com/dart-lang/lints#migrating-from-packagepedantic 8 | - unawaited_futures # https://github.com/dart-lang/lints#migrating-from-packagepedantic 9 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .pub-cache/ 33 | .pub/ 34 | /build/ 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | 47 | # Scaffolded code by `flutter create .` 48 | android/ 49 | ios/ 50 | linux/ 51 | macos/ 52 | web/ 53 | windows/ 54 | test/widget_test.dart 55 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/example/.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: "17025dd88227cd9532c33fa78f5250d548d87e9a" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 17 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 18 | - platform: android 19 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 20 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 21 | - platform: ios 22 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 23 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 24 | - platform: linux 25 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 26 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 27 | - platform: macos 28 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 29 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 30 | - platform: web 31 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 32 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 33 | - platform: windows 34 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 35 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/example/README.md: -------------------------------------------------------------------------------- 1 | # rxdart_flutter_example 2 | 3 | ## Getting Started 4 | 5 | Generate platform-specific code 6 | 7 | ```bash 8 | flutter create . 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart_flutter_example 2 | description: example for rxdart_flutter 3 | version: 1.0.0 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | rxdart_flutter: 13 | path: ../ 14 | 15 | dev_dependencies: 16 | flutter_lints: ^1.0.4 17 | 18 | flutter: 19 | uses-material-design: true 20 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/lib/rxdart_flutter.dart: -------------------------------------------------------------------------------- 1 | library rxdart_flutter; 2 | 3 | export 'src/value_stream_builder.dart'; 4 | export 'src/value_stream_consumer.dart'; 5 | export 'src/value_stream_listener.dart'; 6 | 7 | export 'package:rxdart/rxdart.dart'; 8 | -------------------------------------------------------------------------------- /packages/rxdart_flutter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart_flutter 2 | description: > 3 | rxdart_flutter is a Flutter package that provides a set of widgets for working with rxdart. 4 | This package is officially maintained in the ReactiveX/rxdart repository. 5 | These widgets are specifically designed to work with ValueStreams, making it easier to build reactive UIs in Flutter. 6 | version: 0.0.2 7 | homepage: https://github.com/ReactiveX/rxdart/tree/master/packages/rxdart_flutter 8 | repository: https://github.com/ReactiveX/rxdart/tree/master/packages/rxdart_flutter 9 | issue_tracker: https://github.com/ReactiveX/rxdart/issues 10 | 11 | environment: 12 | sdk: '>=2.12.0 <4.0.0' 13 | flutter: '>=2.0.1' 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | rxdart: ^0.28.0 19 | meta: ^1.3.0 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | flutter_lints: ^1.0.4 25 | 26 | topics: 27 | - rxdart 28 | - reactive-programming 29 | - streams 30 | - observables 31 | - rx 32 | 33 | screenshots: 34 | - description: The ReactiveX logo. 35 | path: screenshots/logo.png -------------------------------------------------------------------------------- /packages/rxdart_flutter/screenshots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveX/rxdart/ed5caf25516e05a1e38670276d17e31dc09bc9ad/packages/rxdart_flutter/screenshots/logo.png -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rxdart_workspace 2 | publish_to: none 3 | 4 | environment: 5 | sdk: '>=2.12.0 <4.0.0' 6 | 7 | dev_dependencies: 8 | lints: ^5.1.1 9 | melos: ^6.3.3 10 | --------------------------------------------------------------------------------